MR的shuffle和Spark的shuffle之間的區別


mr的shuffle 
mapShuffle 
數據存到hdfs中是以塊進行存儲的,每一個塊對應一個分片,maptask就是從分片中獲取數據的 
在某個節點上啟動了map Task,map Task讀取是通過k-v來讀取的,讀取的數據會放到環形緩存區,這樣做的目的是為了防止IO的訪問次數,然后環形緩存區的內存達到一定的閥值的 
時候會把文件益寫到磁盤,溢出的各種小文件會合並成一個大文件,這個合並的過程中會進行排序,這個排序叫做歸並排序 
map階段會涉及到 
1.sort排序(默認按字典排序) 
2.合並(combiner合並) 
3.文件合並(merage 合並 總共有三種,默認是內存到磁盤) 
4.壓縮(設置壓縮就會執行) 
reduce Shuffle 
歸並排序完成后reduce端會拉取map端的數據,拉取的這個過程叫做copy過程,拉取的數據合並成一個文件,GroupComparator(默認,這個我們也可以自定義)是專門對文件夾里面的key進行分組 
然后就形成k-List(v1,v2,v3)的形式,然后reduce經過業務處理,最終輸出到hdfs,如果設置壓縮就會執行,不設置則不執行 
reduce階段會涉及到: 
1.sort排序 
2.分組(將相同的key的value放到一個容器的過程) 
3.merge文件合並

4.壓縮


spark shuffle的版本一
1.rdd中一個partition對應一個shufflemapTask任務,因為某個節點上可以有多個分區,所以可以有多個shufflemapTask 
2.每一個shufflemapTask都會為每一個resultTask創建一個bucket緩存(內存),bucket的數量=M x R,當內存達到一定值的時候會益寫到shuffleblockfile文件中 
3.shuffleMap task會封裝成一個叫mapStatus,這個mapstatus里面包含了每一個resultTask拉取數據的大小 
Mapstatus: 是ShuffleMapTask返回調度器scheduler的對象,包括任務運行的塊管理器地址和對應每個reducer的輸出大小。 
如果partitions的數量大於2000,則用HighlyCompressedMapStatus,否則用CompressedMapStatus。 
4.每一個resultTask拉取過來的數據,就會在內部形成一個rdd,這個rdd叫做shuffleRdd,這個rdd的數據優先存放到內存中,內存中不夠然后存到磁盤里 
如果是groupByKey算子就結束了,下次執行ReduceByKey的時候,再進行相同key的聚合操作,這個時候會把shuffle rdd進行聚合操作生成mapPartitionRdd,就是我們執行reduceByKey之后得到的那個rdd 
spark shuffle的版本二 
版本一的缺點:版本一的shuffle方式中會產生大量的小文件, 
版本二的優點:就是為了減少這么多小文件的生成 
bucket的數量=cpu*resultTask的個數 
版本二設計的原理:一個shuffleMapTask還是會寫入resultTask對應個數的本地文件,但是當下一個shuffleMapTask運行的時候會直接把數據寫到之前已經建立好的本地文件,這個文件可以復用,這種復用機制叫做consolidation機制 
我們把這一組的shuffle文件稱為shuffleGroup,每個文件中都存儲了很多shuffleMapTask對應的數據,這個文件叫做segment,這個時候因為不同的shuffleMapTask都是存在一個文件中 
所以建立索引文件,來標記shuffleMapTask在shuffleBlockFile的位置+偏移量,這樣就可以在一個文件里面把不同的shuffleMaptask數據分出來 
spark shuffle的版本三 
版本三的優點:是通過排序建立索引,相比較於版本二,它只有一個臨時文件,不管有多少個resultTask都只有一個臨時文件, 
缺點:這個排序操作是一個消耗CPU的操作,代價是會消耗很多的cpu 
版本二占用內存多,打開文件多,但不需排序,速度快。版本三占用內存少,打開文件少,速度相對慢。實踐證明使用第二種方案的應用場景更多些。 
shuffle的讀流程 
1.有一個類blockManager,封裝了臨時文件的位置信息,resultTask先通過blockManager,就知道我從哪個節點拿數據 
如果是遠程,它就是發起一次socket請求,創建一個socket鏈接。然后發起一次遠程調用,告訴遠程的讀取程序,讀取哪些數據。讀到的內容再通過socket傳過來。 
2.一條條讀數據和一塊塊讀數據的優缺點? 
如果是一條條讀取的話,實時性好,性能低下

一塊塊讀取的話性能高,但是實時性不好

Shuffle讀由reduce這邊發起,它需要先到臨時文件中讀,一般這個臨時文件和reduce不在一台節點上,它需要跨網絡去讀。但也不排除在一台服務器。不論如何它需要知道臨時文件的位置, 
這個是誰來告訴它的呢?它有一個BlockManager的類。這里就知道將來是從本地文件中讀取,還是需要從遠程服務器上讀取。 
讀進來后再做join或者combine的運算。 
這些臨時文件的位置就記錄在Map結構中。 
可以這樣理解分區partition是RDD存儲數據的地方,實際是個邏輯單位,真正要取數據時,它就調用BlockManage去讀,它是以數據塊的方式來讀。 
比如一次讀取32k還是64k。它不是一條一條讀,一條一條讀肯定性能低。它讀時首先是看本地還是遠程,如果是本地就直接讀這個文件了, 
如果是遠程,它就是發起一次socket請求,創建一個socket鏈接。然后發起一次遠程調用,告訴遠程的讀取程序,讀取哪些數據。讀到的內容再通過socket傳過來。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM