在使用中一直知其然不知其所以然的地使用RDD.cache(),系統的學習之后發現還有一個與cache功能類似看起來冗余的persist
點進去一探究竟之后發現cache()是persist()的特例,persist可以指定一個StorageLevel。StorageLevel的列表可以在StorageLevel 伴生單例對象中找到:
cache的源碼:
/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */ def cache(): this.type = persist()
persist的源碼:
/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */ def persist(): this.type = persist(StorageLevel.MEMORY_ONLY)
區別就是cache默認是在內存中存儲的,而persist可以設置存儲的級別:
持久化級別 | 含義解釋 |
---|---|
MEMORY_ONLY | 使用未序列化的Java對象格式,將數據保存在內存中。如果內存不夠存放所有的數據,則數據可能就不會進行持久化。那么下次對這個RDD執行算子 操作時,那些沒有被持久化的數據,需要從源頭處重新計算一遍。這是默認的持久化策略,使用cache()方法時,實際就是使用的這種持久化策略。 |
MEMORY_AND_DISK | 使用未序列化的Java對象格式,優先嘗試將數據保存在內存中。如果內存不夠存放所有的數據,會將數據寫入磁盤文件中,下次對這個RDD執行算子時,持久化在磁盤文件中的數據會被讀取出來使用。 |
MEMORY_ONLY_SER | 基本含義同MEMORY_ONLY。唯一的區別是,會將RDD中的數據進行序列化,RDD的每個partition會被序列化成一個字節數組。這種方式更加節省內存,從而可以避免持久化的數據占用過多內存導致頻繁GC。 |
MEMORY_AND_DISK_SER | 基本含義同MEMORY_AND_DISK。唯一的區別是,會將RDD中的數據進行序列化,RDD的每個partition會被序列化成一個字節數組。這種方式更加節省內存,從而可以避免持久化的數據占用過多內存導致頻繁GC。 |
DISK_ONLY | 使用未序列化的Java對象格式,將數據全部寫入磁盤文件中。 |
MEMORY_ONLY_2, MEMORY_AND_DISK_2, 等等. | 對於上述任意一種持久化策略,如果加上后綴_2,代表的是將每個持久化的數據,都復制一份副本,並將副本保存到其他節點上。這種基於副本的持久化 機制主要用於進行容錯。假如某個節點掛掉,節點的內存或磁盤中的持久化數據丟失了,那么后續對RDD計算時還可以使用該數據在其他節點上的副本。如果沒有 副本的話,就只能將這些數據從源頭處重新計算一遍了。 |
如何選擇一種最合適的持久化策略
- 默認情況下,性能最高的當然是MEMORY_ONLY,但前提是你的內存必須足夠足夠大,可以綽綽有余地存放下整個RDD的所有數據。因為 不進行序列化與反序列化操作,就避免了這部分的性能開銷;對這個RDD的后續算子操作,都是基於純內存中的數據的操作,不需要從磁盤文件中讀取數據,性能 也很高;而且不需要復制一份數據副本,並遠程傳送到其他節點上。但是這里必須要注意的是,在實際的生產環境中,恐怕能夠直接用這種策略的場景還是有限的, 如果RDD中數據比較多時(比如幾十億),直接用這種持久化級別,會導致JVM的OOM內存溢出異常。
- 如果使用MEMORY_ONLY級別時發生了內存溢出,那么建議嘗試使用MEMORY_ONLY_SER級別。該級別會將RDD數據序列化 后再保存在內存中,此時每個partition僅僅是一個字節數組而已,大大減少了對象數量,並降低了內存占用。這種級別比MEMORY_ONLY多出來 的性能開銷,主要就是序列化與反序列化的開銷。但是后續算子可以基於純內存進行操作,因此性能總體還是比較高的。此外,可能發生的問題同上,如果RDD中 的數據量過多的話,還是可能會導致OOM內存溢出的異常。
- 如果純內存的級別都無法使用,那么建議使用MEMORY_AND_DISK_SER策略,而不是MEMORY_AND_DISK策略。因為 既然到了這一步,就說明RDD的數據量很大,內存無法完全放下。序列化后的數據比較少,可以節省內存和磁盤的空間開銷。同時該策略會優先盡量嘗試將數據緩 存在內存中,內存緩存不下才會寫入磁盤。
- 通常不建議使用DISK_ONLY和后綴為_2的級別:因為完全基於磁盤文件進行數據的讀寫,會導致性能急劇降低,有時還不如重新計算一次 所有RDD。后綴為_2的級別,必須將所有數據都復制一份副本,並發送到其他節點上,數據復制以及網絡傳輸會導致較大的性能開銷,除非是要求作業的高可用 性,否則不建議使用。
參考文章地址:http://lxw1234.com/archives/2016/05/661.htm