比較慚愧,博客很久(半年)沒更新了。最近也自己搭了個博客,wordpress玩的還不是很熟,感興趣的朋友可以多多交流哈!地址是:http://www.leocook.org/
另外,我建了個QQ群:305994766,希望對大數據、算法研發、系統架構感興趣的朋友能夠加入進來,大家一起學習,共同進步(進群請說明自己的公司-職業-昵稱)。
1.應用程序角度進行優化
1.1.減少不必要的reduce任務
若對於同一份數據需要多次處理,可以嘗試先排序、分區,然后自定義InputSplit將某一個分區作為一個Map的輸入,在Map中處理數據,將Reduce的個數設置為空。
1.2.外部文件引用
如字典、配置文件等需要在Task之間共享的數據,可使用分布式緩存DistributedCache或者使用-files
1.3.使用Combiner
combiner是發生在map端的,作用是歸並Map端輸出的文件,這樣Map端輸出的數據量就小了,減少了Map端和reduce端間的數據傳輸。需要注意的是,Combiner不能影響作業的結果;不是每個MR都可以使用Combiner的,需要根據具體業務來定;Combiner是發生在Map端的,不能垮Map來執行(只有Reduce可以接收多個Map任務的輸出數據)
1.4.使用合適的Writable類型
盡可能使用二進制的Writable類型,例如:IntWritable, FloatWritable等,而不是Text。因為在一個批處理系統中將數值轉換為文本時低效率的。使用二進制的Writable類型可以降低cpu資源的消耗,也可以減少Map端中間數據、結果數據占用的空間。
1.5.盡可能的少創建新的Java對象
a)需要注意的Writable對象,例如下面的寫法:
public void map(...) { … for (String word : words) { output.collect(new Text(word), new IntWritable(1)); } }
這樣會沖去創建對象new Text(word)和new IntWritable(1)),這樣可能會產生海量的短周期對象。更高效的寫法見下:
class MyMapper … { Text wordText = new Text(); IntWritable one = new IntWritable(1); public void map(...) { for (String word: words) { wordText.set(word); output.collect(wordText, one); } } }
b)對於可變字符串,使用StringBuffer而不是String
String類是經過final修飾的,那么每次對它的修改都會產生臨時對象,而SB則不會。
2. Linux系統層面上的配置調優
2.1. 文件系統的配置
a) 關閉文件在被操作時會記下時間戳:noatime和nodiratime
b) 選擇I/O性能較好的文件系統(Hadoop比較依賴本地的文件系統)
2.2. Linux文件系統預讀緩沖區大小
命令blockdev
2.3. 去除RAID和LVM
2.4. 增大同時打開的文件數和網絡連接數
ulimit
net.core.somaxconn
2.5. 關閉swap分區
在Hadoop中,對於每個作業處理的數據量和每個Task中用到的各種緩沖,用戶都是完全可控的。
/etc/sysctl.conf
2.6. I/O調度器選擇
詳情見AMD的白皮書
3. Hadoop平台內參數調優
Hadoop相關可配置參數共有幾百個,但是其中只有三十個左右會對其性能產生顯著影響。
3.1. 計算資源優化
a) 設置合理的slot(資源槽位)
mapred.tasktracker.map.tasks.maximum / mapred.tasktracker.reduce.tasks.maximum
參數說明:每個TaskTracker上可並發執行的Map Task和Reduce Task數目
默認值:都是2
推薦值:根據具體的節點資源來看,推薦值是(core_per_node)/2~2*(cores_per_node)
單位:無
3.2. 節點間的通信優化
a) TaskTracker和JobTracker之間的心跳間隔
這個值太小的話,在一個大集群中會造成JobTracker需要處理高並發心跳,可能會有很大的壓力。
建議集群規模小於300時,使用默認值3秒,在此基礎上,集群規模每增加100台,會加1秒。
b) 啟用帶外心跳(out-of-band heartbeat)
mapreduce.tasktracker.outofband.heartbeat
參數說明:主要是為了減少任務分配延遲。它與常規心跳不同,一般的心跳是一定時間間隔發送的,而帶外心跳是在任務運行結束或是失敗時發送,這樣就能在TaskTracker節點出現空閑資源的時候能第一時間通知JobTracker。
3.3. 磁盤塊的配置優化
a) 作業相關的磁盤配置:mapred.local.dir
參數說明:map本地計算時所用到的目錄,建議配置在多塊硬盤上
b) 存儲相關的磁盤配置(HDFS數據存儲):dfs.data.dir
參數說明:HDFS的數據存儲目錄,建議配置在多塊硬盤上,可提高整體IO性能
例如:
<property> <name>dfs.name.dir</name> <value>/data1/hadoopdata/mapred/jt/,/data2/hadoopdata/mapred/jt/</value> </property>
c) 存儲相關的磁盤配置(HDFS元數據存儲):dfs.name.dir
參數說明:HDFS的元數據存儲目錄,建議設置多目錄,每個多目錄都可保存元數據的一個備份
注:要想提升hadoop整體IO性能,對於hadoop中用到的所有文件目錄,都需要評估它磁盤IO的負載,對於IO負載可能會高的目錄,最好都配置到多個磁盤上,以提示IO性能
3.4. RPC Handler個數和Http線程數優化
a) RPC Handler個數(mapred.job.tracker.handler.count)
參數說明:JobTracker需要並發的處理來自各個TaskTracker的RPC請求,可根據集群規模和並發數來調整RPC Handler的個數。
默認值:10
推薦值:60-70,最少要是TaskTracker個數的4%
單位:無
b) Http線程數(tasktracker.http.threads)
在Shuffle階段,Reduce Task會通過Http請求從各個TaskTracker上讀取Map Task的結果,TaskTracker是使用Jetty Server來提供服務的,這里可適量調整Jetty Server的工作線程以提高它的並發處理能力。
默認值:40
推薦值:50-80+
3.5. 選擇合適的壓縮算法
mapred.compress.map.output / Mapred.output.compress
map輸出的中間結果時需要進行壓縮的,指定壓縮方式(Mapred.compress.map.output.codec/ Mapred.output.compress.codec)。推薦使用LZO壓縮。
3.6. 啟用批量任務調度(現在新版本都默認支持了)
a) Fair Scheduler
mapred.fairscheduler.assignmultiple
b) Capacity Scheduler
3.7. 啟用預讀機制(Apache暫時沒有)
Hadoop是順序讀,所以預讀機制可以很明顯的提高HDFS的讀性能。
HDFS預讀:
dfs.datanode.readahead :true
dfs.datanode.readahead.bytes :4MB
shuffle預讀:
mapred.tasktracker.shuffle.fadvise : true
mapred.tasktracker.shuffle.readahead.bytes : 4MB
3.8.HDFS相關參數優化
1) dfs.replication
參數說明:hdfs文件副本數
默認值:3
推薦值:3-5(對於IO較為密集的場景可適量增大)
單位:無
2) dfs.blocksize
參數說明:
默認值:67108864(64MB)
推薦值:稍大型集群建議設為128MB(134217728)或256MB(268435456)
單位:無
3) dfs.datanode.handler.count
參數說明:DateNode上的服務線程數
默認值:10
推薦值:
單位:無
4) fs.trash.interval
參數說明:HDFS文件刪除后會移動到垃圾箱,該參數時清理垃圾箱的時間
默認值:0
推薦值:1440(1day)
單位:無
5) io.sort.factor
參數說明:當一個map task執行完之后,本地磁盤上(mapred.local.dir)有若干個spill文件,map task最后做的一件事就是執行merge sort,把這些spill文件合成一個文件(partition)。執行merge sort的時候,每次同時打開多少個spill文件由該參數決定。打開的文件越多,不一定merge sort就越快,所以要根據數據情況適當的調整。
默認值:10
推薦值:
單位:無
6) mapred.child.java.opts
參數說明:JVM堆的最大可用內存
默認值:-Xmx200m
推薦值:-Xmx1G | -Xmx4G | -Xmx8G
單位:-Xmx8589934592也行,單位不固定
7) io.sort.mb
參數說明:Map Task的輸出結果和元數據在內存中占的buffer總大小,當buffer達到一定閥值時,會啟動一個后台進程來對buffer里的內容進行排序,然后寫入本地磁盤,形成一個split小文件
默認值:100
推薦值:200 | 800
單位:兆
8) io.sort.spill.percent
參數說明:即io.sort.mb中所說的閥值
默認值:0.8
推薦值:0.8
單位:無
9) io.sort.record
參數說明:io.sort.mb中分類給元數據的空間占比
默認值:0.05
推薦值:0.05
單位:無
10) Mapred.reduce.parallel
參數說明:Reduce shuffle階段copier線程數。默認是5,對於較大集群,可調整為16~25
默認值:5
推薦值:16~25
單位:無
4.系統實現角度調優
https://www.xiaohui.org/archives/944.html
主要針對HDFS進行優化,HDFS性能低下的兩個原因:調度延遲和可移植性
4.1. 調度延遲
關於調度延遲主要是發生在兩個階段:
a) tasktracker上出現空余的slot到該tasktracker接收到新的task;
b) tasktracker獲取到了新的Task后,到連接上了datanode,並且可以讀寫數據。
之所以說這兩個階段不夠高效,因為一個分布式計算系統需要解決的是計算問題,如果把過多的時間花費在其它上,就顯得很不合適,例如線程等待、高負荷的數據傳輸。
下面解釋下會經歷上邊兩個階段發生的過程:
a) 當tasktracker上出現slot時,他會調用heartbeat方法向jobtracker發送心跳包(默認時間間隔是3秒,集群很大時可適量調整)來告知它,假設此時有准備需要執行的task,那么jobtracker會采用某種調度機制(調度機制很重要,是一個可以深度研究的東東)選擇一個Task,然后通過調用heartbeat方法發送心跳包告知tasktracker。在該過程中,HDFS一直處於等待狀態,這就使得資源利用率不高。
b) 這個過程中所發生的操作都是串行化的:tasktracker會連接到namenode上獲取到自己需要的數據在datanode上的存儲情況,然后再從datanode上讀數據,在該過程中,HDFS一直處於等待狀態,這就使得資源利用率不高。
若能減短hdfs的等待時間;在執行task之前就開始把數據讀到將要執行該task的tasktracker上,減少數據傳輸時間,那么將會顯得高效很多。未解決此類問題,有這樣幾種解決方案:重疊I/O和CPU階段(pipelining),task預取(task prefetching),數據預取(data prefetching)等。
4.2. 可移植性
Hadoop是Java寫的,所以可移植性相對較高。由於它屏蔽了底層文件系統,所以無法使用底層api來優化數據的讀寫。在活躍度較高的集群里(例如共享集群),大量並發讀寫會增加磁盤的隨機尋道時間,這會降低讀寫效率;在大並發寫的場景下,還會增加大量的磁盤碎片,這樣將會大大的增加了讀數據的成本,hdfs更適合文件順序讀取。
對於上述問題,可以嘗試使用下面的解決方案:
tasktracker現在的線程模型是:one thread per client,即每個client連接都是由一個線程處理的(包括接受請求、處理請求,返回結果)。那么這一塊一個拆分成兩個部分來做,一組線程來處理和client的通信(Client Threads),一組用於數據的讀寫(Disk Threads)。
想要解決上述兩個問題,暫時沒有十全十美的辦法,只能盡可能的權衡保證調度延遲相對較低+可移植性相對較高。
4.3. 優化策略:Prefetching與preshuffling
a) Prefetching包括Block-intra prefetching和Block-inter prefetching:
Block-intra prefetching:對block內部數據處理方式進行了優化,即一邊進行計算,一邊預讀將要用到的數據。這種方式需要解決兩個難題:一個是計算和預取同步,另一個是確定合適的預取率。前者可以使用進度條(processing bar)的概念,進度條主要是記錄計算數據和預讀數據的進度,當同步被打破時發出同步失效的通知。后者是要根據實際情況來設定,可采用重復試驗的方法來確定。
Block-inter prefetching:在block層面上預讀數據,在某個Task正在處理數據塊A1的時候,預測器能預測接下來將要讀取的數據塊A2、A3、A4,然后把數據塊A2、A3、A4預讀到Task所在的rack上。
b) preshuffling
數據被map task處理之前,由預測器判斷每條記錄將要被哪個reduce task處理,將這些數據交給靠近reduce task的map task來處理。
參考資料:
cloudera官方文檔
http://blog.cloudera.com/blog/2009/12/7-tips-for-improving-mapreduce-performance/
AMD白皮書(較為實用)
http://www.admin-magazine.com/HPC/content/download/9408/73372/file/Hadoop_Tuning_Guide-Version5.pdf
國內博客(大部分內容都是AMD白皮書上的翻譯):
http://dongxicheng.org/mapreduce/hadoop-optimization-0/
http://dongxicheng.org/mapreduce/hadoop-optimization-1/
