在這篇論文之前 — 它所降落的世界
到 2010 年,MapReduce 模型已經成為在不可靠的商用叢集上運算的預設方式,Dryad 與 Map-Reduce-Merge 則進一步擴充了它支援的資料流形狀。這些系統的交換條件都一樣:使用者寫出一張非循環的運算子圖,系統則負責考量資料位置的排程、負載平衡與容錯,全程不需使用者介入。但只要應用會重複碰同一份資料,這個交換條件就嚴重漏水。跑梯度下降的 Hadoop 使用者必須把每一次迭代寫成一個獨立 job,每次都從 HDFS 重讀整份資料;透過 Pig 或 Hive 做臨時 SQL 探索的分析師,每條查詢都要等上數十秒,因為每條查詢都是一個從磁碟讀資料的全新 MapReduce job。看似顯而易見的替代方案——分散式共享記憶體(DSM)——雖然已被研究二十年,卻是用 checkpoint 來容錯,失敗時整支程式必須回捲,而且即使什麼都沒壞也要付出額外成本;Twister 雖能讓靜態資料跨迭代留在記憶體,卻完全沒有容錯,而且只允許一個 map 函式與一個 reduce 函式。
術語 — 依本篇論文的用法
- Resilient distributed dataset(RDD)
- 一個唯讀、切分到多台機器上的物件集合,任一分割區遺失都能被重建。它的元素不必存在於實體儲存上;handle 本身就帶著足以從可靠儲存中的資料算出整個資料集的資訊。
- Lineage
- 由資料集物件串成的鏈,記錄每個 RDD 指向父物件的指標,以及父物件是如何被轉換的。Spark 重播這條鏈只重算遺失的分割區,而不是靠 checkpoint 與回捲。
- Working set(工作集)
- 應用會跨多個平行操作重複使用的那份資料,例如迭代式機器學習或反覆執行的互動查詢。這正是非循環資料流系統處理不好、而 Spark 專門為之設計的工作負載類型。
- 平行操作(parallel operation)
- 把閉包送到 worker 上、藉此觸發 RDD 運算的動作:reduce 以結合律函式合併元素並回傳給 driver,collect 把所有元素送回 driver,foreach 則為副作用而對每個元素執行函式。
- Driver 程式
- 使用者的主程式,負責實作應用的高階控制流程、定義 RDD 與共享變數,並在叢集上啟動平行操作。所有 reduce 與 collect 的結果都回到這裡。
- 廣播變數(broadcast variable)
- 包住一份大型唯讀值的封裝,保證該值只會被複製到每個 worker 一次,而不是隨每個閉包一起打包。它的序列化形式只是共享檔案系統中的一個檔案路徑,而且可跨多個平行操作重複使用。
- Accumulator(累加器)
- worker 只能以結合律運算加入、且只有 driver 能讀取的共享變數,只要型別具備 add 運算與 zero 值即可定義。只加不減的語意讓它容易做到容錯,driver 對每個分割區的更新只套用一次。
- cache 動作
- 一種持久化設定的變更,讓 RDD 維持延遲求值,但提示系統在第一次算出後應保留在記憶體中。它僅僅是提示:叢集記憶體不足時,Spark 會在用到那些分割區時重新計算。
- 偏好位置(preferred locations)
- 由 getPreferredLocations 回傳、以分割區為單位的放置提示,供 delay scheduling 把 task 送到資料所在之處。對已快取的資料集,這些位置一開始沿用父物件,某分割區在某節點被快取後即更新為該節點。