[英]Object cache on Spark executors
Spark專家的一個好問題。
我正在處理map
操作(RDD)中的數據。 在mapper函數中,我需要查找類A
對象以用於處理RDD中的元素。
由於這將在執行程序上執行,並且類型A
的元素(將被查找)的創建恰好是一項昂貴的操作,我想在每個執行程序上預加載和緩存這些對象。 這樣做的最佳方式是什么?
一個想法是廣播查找表,但A
類不可序列化(無法控制其實現)。
另一個想法是將它們加載到單個對象中。 但是,我想控制加載到查找表中的內容(例如,可能在不同的Spark作業上有不同的數據)。
理想情況下,我想指定將在執行程序上加載一次(包括Streaming的情況,以便查找表在批處理之間保留在內存中),通過在啟動期間驅動程序上可用的參數,數據得到處理。
是否有干凈優雅的方式或無法實現?
這正是broadcast.
的目標用例broadcast.
廣播變量傳輸一次並使用種子有效地移動到所有執行器,並保留在內存/本地磁盤中,直到您不再需要它們為止。
在使用其他人的界面時,序列化經常會成為一個問題。 如果您可以強制執行您使用的對象是可序列化的,那么這將是最佳解決方案。 如果這是不可能的,那么你的生活會變得更加復雜。 如果無法序列化A
對象,則必須在每個任務的執行程序上創建它們。 如果它們存儲在某個文件中,則看起來像:
rdd.mapPartitions { it =>
val lookupTable = loadLookupTable(path)
it.map(elem => fn(lookupTable, elem))
}
請注意,如果您正在使用此模型,則必須為每個任務加載一次查找表 - 您無法從廣播變量的跨任務持久性中受益。
編輯:這是另一個模型,我相信讓你可以跨每個JVM的任務共享查找表。
class BroadcastableLookupTable {
@transient val lookupTable: LookupTable[A] = null
def get: LookupTable[A] = {
if (lookupTable == null)
lookupTable = < load lookup table from disk>
lookupTable
}
}
這個類可以廣播(沒有實質性的傳輸),並且第一次按JVM調用它,你將加載查找表並返回它。
如果序列化變得不可能,那么如何將查找對象存儲在數據庫中? 它不是最簡單的解決方案,但應該可以正常工作。 我可以建議檢查例如spark-redis ,但我相信那里有更好的解決方案。
由於A
不可序列化,因此最簡單的解決方案是創建自己的可序列化類型A1
其中包含計算所需的所有A
數據。 然后在廣播中使用新的查找表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.