MapReduce是一種框架,所謂框架,也即是一個“條條框框”。那么MapReduce的“條條框框”如下:
1、每啟動一個任務,就會啟動一個JVM,JVM啟動是非常耗時的操作,因為一個JVM需要加載很多數據比如很多jar,很多類等等。
2、中間結果要基於磁盤來排序,因為reduce只能讀以key排好序的數據,所以MapReduce需要花費大量時間(主要是磁盤IO)在排序環節。
3、結果寫入到HDFS中,這個是最大瓶頸,HDFS的吞吐量是非常低的。
這里以線性回歸來舉例,LR是一種迭代的算法,所謂迭代,也即是多輪,且每輪都依賴於上一輪的結果。我們假設一個迭代需要一個MR Job,
這個job有幾個非常耗時的操作,全部和HDFS有關:
1、讀取數據,即便是SGD(隨機梯度下降),也是需要讀取全部的訓練數據的。
2、寫結果,因為每一輪為了給下一輪提供數據,每個Job都會把計算結果(梯度)返回給Driver而不是寫入HDFS。
我們假設HDFS的吞吐量是本地磁盤的吞吐量的1/10,那么如果存在這么一種框架,它能讓我們不讀HDFS,而是直接讀和寫本地磁盤,那么每一輪迭代就只需要MR實現的1/10的時間。我們再假設如果這個框架能把數據全部放內存中,省去讀取磁盤的,那么它就能更快,達到100倍速度於MR模式。
Spark針對對於MapReduce的幾個約束,做出以下突破:
1、對於新的任務,Executor只需啟動一條線程即可,這讓job在啟動方面變得很快,每個任務的啟動負載相對於啟動一個全新的JVM來說是非常輕的。
2、Spark在shuffle時其實也是要寫本地磁盤的,不過它的reduce端是用內存中的HashMap做aggregate或reduce,相比較MapReduce的reduce端用磁盤來做merge,基於內存的方法會快很多。不過Spark在這點上有個缺陷,那么就是如果reduce端的內存不夠,會報OOM錯誤,因此需要用戶設定一個正確的reduce端的分區數。
3、Spark在執行一個action后,可以把結果放在內存或者本地磁盤中,而非HDFS上,鑒於內存和本地磁盤的吞吐量都高於HDFS,這種做法非常適合迭代邏輯。
Spark就是這么一種框架,它打破了MR框架的約束,讓迭代任務變得非常地快。