記憶體處理海量資料就不得不提到大資料技術中特別火的Spark,說到Spark,就不得不將它與Hadoop進行比較。這個答案將從Hadoop的基本概念出發,逐步引出Spark相對於Hadoop中的MapReduce的優勢。
Hadoop當初作為一種大資料技術橫空出世,經過多年的發展,Hadoop已經不單單指某一個技術,而是一個完整的大資料生態。
Hadoop的本質是分散式系統,因為單臺機器無法完成大資料的儲存、處理,所以需要將資料分別存放在不同的機器,並且能夠讓使用者像訪問單臺機器的資料一樣去訪問、操作這些資料。為了實現這個任務,Hadoop當年提出了兩個概念:HDFS與MapReduce。
即分散式的資料儲存方案,它的作用是將大量資料存放在一個由多臺機器組成的叢集中,每個機器存放一部分資料。
假設左邊是我們要儲存的資料集,HDFS叢集包含儲存的節點,即右邊的Data Node1、2、3,以及一個Name Node,用於存放各個資料塊所在的位置。比如我們現在需要訪問藍色資料塊以及綠色資料塊,分為以下幾個步驟:
客戶端向Name Node發出請求,獲取藍色資料塊與綠色資料塊的位置
Name Node返回Data Node1與Data Node2的地址
客戶端訪問Data Node1與Data Node2
如果我們要在叢集中增加一個數據,步驟如下:
客戶端向Name Node發出寫入請求
Name Node確認請求,並返回Data Node地址
開始向目的地址寫入資料,相應的機器在寫入成功後返回寫入成功的確認資訊
客戶端向Name Node傳送確認資訊
可以看出,整個叢集最關鍵的節點是Name Node,它管理了整個檔案系統的資訊,以及相應的檔案操作的排程。當然一個叢集不一定只有一個Name Node,如果僅有一個Name Node,它無法服務時整個叢集就都停止工作了。
上述的概念與資料存放訪問等操作僅僅是最簡單的情況,實際情況複雜的多,例如叢集還需要進行資料備份,當新寫入資料時,對備份資料的寫入也有一個複雜的流程。
MapReduce是一個抽象的程式設計模型,它將分散式的資料處理簡化為兩個操作,Map與Reduce。在MapReduce出現前,分散式叢集對資料的處理是很複雜的,因為如果我們要讓分散式叢集完成一個任務,首先需要將這些任務分解成很多子任務,然後要將這些子任務分配至不同的機器,最後完成了子任務後,需要將子任務產生的結果進行合併、彙總等操作。
而MapReduce抽象了這個流程,它將機器分為兩類,分別是Master和Worker。Master負責排程工作,Worker是實際執行任務的機器。Worker也可以分為兩種,Mapper和Reducer。Mapper主要負責子任務的執行,Reducer負責彙總各個Mapper的執行結果。
我們可以用一個簡單的例子來解釋這個過程,例如現在我們需要從一堆撲克牌中數出A的數量,那麼我們會將撲克牌分成幾份,每個人(Mapper)在分到的牌中數出A的數量,有個人數牌堆1,有個人數牌堆2。最後每個人數完了,將結果彙總(Reduce)起來,就是整堆牌中A的數量。
當然,真正的任務也不止這兩個操作,還包含Split,即切割資料,Shuffle,即歸類資料等操作。這些操作的設計也是特別精妙的,如果設計的不好,很可能影響整個系統的效能。
舉個例子,假如我們有個電商網站,儲存了大量使用者的購買記錄,我們想處理這些資料,那麼該如何對這些資料進行分片?如果說我們以使用者年齡作為分片的指標,那麼可能20-30歲年齡段的使用者數遠遠大於70+年齡段的使用者數。這樣50+年齡段的使用者資料處理完成後,20-30歲年齡段的使用者資料仍然還在處理。這就造成了每個Worker的處理時間不一,延遲了整個任務的完成進度。
除此之外,MapReduce這個抽象對於複雜任務是很難簡單實現的,需要處理大量邏輯,以及依賴關係。
總之,MapReduce這個模式在之後業界的實踐中遇到了如下問題:
1. Reduce需要在Map後完成,如果資料沒有合理的分割,則整個流程將會大大延時
2. Map與Reduce在處理複雜邏輯上有些力不從心
3. 效能瓶頸,因為MapReduce處理的中間結果需要存放在HDFS上,所以寫入寫出時間大大影響了效能
4. 每次任務的延時巨大,只適合批次資料的處理,不太能處理實時資料
Spark的出現一定程度上解決了上述的問題,可以作為MapReduce的替代品。其速度遠遠超過Hadoop的MapReduce,
上圖來自Spark的官網,執行同樣的Logistic Regression任務,Spark的執行用時遠遠小於Hadoop。這其實是因為Spark對於資料處理的執行方式不同,MapReduce是一個序列的過程,資料操作每一個步驟都需要一次讀寫硬碟操作。而Spark則是將每一步的結果快取至記憶體,減少了大量讀寫的時間。
為了完成這個一步到位,不需要硬碟多次讀寫的任務,Spark提出了新的思想,即RDD,基於分散式記憶體的資料抽象。
RDD的全稱叫做Resilient Distributed Datasets,即彈性分散式資料集,基於RDD,Spark定義了很多資料操作,比起MapReduce,大大提高了邏輯的表示能力。
當然,RDD這個概念十分難以理解,它並不是一個實際存在的東西,而是一個邏輯上的概念,在實際的物理儲存中,真實的資料仍然是存放在不同的節點中。它具有以下幾個特性:
分割槽
不可變
能並行操作
分割槽的意思是,同一個RDD中的資料儲存在叢集不同的節點中,正是這個特性,才能保證它能夠被並行處理。前面提到,RDD是一個邏輯上的概念,它只是一種資料的組織形式,我們可以用下圖來說明這個組織結構:
資料仍然是分佈在叢集中的各個節點,RDD中不存放任何資料,但是每個分割槽有它在RDD中的一個index,透過RDD自己的ID和分割槽的index可以確定每個資料塊的編號,從而能夠提取到相應的資料進行操作。
每一個RDD都是隻讀的,包含的分割槽資訊不可以被改變。因為已有的RDD無法被改變,所以每次對資料的操作,會產生新的RDD作為結果。每次產生的新RDD,我們需要記錄它是透過哪個RDD進行轉換操作得來,因此新老RDD存在依賴關係,這樣做的一個好處是不需要將每一步產生的資料結果進行儲存,如果某一步失敗了,只需要回滾至它的前一步RDD再次進行操作,而不需要重複所有的操作。具體依賴的細節這裡不再闡述,實現邏輯比較複雜,之後會有文章專門講解。
之前提到同一個RDD中的資料儲存在叢集不同的節點中,正是這個特性,才能保證它能夠被並行處理。因為不同節點的資料可以被分別處理,
比如現在一群人手中都分別拿著幾種水果,如果現在要給這些水果按照種類順序削皮,例如先削蘋果,後削梨,最後削桃子,肯定是一種水果分別在不同的人手上才能完成並行的任務。如果一個人手上都是蘋果,一個人手上都是梨,那隻能等一個人削完另一個人才能繼續。
相比MapReduce,Spark做出了幾個改進,從而獲得了效能大幅度的提升。
Spark將操作的資料放入記憶體中,而不是硬碟,這讓讀寫速度大大提升
記憶體處理海量資料就不得不提到大資料技術中特別火的Spark,說到Spark,就不得不將它與Hadoop進行比較。這個答案將從Hadoop的基本概念出發,逐步引出Spark相對於Hadoop中的MapReduce的優勢。
Hadoop當初作為一種大資料技術橫空出世,經過多年的發展,Hadoop已經不單單指某一個技術,而是一個完整的大資料生態。
Hadoop的本質是分散式系統,因為單臺機器無法完成大資料的儲存、處理,所以需要將資料分別存放在不同的機器,並且能夠讓使用者像訪問單臺機器的資料一樣去訪問、操作這些資料。為了實現這個任務,Hadoop當年提出了兩個概念:HDFS與MapReduce。
HDFS即分散式的資料儲存方案,它的作用是將大量資料存放在一個由多臺機器組成的叢集中,每個機器存放一部分資料。
假設左邊是我們要儲存的資料集,HDFS叢集包含儲存的節點,即右邊的Data Node1、2、3,以及一個Name Node,用於存放各個資料塊所在的位置。比如我們現在需要訪問藍色資料塊以及綠色資料塊,分為以下幾個步驟:
客戶端向Name Node發出請求,獲取藍色資料塊與綠色資料塊的位置
Name Node返回Data Node1與Data Node2的地址
客戶端訪問Data Node1與Data Node2
如果我們要在叢集中增加一個數據,步驟如下:
客戶端向Name Node發出寫入請求
Name Node確認請求,並返回Data Node地址
開始向目的地址寫入資料,相應的機器在寫入成功後返回寫入成功的確認資訊
客戶端向Name Node傳送確認資訊
可以看出,整個叢集最關鍵的節點是Name Node,它管理了整個檔案系統的資訊,以及相應的檔案操作的排程。當然一個叢集不一定只有一個Name Node,如果僅有一個Name Node,它無法服務時整個叢集就都停止工作了。
上述的概念與資料存放訪問等操作僅僅是最簡單的情況,實際情況複雜的多,例如叢集還需要進行資料備份,當新寫入資料時,對備份資料的寫入也有一個複雜的流程。
MapReduceMapReduce是一個抽象的程式設計模型,它將分散式的資料處理簡化為兩個操作,Map與Reduce。在MapReduce出現前,分散式叢集對資料的處理是很複雜的,因為如果我們要讓分散式叢集完成一個任務,首先需要將這些任務分解成很多子任務,然後要將這些子任務分配至不同的機器,最後完成了子任務後,需要將子任務產生的結果進行合併、彙總等操作。
而MapReduce抽象了這個流程,它將機器分為兩類,分別是Master和Worker。Master負責排程工作,Worker是實際執行任務的機器。Worker也可以分為兩種,Mapper和Reducer。Mapper主要負責子任務的執行,Reducer負責彙總各個Mapper的執行結果。
我們可以用一個簡單的例子來解釋這個過程,例如現在我們需要從一堆撲克牌中數出A的數量,那麼我們會將撲克牌分成幾份,每個人(Mapper)在分到的牌中數出A的數量,有個人數牌堆1,有個人數牌堆2。最後每個人數完了,將結果彙總(Reduce)起來,就是整堆牌中A的數量。
當然,真正的任務也不止這兩個操作,還包含Split,即切割資料,Shuffle,即歸類資料等操作。這些操作的設計也是特別精妙的,如果設計的不好,很可能影響整個系統的效能。
舉個例子,假如我們有個電商網站,儲存了大量使用者的購買記錄,我們想處理這些資料,那麼該如何對這些資料進行分片?如果說我們以使用者年齡作為分片的指標,那麼可能20-30歲年齡段的使用者數遠遠大於70+年齡段的使用者數。這樣50+年齡段的使用者資料處理完成後,20-30歲年齡段的使用者資料仍然還在處理。這就造成了每個Worker的處理時間不一,延遲了整個任務的完成進度。
除此之外,MapReduce這個抽象對於複雜任務是很難簡單實現的,需要處理大量邏輯,以及依賴關係。
總之,MapReduce這個模式在之後業界的實踐中遇到了如下問題:
1. Reduce需要在Map後完成,如果資料沒有合理的分割,則整個流程將會大大延時
2. Map與Reduce在處理複雜邏輯上有些力不從心
3. 效能瓶頸,因為MapReduce處理的中間結果需要存放在HDFS上,所以寫入寫出時間大大影響了效能
4. 每次任務的延時巨大,只適合批次資料的處理,不太能處理實時資料
SparkSpark的出現一定程度上解決了上述的問題,可以作為MapReduce的替代品。其速度遠遠超過Hadoop的MapReduce,
上圖來自Spark的官網,執行同樣的Logistic Regression任務,Spark的執行用時遠遠小於Hadoop。這其實是因為Spark對於資料處理的執行方式不同,MapReduce是一個序列的過程,資料操作每一個步驟都需要一次讀寫硬碟操作。而Spark則是將每一步的結果快取至記憶體,減少了大量讀寫的時間。
為了完成這個一步到位,不需要硬碟多次讀寫的任務,Spark提出了新的思想,即RDD,基於分散式記憶體的資料抽象。
RDD的全稱叫做Resilient Distributed Datasets,即彈性分散式資料集,基於RDD,Spark定義了很多資料操作,比起MapReduce,大大提高了邏輯的表示能力。
當然,RDD這個概念十分難以理解,它並不是一個實際存在的東西,而是一個邏輯上的概念,在實際的物理儲存中,真實的資料仍然是存放在不同的節點中。它具有以下幾個特性:
分割槽
不可變
能並行操作
分割槽分割槽的意思是,同一個RDD中的資料儲存在叢集不同的節點中,正是這個特性,才能保證它能夠被並行處理。前面提到,RDD是一個邏輯上的概念,它只是一種資料的組織形式,我們可以用下圖來說明這個組織結構:
資料仍然是分佈在叢集中的各個節點,RDD中不存放任何資料,但是每個分割槽有它在RDD中的一個index,透過RDD自己的ID和分割槽的index可以確定每個資料塊的編號,從而能夠提取到相應的資料進行操作。
不可變每一個RDD都是隻讀的,包含的分割槽資訊不可以被改變。因為已有的RDD無法被改變,所以每次對資料的操作,會產生新的RDD作為結果。每次產生的新RDD,我們需要記錄它是透過哪個RDD進行轉換操作得來,因此新老RDD存在依賴關係,這樣做的一個好處是不需要將每一步產生的資料結果進行儲存,如果某一步失敗了,只需要回滾至它的前一步RDD再次進行操作,而不需要重複所有的操作。具體依賴的細節這裡不再闡述,實現邏輯比較複雜,之後會有文章專門講解。
並行操作之前提到同一個RDD中的資料儲存在叢集不同的節點中,正是這個特性,才能保證它能夠被並行處理。因為不同節點的資料可以被分別處理,
比如現在一群人手中都分別拿著幾種水果,如果現在要給這些水果按照種類順序削皮,例如先削蘋果,後削梨,最後削桃子,肯定是一種水果分別在不同的人手上才能完成並行的任務。如果一個人手上都是蘋果,一個人手上都是梨,那隻能等一個人削完另一個人才能繼續。
總結相比MapReduce,Spark做出了幾個改進,從而獲得了效能大幅度的提升。
Spark將操作的資料放入記憶體中,而不是硬碟,這讓讀寫速度大大提升
Spark任務中每一步操作產生的結果並不需要寫入硬碟,而是隻記錄操作之間的依賴關係,因此提高了容錯率,並大大降低了恢復任務的成本使用分割槽的方式,讓資料能夠並行處理