HDFS讀寫數據的過程
寫
1)client向namenode發送請求,namenode從元數據中檢查目標文件是否存在,上傳路徑路徑是否合法
2)namenode返回是否可以上傳文件,假設可以上傳
3)client請求第一個 block該傳輸到哪些datanode服務器上
4)namenode返回可以上傳的datanode 服務器dn1 dn2 dn4
5)client將於datanode中最近的一個datanode 建立RPC連接 ,形成pipeline 通道 , pipeline會連接所有將被上傳的datanode機器,
6)、client開始往dn1上傳第一個block(先從磁盤讀取數據放到一個本地內存緩存),以packet爲單位,dn1收到一個packet就會傳給dn2,dn2傳給dn4
7)當一個block傳輸完成之後,client再次請求namenode上傳第二個block的服務器。最終完成上傳
讀
1)client向namenode通信查詢元數據,找到存放block文件的datanode
2)挑選一臺datanode(就近原則,然後隨機)服務器,請求建立socket流 利用FileChannel讀取數據
3)datanode開始發送數據(從磁盤裏面讀取數據放入流,以packet爲單位來做校驗)
4)客戶端以packet爲單位接收,現在本地緩存,然後寫入目標文件
mapreduce的執行流程 (大體流程)
1、 一個mr程序啓動的時候,最先啓動的是MRAppMaster,MRAppMaster啓動後根據本次job的描述信息,計算出需要的maptask實例數量,然後向集羣申請機器啓動相應數量的maptask進程
2、 maptask進程啓動之後,根據給定的數據切片範圍進行數據處理,主體流程爲:T
a) 利用客戶指定的inputformat來獲取RecordReader讀取數據,形成輸入KV對
b) 將輸入KV對傳遞給客戶定義的map()方法,做邏輯運算,並將map()方法輸出的KV對收集到緩存
c) 將緩存中的KV對按照K分區排序後不斷溢寫到磁盤文.件
3、 MRAppMaster監控到所有maptask進程任務完成之後,會根據客戶指定的參數啓動相應數量的reducetask進程,並告知reducetask進程要處理的數據範圍(數據分區)
4、 Reducetask進程啓動之後,根據MRAppMaster告知的待處理數據所在位置,從若干臺maptask運行所在機器上獲取到若干個maptask輸出結果文件,並在本地進行重新歸併排序,然後按照相同key的KV爲一個組,調用客戶定義的reduce()方法進行邏輯運算,並收集運算輸出的結果KV,然後調用客戶指定的outputformat將結果數據輸出到外部存儲
mapTast 的 並行機制
一個job的map階段並行度由客戶端在提交job時決定。而客戶端對應map階段並行度的劃分規則:
將文件劃分爲多個split 每個split 交給一個mapTast進行處理 一個split的大小默認爲128MB
切片的形成是由FileInputFormat實現類的getSplits()方法完成,
如果input的文件非常的大,比如1TB,可以考慮將hdfs上的每個block size設大,比如設成256MB或者512MB
如果input的文件的文件非常小 ,且非常多 啓動多個maptast明顯會降低程序的效率 , 可以先將小文件合併成大文件 再交給mapreduce處理
FileInputFormat切片機制
1、切片定義在InputFormat類中的getSplit()方法
2、FileInputFormat中默認的切片機制:
簡單地按照文件的內容長度進行切片 切片大小,默認等於block大小 切片時不考慮數據集整體,而是逐個針對每一個文件單獨切片比如待處理數據有兩個文件:
file1.txt 320M
file2.txt 10M
經過FileInputFormat的切片機制運算後,形成的切片信息如下:
file1.txt.split1-- 0~128
file1.txt.split2-- 128~256
file1.txt.split3-- 256~320
file2.txt.split1-- 0~10M
3、FileInputFormat中切片的大小的參數配置
通過分析源碼,在FileInputFormat中,計算切片大小的邏輯:Math.max(minSize, Math.min(maxSize, blockSize)); 切片主要由這幾個值來運算決定
minsize:默認值:1
配置參數:
mapreduce.input.fileinputformat.split.minsize
maxsize:默認值:Long.MAXValue
配置參數:mapreduce.input.fileinputformat.split.maxsize
blocksize
因此,默認情況下,切片大小=blocksize
maxsize(切片最大值):
參數如果調得比blocksize小,則會讓切片變小,而且就等於配置的這個參數的值
minsize (切片最小值):
參數調的比blockSize大,則可以讓切片變得比blocksize還大
選擇併發數的影響因素:
運算節點的硬件配置 運算任務的類型:CPU密集型還是IO密集型 運算任務的數據量
ReduceTask並行度的決定
這個是由我們自己設置的
//默認值是1,手動設置爲4
job.setNumReduceTasks(4);
如果數據分佈不均勻,就有可能在reduce階段產生數據傾斜
注意: reducetask數量並不是任意設置,還要考慮業務邏輯需求,有些情況下,需要計算全局彙總結果,就只能有1個reducetask
儘量不要運行太多的reduce task。對大多數job來說,最好rduce的個數最多和集羣中的reduce持平,或者比集羣的 reduce slots小。這個對於小集羣而言,尤其重要。
mapreduce的shuffle機制(只能簡單概述一下以統計統計單詞爲例)
map端
當map函數通過context.write()開始輸出數據
數,outputCollector將數據以<key,value>輸出到輸出到環形緩衝
環形緩衝區(
) 默認大小爲100 實際上是是一個 字節數組 ,其中包括了數據區,和索引區 當輸出到環形緩衝區的數據達到閥值的時候,kvbuffer
默認爲80% 系統就會開啓一個線程將數據寫入磁盤, 這個過程叫做spill (索引區的內容保存在內存, 也肯也寫入到文件中)
在寫入之前 , 通過調用
Partitioner
的getPartition(),計算出數據要分到那個reduce,將這個信息同數據一起保存kvbuffer, 並對數據的key進行了一個快速排序
(QuickSort)
排序後的數據被寫入到
mapreduce.cluster.local.dir
配置的目錄中的其中一個,Spill文件名像sipll0.out,spill1.out等
最後, 多個spill小文件 ,會合併成一個大文件 (這裏進行了一個合併排序, 分區),並最終形成一個唯一大文件 以及相對於的索引文件 建立索引文件是爲了方便進行數據的查找,
最後, 多個spill小文件 ,會合併成一個大文件 (這裏進行了一個合併排序, 分區),並最終形成一個唯一大文件 以及相對於的索引文件 建立索引文件是爲了方便進行數據的查找,
Reducer端
Reducer端的shuffle主要包括三個階段,copy、sort(merge)和reduce。
copy: Mrappmaster告知reduce ,mapTast的位置 , 每個Reducer只獲取屬於自己分區的數據
sort:這個階段按照 ,在每個reduce對自己這個分區的數據 進行一個歸併排序 ,
reduce: 合併後的文件作爲輸入傳遞給Reducer,Reducer針對每個key及其排序的數據調用reduce函數。產生的reduce輸出一般寫入到HDFS