(Neden) önbelleği aramamız veya bir RDD'de kalmamız gerekiyor mu


171

Bir metin dosyasından veya koleksiyondan (veya başka bir RDD'den) esnek dağıtılmış bir veri kümesi (RDD) oluşturulduğunda, RDD verilerini belleğe kaydetmek için "önbellek" veya "kalıcı" yı çağırmamız gerekir mi? Yoksa RDD verileri varsayılan olarak bellekte dağıtılmış bir şekilde mi saklanır?

val textFile = sc.textFile("/user/emp.txt")

Anladığım kadarıyla, yukarıdaki adımdan sonra, textFile bir RDD'dir ve düğümün belleğinin tümünde / bazılarında kullanılabilir.

Öyleyse, neden textFile RDD'de "önbellek" veya "sürekli" olarak adlandırmamız gerekiyor?

Yanıtlar:


300

Çoğu RDD işlemi tembeldir. RDD'yi bir dizi işlemin açıklaması olarak düşünün. RDD veri değildir. Yani bu çizgi:

val textFile = sc.textFile("/user/emp.txt")

Hiçbir şey yapmaz. "Bu dosyayı yüklememiz gerekecek" yazan bir RDD oluşturur. Dosya bu noktada yüklenmez.

Verilerin içeriğinin gözlemlenmesini gerektiren RDD işlemleri tembel olamaz. (Bunlara eylemler denir .) Bir örnek RDD.count- dosyadaki satır sayısını belirtmek için dosyanın okunması gerekir. Dolayısıyla, yazarsanız textFile.count, bu noktada dosya okunur, satırlar sayılır ve sayım döndürülür.

textFile.countTekrar ararsan ne olur ? Aynı şey: dosya tekrar okunacak ve sayılacaktır. Hiçbir şey depolanmaz. RDD veri değildir.

Peki ne yapar RDD.cache? textFile.cacheYukarıdaki koda eklerseniz :

val textFile = sc.textFile("/user/emp.txt")
textFile.cache

Hiçbir şey yapmaz. RDD.cacheaynı zamanda tembel bir işlemdir. Dosya hala okunmuyor. Ancak şimdi RDD "bu dosyayı oku ve sonra içeriği önbelleğe al" diyor. Daha sonra textFile.countilk kez çalıştırırsanız , dosya yüklenir, önbelleğe alınır ve sayılır. textFile.countİkinci kez ararsanız , işlem önbelleği kullanır. Sadece verileri önbellekten alır ve satırları sayar.

Önbellek davranışı, kullanılabilir belleğe bağlıdır. Örneğin dosya belleğe sığmazsa textFile.count, normal davranışa geri döner ve dosyayı yeniden okur.


4
Merhaba daniel, - önbelleği çağırdığınızda, bu RDD'nin kaynaktan yeniden yüklenmediği (ör. Metin dosyası) anlamına gelir - önbelleklendiğinde metin dosyasındaki verilerin en son olduğundan nasıl emin olabilirsiniz? (kıvılcım bunu çözüyor mu veya kaynak verilerin
kökende

ayrıca - periyodik olarak dağılmanız gerekiyorsa, - önbelleğe alınmış bir RDD'niz varsa, önbelleğe alınmış başka bir RDD'ye bağlıysanız, yeniden hesaplanan sonuçları görmek için her iki RDD'nin de dağılımını kaldırmanız gerekir mi?
andrew.butkus

21
Spark sadece dosyanın asla değişmeyeceğini varsayar. Dosyayı rastgele bir zamanda okur ve daha sonra gerektiğinde bölümlerini yeniden okuyabilir. (Örneğin, verilerin bir kısmı önbellekten çıkarılmışsa.) Dosyalarınızı değiştirmemeniz daha iyi olur! Yeni verileriniz olduğunda yeni bir adla yeni bir dosya oluşturun ve yeni bir RDD olarak yükleyin. Sürekli yeni veriler alıyorsanız Spark Streaming'a bakın.
Daniel Darabos

10
Evet. RDD'ler değişmezdir, bu nedenle her RDD bağımlılıklarının da değişmez olduğunu varsayar. Kıvılcım Akışı, bir değişiklik akışı üzerinde çalışan bu tür ağaçları ayarlamanıza izin verir. Ancak daha da basit bir çözüm, ağacı parametre olarak bir dosya adı alan bir işlevde oluşturmaktır. Sonra sadece yeni dosya ve puf fonksiyonunu çağırın, yeni hesaplama ağacına sahipsiniz.
Daniel Darabos

1
@Humoyun: Spark UI'nin Depolama sekmesinde, her bir RDD'nin ne kadarının önbelleğe alındığını görebilirsiniz. Veriler o kadar büyük olabilir ki, sadece% 40'ı önbellekleme için sahip olduğunuz toplam belleğe sığar. Bu durumda perisistbir seçenek, önbellek verilerinin diske dökülmesine izin veren bir depolama seçeneği kullanmak ve seçmektir.
Daniel Darabos

197

Sorunun daha iyi formüle edileceğini düşünüyorum:

RDD'de ne zaman önbellek çağırmamız veya devam etmemiz gerekir?

Kıvılcım süreçleri tembeldir, yani gerekli olana kadar hiçbir şey olmayacaktır. Soruyu hızlı bir şekilde cevaplamak için val textFile = sc.textFile("/user/emp.txt"), yayınlandıktan sonra , HadoopRDDdosyaya kaynak olarak kullanılarak verilere hiçbir şey olmaz, sadece a oluşturulur.

Diyelim ki bu verileri biraz dönüştürüyoruz:

val wordsRDD = textFile.flatMap(line => line.split("\\W"))

Yine, verilere hiçbir şey olmuyor. Şimdi , gerektiğinde uygulanacak wordsRDDbir başvuru testFileve bir işlev içeren yeni bir RDD var .

Yalnızca RDD üzerinde eylem çağrıldığında, örneğin wordsRDD.count, soy olarak adlandırılan RDD zinciri yürütülür. Yani, bölümler halinde ayrılmış veriler Spark kümesinin yürütücüler tarafından yüklenecek, flatMapişlev uygulanacak ve sonuç hesaplanacaktır.

Doğrusal bir soyda, bu örnekteki gibi cache(), gerekli değildir. Veriler yürütücülere yüklenecek, tüm dönüşümler uygulanacak ve son countolarak tüm bellekte hesaplanacak - veriler belleğe sığarsa.

cacheRDD'nin kökü dallandığında yararlıdır. Diyelim ki önceki örneğin kelimelerini pozitif ve negatif kelimeler için bir sayıya filtrelemek istiyorsunuz. Bunu şu şekilde yapabilirsiniz:

val positiveWordsCount = wordsRDD.filter(word => isPositive(word)).count()
val negativeWordsCount = wordsRDD.filter(word => isNegative(word)).count()

Burada, her şube verilerin yeniden yüklenmesini sağlar. Açık bir cacheifade eklemek, daha önce yapılan işlemlerin korunmasını ve yeniden kullanılmasını sağlayacaktır. İş şu şekilde görünecektir:

val textFile = sc.textFile("/user/emp.txt")
val wordsRDD = textFile.flatMap(line => line.split("\\W"))
wordsRDD.cache()
val positiveWordsCount = wordsRDD.filter(word => isPositive(word)).count()
val negativeWordsCount = wordsRDD.filter(word => isNegative(word)).count()

Bu nedenle, cachedaha sonraki işlemler için tekrar kullanılabilecek bir kontrol noktası oluşturduğundan 'soyun kırılması' söylenir.

Temel kural: Kullanım cachezaman RDD soy dışarı dalları veya RDD bir döngü içinde gibi birden çok kez kullanıldığında.


1
Muhteşem. Teşekkürler. İlgili bir soru daha. Önbelleğe aldığımızda veya devam ettiğimizde, veriler yürütücünün belleğinde veya çalışan düğümünün belleğinde depolanır. Yürütücünün belleği ise, Nasıl Spark hangi yürütücünün verilere sahip olduğunu tanımlar.
Ramana

1
@RamanaUppala yürütme belleği kullanılır. Önbellekleme için kullanılan yürütücü belleğinin bir kısmı yapılandırma tarafından kontrol edilir spark.storage.memoryFraction. Hangi yürütücünün hangi verilere sahip olduğuna ilişkin olarak, RDD yürütücülere dağıtılan bölümlerini izleyecektir.
maasg

5
Ben ancak ne yanlışım varsa @maasg düzelt cachene de persist olabilir soyunu kırmak .
zero323

Yukarıdaki örnekte .cache () ifadesi olmasaydı wordsRDD nerede saklanır?
sun_dare

iki saymadan önce, iki dalı bir rdd ve sayımla birleştirirsek ne olur? bu durumda önbellek yararlı mıdır?
Xiawei Zhang

30

RDD verilerini belleğe kaydetmek için açıkça "önbellek" veya "sürekli" çağırmamız gerekir mi?

Evet, sadece gerektiğinde.

RDD verileri varsayılan olarak bellekte dağıtılmış bir şekilde saklanır mı?

Hayır!

Ve bunun nedenleri:

  • Spark iki tür paylaşılan değişkeni destekler: tüm düğümlerde bellekteki bir değeri önbelleğe almak için kullanılabilen yayın değişkenleri ve sayaçlar ve toplamlar gibi yalnızca "eklenen" değişkenler olan akümülatörler.

  • RDD'ler iki tür işlemi destekler: varolan bir veri kümesinden yeni bir veri kümesi oluşturan dönüşümler ve veri kümesinde bir hesaplama yaptıktan sonra sürücü programına bir değer döndüren eylemler. Örneğin, harita her veri kümesi öğesini bir işlevden geçiren ve sonuçları temsil eden yeni bir RDD döndüren bir dönüşümdür. Öte yandan, azalt, bazı işlevleri kullanarak RDD'nin tüm öğelerini toplayan ve nihai sonucu sürücü programına döndüren bir eylemdir (dağıtılmış bir veri kümesini döndüren paralel bir azaltmaByKey olsa da).

  • Spark'daki tüm dönüşümler tembeldir, çünkü sonuçlarını hemen hesaplamazlar. Bunun yerine, bazı temel veri kümelerine (örneğin bir dosya) uygulanan dönüşümleri hatırlarlar. Dönüşümler yalnızca bir eylemin sürücü programına döndürülmesi için bir sonucun gerekli olması durumunda hesaplanır. Bu tasarım Spark'ın daha verimli çalışmasını sağlar - örneğin, harita aracılığıyla oluşturulan bir veri kümesinin küçültülerek kullanılacağını fark edebilir ve yalnızca daha büyük eşlenmiş veri kümesinden ziyade yalnızca sürücüye indirgeme sonucunu döndürebiliriz.

  • Varsayılan olarak, dönüştürülen her RDD, üzerinde her eylem gerçekleştirdiğinizde yeniden hesaplanabilir. Bununla birlikte, persist (veya önbellek) yöntemini kullanarak bellekteki bir RDD'yi de kalıcı tutabilirsiniz; bu durumda Spark, bir sonraki sorgulamada çok daha hızlı erişim için öğeleri kümede tutacaktır. Diskte kalıcı RDD'lerin desteklenmesi veya birden çok düğümde çoğaltılması için de destek vardır.

Daha fazla ayrıntı için lütfen Spark programlama kılavuzuna bakın .


1
Soruma cevap vermedi.
Ramana

Ne cevap vermiyor?
eliasah

1
RDD'nin verileri varsayılan bellekte saklandığında, neden Önbellek veya Kalıcı'yı çağırmamız gerekir?
Ramana

RDD'ler varsayılan olarak bellekte depolanmaz, bu nedenle
RDD'nin

2
Bu iyi bir cevap, neden indirildi bilmiyorum. RDD'lerin üst düzey kavramlardan nasıl çalıştığını açıklayan yukarıdan aşağıya bir cevaptır. Aşağıdan yukarıya doğru başka bir cevap ekledim: "bu satır ne yapıyor" dan başlayarak. Belki de Spark ile yeni başlayan biri için takip etmek daha kolaydır.
Daniel Darabos

11

RDD'lerinizi önbelleğe almanız gereken üç durum aşağıdadır:

RDD'yi birçok kez kullanma

aynı RDD üzerinde birden çok eylem gerçekleştirme

uzun (veya çok pahalı) dönüşüm zincirleri için


7

cacheYöntem çağrısı eklemek (veya geçici olarak eklemek) için başka bir neden ekleme .

hata ayıklama belleği sorunları için

ile cacheyöntem, kıvılcım RDD boyutu ile ilgili ayıklama bilgi verecektir. kıvılcım entegre kullanıcı arayüzünde RDD bellek tüketimi bilgisi alırsınız. ve bu hafıza sorunlarını teşhis etmede çok yardımcı oldu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.