首先,對RDD相關的操作需要傳入閉包函數,如果這個函數需要通路外部定義的變量,就需要滿足一定條件(比如必須可被序列化),否則會抛出運作時異常。閉包函數在最終傳入到executor執行,需要經曆以下步驟:
1.driver通過反射,運作時找到閉包通路的變量,并封裝成一個對象,然後序列化該對象
2.将序列化後的對象通過網絡傳輸到worker節點
3.worker節點反序列化閉包對象
4.worker節點的executor執行閉包函數
簡而言之,就是要通過網絡傳遞函數、然後執行,期間會經曆序列化和反序列化,是以要求被傳遞的變量必須可以被序列化和反序列化,否則會抛類似Error:Task not serializable: java.io.NotSerializableException when calling function outside closure only on classes not objects這樣的異常。即使是本地執行時,也會按照上述的步驟執行,這也是為什麼不允許在RDD内部直接操作RDD的原因(SparkContext不支援序列化)。同時,在這些算子閉包内修改外部定義的變量不會被回報到driver端。