問題:
1.RDD中基本所有的數(shù)據(jù)都是存儲(chǔ)都在堆內(nèi)存里,這部分?jǐn)?shù)據(jù)是通過jvm中的GC管理的,進(jìn)行Spark操作的時(shí)候可能會(huì)出現(xiàn)資源不一致的問題,當(dāng)我們長時(shí)間不使用某個(gè)變量,變量會(huì)被gc回收,但是Spark顯示的時(shí)候顯示不出來這一部分?jǐn)?shù)據(jù),所以說Spark無法精確的顯示內(nèi)存信息。
2.發(fā)生RDD數(shù)據(jù)丟失的情況的時(shí)候,可以根據(jù)lineage重新計(jì)算RDD的數(shù)據(jù),但是如果依賴關(guān)系是寬依賴,重算的消耗比較大,可以使用checkpoint將數(shù)據(jù)提前寫入磁盤,讀寫磁盤的過程消耗寶貴的IO資源并且寫入磁盤之后,依賴關(guān)系會(huì)消失。
Spark速度非??斓脑蛑?,就是在不同操作中可以在內(nèi)存中持久化或緩存數(shù)據(jù)集。當(dāng)持久化某個(gè)RDD后,每一個(gè)節(jié)點(diǎn)都將把計(jì)算的分片結(jié)果保存在內(nèi)存中,并在對此RDD或衍生出的RDD進(jìn)行的其他動(dòng)作中重用。這使得后續(xù)的動(dòng)作變得更加迅速。RDD相關(guān)的持久化和緩存,是Spark最重要的特征之一。可以說,緩存是Spark構(gòu)建迭代式算法和快速交互式查詢的關(guān)鍵。如果一個(gè)有持久化數(shù)據(jù)的節(jié)點(diǎn)發(fā)生故障,Spark 會(huì)在需要用到緩存的數(shù)據(jù)時(shí)重算丟失的數(shù)據(jù)分區(qū)。
持久化緩存使用的是堆外內(nèi)存,直接由操作系統(tǒng)管理,不受GC的控制,并且堆外內(nèi)存空間要比堆內(nèi)存空間大3倍。使用起來也比較簡單。當(dāng)數(shù)據(jù)丟失之后Spark首先會(huì)去緩存中查找數(shù)據(jù),沒有緩存就檢查checkpoint,如果也沒有就只能重新計(jì)算了。
val sumed: RDD[(String, Int)] = tuples.reduceByKey(_+_).cache()
需要注意的是cache是transformation函數(shù),所以需要一個(gè)action算子來觸發(fā)。一般來說緩存shuffle之后的數(shù)據(jù),以為shuffle的代價(jià)比較大,通常shuffle之后緊接一個(gè)cache。
持久化等級(jí):
val NONE = new StorageLevel(false, false, false, false)
val DISK_ONLY = new StorageLevel(true, false, false, false)
val DISK_ONLY_2 = new StorageLevel(true, false, false, false, 2)
val MEMORY_ONLY = new StorageLevel(false, true, false, true)
val MEMORY_ONLY_2 = new StorageLevel(false, true, false, true, 2)
val MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)
val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, false, 2)
val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)
val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false, false)
val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)
val OFF_HEAP = new StorageLevel(false, false, true, false)
參數(shù)(按順序)
useDisk是否使用磁盤
useMemory是否使用內(nèi)存
useoffHeap 是否使用堆外內(nèi)存
deserialized是否使用反序列化
replication 副本的數(shù)量
如果使用cache函數(shù)緩存,默認(rèn)使用MEMORY_ONLY,如果需要更改持久化等級(jí),可以使用prisist函數(shù)設(shè)置持久化等級(jí)。
緩存的RDD什么時(shí)候去釋放呢?當(dāng)我們調(diào)用persist緩存一個(gè)RDD時(shí),會(huì)調(diào)用registerRDDForCleanup(this),這就是將本身的RDD注冊到一個(gè)弱引用中。當(dāng)這個(gè)RDD變?yōu)椴豢蛇_(dá)時(shí),會(huì)自動(dòng)將該RDD對象插入到referenceQueue中,等到下次GC時(shí)就會(huì)走doCleanupRDD分支。為了讓出內(nèi)存,除了手動(dòng)unpersist之外,MetadataCleaner的SPARK_CONTEXT會(huì)定期清理persistentRdds中過期的數(shù)據(jù),其實(shí)與unpersist產(chǎn)生的作用是一樣的。一旦清理了,那這個(gè)緩存的RDD就沒有強(qiáng)引用了。