文章目錄
一、Hadoop數據壓縮
1.1 概述
壓縮技術能夠有效減少底層存儲系統(HDFS
)讀寫字節數。壓縮提供了網絡帶寬和磁盤空間的效率。在運行MR
程序時,IO
操作、網絡數據傳輸、Shuffle
和Merge
要花大量的時間,尤其是數據規模很大和工作負載密集的情況下,因此,使用數據壓縮顯得非常重要。
鑑於磁盤IO
和網絡帶寬是Hadoop
的寶貴資源,數據壓縮對於節省資源、最小化磁盤IO
和網絡傳輸資源非常有幫助。可以在任意MapReduce
階段啓動壓縮。不過,儘管壓縮和解壓操作的CPU
開銷不高,其性能的提升和資源的節省並非沒有代價。
1.2 壓縮策略和原則
壓縮是提供Hadoop
運行效率的一種優化策略。通過對Mapper
、Reducer
運行過程中的數據進行壓縮,以減少磁盤IO
,提供MR
程序運行速度。
注意: 採用壓縮技術減少了磁盤IO
,但同時增加了CPU
運算負擔。所以,壓縮特性運用得當能提高性能,但運用不當也可能降低性能。
壓縮基本原則:
- 運算密集的
job
,少用壓縮 IO
密集的job
,多用壓縮
1.3 MR支持的壓縮編碼
壓縮格式 | hadoop自帶? | 算法 | 文件擴展名 | 是否可切分 | 換成壓縮格式後,原來的程序是否需要修改 |
---|---|---|---|---|---|
DEFLATE | 是,直接使用 | DEFLATE | .deflate | 否 | 和文本處理一樣,不需要修改 |
Gzip | 是,直接使用 | DEFLATE | .gz | 否 | 和文本處理一樣,不需要修改 |
bzip2 | 是,直接使用 | bzip2 | .bz2 | 是 | 和文本處理一樣,不需要修改 |
LZO | 否,需要安裝 | LZO | .lzo | 是 | 和文本處理一樣,不需要修改 |
Snappy | 否,需要安裝 | Snappy | .snappy | 否 | 和文本處理一樣,不需要修改 |
爲了支持多種壓縮/解壓縮算法,Hadoop
引入了編碼/解碼器,如下表所示:
壓縮格式 | 對應的編碼/解碼器 |
---|---|
DEFLATE | org.apache.hadoop.io.compress.DefaultCodec |
gzip | org.apache.hadoop.io.compress.GzipCodec |
bzip2 | org.apache.hadoop.io.compress.BZip2Codec |
LZO | com.hadoop.compression.lzo.LzopCodec |
Snappy | org.apache.hadoop.io.compress.SnappyCodec |
壓縮性能的比較:
壓縮算法 | 原始文件大小 | 壓縮文件大小 | 壓縮速度 | 解壓速度 |
---|---|---|---|---|
gzip | 8.3GB | 1.8GB | 2.9GB | 58MB/s |
bzip2 | 8.3GB | 1.1GB | 2.4MB/s | 9.5MB/s |
LZO | 8.3GB | 2.9GB | 49.3MB/s | 74.6MB/s |
1.4 壓縮方式選擇
①Gzip壓縮
優點 :壓縮率比較高,而且壓縮/解壓速度也比較快; Hadoop
本身支持,在應用中處理Gzip
格式的文件就和直接處理文本一樣;大部分Linux系統都自帶Gzip
命令,使用方便
缺點:不支持split
應用場景:當每個文件壓縮後130M以內的(一個塊大小以內的),都可以考慮用Gzip
壓縮格式,例如將一天或者一個小時的日子壓縮成一個Gzip
文件
②Bzip2壓縮
優點:支持Split
,具有很高的壓縮率,比Gzip
壓縮率都高; Hadoop
本身自帶,使用方便
缺點:壓縮/解壓速度慢
應用場景:適合對速度要求不高,但需要較高的壓縮率的時候;或者輸出之後的數據比較大,處理之後的數據需要壓縮存檔減少磁盤空間並且以後數據用得比較少的情況;或者對單個很大的文本文件想壓縮減少存儲空間,同時又需要支持Split
,而且兼容之前的應用程序的情況
③Lzo壓縮
優點:壓縮/解壓速度也比較快,合理的壓縮率;支持Split
, 是Hadoop
中最流行的壓縮格式;可以在Linux
系統下安裝lzop
命令,使用方便。
缺點:壓縮率比Gzip
要低一些; Hadoop
本身不支持,需要安裝;在應用中對Lzo
格式的文件需要做一些特殊處理(爲了支持Split
需要建索引,還需要指定InputFormat
爲Lzo
格式)。
應用場景:一個很大的文本文件,壓縮之後還大於200M以上的可以考慮,而且單個文件越大,Lzo
優點越越明顯。
④Snappy壓縮
優點:高速壓縮速度和合理的壓縮率
缺點:不支持Split
;壓縮率比Gzip
要低; Hadoop
本身不支持, 需要安裝
應用場景:當MapReduce
作業的Map
輸出的數據比較大的時候,作爲Map
到Reduce
的中間數據的壓縮格式;或者作爲一個MapReduce
作業的輸出和另外一個MapReduce
作業的輸入
1.5 壓縮位置選擇
1.6 壓縮參數配置
要在Hadoop
中啓用壓縮,可以配置如下參數:
參數 | 默認值 | 階段 | 建議 |
---|---|---|---|
io.compression.codecs(在core-site.xml中配置) | org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.BZip2Codec |
輸入壓縮 | Hadoop使用文件擴展名判斷是否支持某種編解碼器 |
mapreduce.map.output.compress(在mapred-site.xml中配置) | false | mapper輸出 | 這個參數設爲true啓用壓縮 |
mapreduce.map.output.compress.codec(在mapred-site.xml中配置) | org.apache.hadoop.io.compress.DefaultCodec | mapper輸出 | 這個參數設爲true啓用壓縮 |
mapreduce.output.fileoutputformat.compress(在mapred-site.xml中配置 | false | reducer輸出 | 這個參數設爲true啓用壓縮 |
mapreduce.output.fileoutputformat.compress.codec(在mapred-site.xml中配置) | org.apache.hadoop.io.compress. DefaultCodec | reducer輸出 | 使用標準工具或者編解碼器,如gzip和bzip2 |
mapreduce.output.fileoutputformat.compress.type(在mapred-site.xml中配置) | RECORD | reducer輸出 | SequenceFile輸出使用的壓縮類型:NONE和BLOCK |
1.7 壓縮實操案例
在驅動類Driver
進行配置設置(具體參數見上):
public class WordCountDriver {
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
// 開啓map端輸出壓縮
configuration.setBoolean("mapreduce.map.output.compress", true);
// 設置map端輸出壓縮方式
configuration.setClass("mapreduce.map.output.compress.codec", BZip2Codec.class,
CompressionCodec.class);
Job job = Job.getInstance(configuration);
......
}
}
二、Yarn資源調度
Yarn
架構見:Hadoop概述
2.1 Yarn的工作機制
MR
程序提交到客戶端所在的節點YarnRunner
向ResourceManager
申請一個Application
,ResourceManager
將應用程序的資源路徑返回給YarnRunner
,然後將運行所需資源提交到HDFS
上- 程序提交完畢後,申請運行
mrAppMaster
ResourceManager
將用戶的請求初始化成一個Task
- 其中一個
NodeManager
領取到Task
任務,該NodeManager
創建容器Container
併產生MRAppmaster
Container
從HDFS
上拷貝資源到本地,MRAppmaster
向ResourceManager
申請運行MapTask
資源RM
將運行MapTask
任務分配給另外兩個NodeManager
,另兩個NodeManager
分別領取任務並創建容器MR
向兩個接收到任務的NodeManager
發送程序啓動腳本,這兩個NodeManager
分別啓動MapTask
,MapTask
對數據分區排序MrAppMaster
等待所有MapTask
運行完畢後,向RM
申請容器,運行ReduceTask
ReduceTask
向MapTask
獲取相應分區的數據- 程序運行完畢後,
MR
會向RM
申請註銷自己
2.2 資源調度器
目前,Hadoop
作業調度器主要有三種:FIFO
、Capacity Scheduler
和Fair Scheduler
。Hadoop2.7.2
默認的資源調度器是Capacity Scheduler
。
具體設置詳見:yarn-default.xml
文件:
<property>
<description>The class to use as the resource scheduler.</description>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
</property>
- 先進先出調度器(FIFO)
- 容量調度器(Capacity Scheduler)
- 公平調度器(Fair Scheduler)
2.3 任務的推測執行
一個作業由若干個Map
任務和Reduce
任務構成。因硬件老化、軟件Bug
等,某些任務可能運行非常慢。
思考:系統中有99%的Map
任務都完成了,只有少數幾個Map
老是進度很慢,完不成,怎麼辦?
推測執行機制: 發現拖後腿的任務,比如某個任務運行速度遠慢於任務平均速度。爲拖後腿任務啓動一個備份任務,同時運行。誰先運行完,則採用誰的結果。
執行推測任務的前提條件:
- 每個
Task
只能有一個備份任務 - 當前
Job
已完成的Task
必須不小於5% - 開啓推測執行參數設置。
mapred-site.xml
文件中默認是打開的
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some map tasks may be executed in parallel.</description>
</property>
<property>
<name>mapreduce.reduce.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some reduce tasks may be executed in parallel.</description>
</property>
不能啓用推測執行機制情況:
- 任務間存在嚴重的負載傾斜
- 特殊任務,比如任務向數據庫中寫數據
三、企業優化
3.1 MapReduce 跑的慢的原因
①計算機性能‘
CPU、內存、磁盤健康、網絡
②I/O操作優化
- 數據傾斜
MapReduce
數設置不合理Map
運行時間太長,導致Reduce
等待過久- 小文件過多
- 大量的不可分塊的超大文件
Spil
次數過多Merge
次數過多等
3.2 MapReduce優化方法
MapReduce
優化方法主要從六個方面考慮:數據輸入、Map
階段、Reduce
階段、IO
傳輸、數據傾斜問題和常用的調優參數
①數據輸入
合併小文件:在執行MR
任務前將小文件進行合併,大量的小文件會產生大量的Map
任務,增大Map
任務裝載次數,而任務的裝載比較耗時,從而導致MR
運行較慢。
採用Combine TextInputFormat
來作爲輸入,解決輸入端大量小文件場景
②Map階段
- 減少溢寫
Spill
次數:通過調整io.sort.mb
及sort.spill,percent
參數值,增大觸發Spill
的內存上限,減少Spill
次數,從而減少磁盤IO
- 減少合併
Merge
次數:通過調整io.sort.factor
參數,增大Merge
的文件數目,減少Merge
的次數,從而縮短MR
的處理時間 - 在
Map
之後,不影響業務邏輯的前提下,先進行Combiner
處理,減少IO
③Reduce階段
- 合理設置
Map
和Reduce
數:兩個都不能設置太少,也不能設置太多。太少,會導致Task
等待,延長處理時間;太多,會導致Map
、Reduce
任務間競爭資源,造成處理超時等錯誤。 - 設置
Map
、Reduce
共存:調整slowstart.completedmaps
參數,使Map
運行到一定程度後,Reduce
也開始運行,減少Reduce
的等待時間。 - 規避使用
Reduce
:因爲Reduce
在用於連接數據集的時候將會產生大量的網絡消耗。 - 合理設置
Reduce
端的Buffer
:默認情況下,數據達到一個閾值的時候,Buffer
中的數據就會寫入磁盤,然後Reduce
會從磁盤中獲得所有的數據。也就是說,Buffer
和Reduce
是沒有直接關聯的,中間多次寫磁盤->
讀磁盤的過程,既然有這個弊端,那麼就可以通過參數來配置,使得Buffer
中的一部分數據可以直接輸送到Reduce
,從而減少IO
開銷:mapreduce.reduce input. buffer. percent
,默認爲0.0。 當值大於0的時候,會保留指定比例的內存讀Buffer
中的數據直接拿給Reduce
使用。這樣一來,設置Buffer
需要內存,讀取數據需要內存,Reduce
計算也要內存,所以要根據作業的運行情況進行調整。
④IO傳輸
- 採用數據壓縮的方式,減少網絡
IO
的的時間,安裝Snappy
和LZO
壓縮編碼器。 - 使用
SequenceFile
二進制文件。
⑤數據傾斜問題
數據傾斜現象:
- 數據頻率傾斜:某一個區域的數據量要遠遠大於其他區域。
- 數據大小傾斜:部分記錄的大小遠遠大於平均值。
減少數據傾斜的方法:
- 抽樣和範圍分區:可以通過對原始數據進行抽樣得到的結果集來預設分區邊界值。
- 自定義分區: 基於輸出鍵的背景知識進行自定義分區。例如,如果
Map
輸出鍵的單詞來源於一本書。且其中某幾個專業詞彙較多。那麼就可以自定義分區將這這些專業詞彙發送給固定的一部分Reduce
實例, 而將其他的都發送給剩餘的Reduce
實例。 - Combine: 使用
Combine
可以大量地減小數據傾斜。在可能的情況下,Combine
的目的就是聚合並精簡數據。 - 採用Map Join,儘量避免Reduce Join
⑥常用的調優參數
資源相關參數(配置在mapred-default.xml
):
配置參數 | 參數說明 |
---|---|
mapreduce.map.memory.mb | 一個MapTask可使用的資源上限(單位:MB),默認爲1024。如果MapTask實際使用的資源量超過該值,則會被強制殺死 |
mapreduce.reduce.memory.mb | 一個ReduceTask可使用的資源上限(單位:MB),默認爲1024。如果ReduceTask實際使用的資源量超過該值,則會被強制殺死 |
mapreduce.map.cpu.vcores | 每個MapTask可使用的最多cpu core數目,默認值: 1 |
mapreduce.reduce.cpu.vcores | 每個ReduceTask可使用的最多cpu core數目,默認值: 1 |
mapreduce.reduce.shuffle.parallelcopies | 每個Reduce去Map中取數據的並行數。默認值是5 |
mapreduce.reduce.shuffle.merge.percent | Buffer中的數據達到多少比例開始寫入磁盤。默認值0.66 |
mapreduce.reduce.shuffle.input.buffer.percent | Buffer大小佔Reduce可用內存的比例。默認值0.7 |
mapreduce.reduce.input.buffer.percent | 指定多少比例的內存用來存放Buffer中的數據,默認值是0.0 |
YARN配置(yarn-default.xml
):
配置參數 | 配置參數 |
---|---|
yarn.scheduler.minimum-allocation-mb | 給應用程序Container分配的最小內存,默認值:1024 |
yarn.scheduler.maximum-allocation-mb | 給應用程序Container分配的最大內存,默認值:8192 |
yarn.scheduler.maximum-allocation-mb | 每個Container申請的最小CPU核數,默認值:1 |
yarn.scheduler.maximum-allocation-vcores | 每個Container申請的最大CPU核數,默認值:32 |
yarn.nodemanager.resource.memory-mb | 給Containers分配的最大物理內存,默認值:8192 |
Shuffle性能優化(mapred-default.xml
):
配置參數 | 參數說明 |
---|---|
mapreduce.task.io.sort.mb | Shuffle的環形緩衝區大小,默認100m |
mapreduce.map.sort.spill.percent | 環形緩衝區溢出的閾值,默認80% |
容錯相關參數(MapReduce
性能優化):
配置參數 | 參數說明 |
---|---|
mapreduce.map.maxattempts | 每個MapTask最大重試次數,一旦重試參數超過該值,則認爲MapTask運行失敗,默認值:4 |
mapreduce.reduce.maxattempts | 每個ReduceTask最大重試次數,一旦重試參數超過該值,則認爲ReduceTask運行失敗,默認值:4 |
mapreduce.task.timeout | Task超時時間,經常需要設置的一個參數,該參數表達的意思爲:如果一個Task在一定時間內沒有任何進入,即不會讀取新的數據,也沒有輸出數據,則認爲該Task處於Block狀態,可能是卡住了,也許永遠會卡住,爲了防止因爲用戶程序永遠Block住不退出,則強制設置了一個該超時時間(單位毫秒),默認是600000。如果你的程序對每條輸入數據的處理時間過長(比如會訪問數據庫,通過網絡拉取數據等),建議將該參數調大,該參數過小常出現的錯誤提示是“AttemptID:attempt_14267829456721_123456_m_000224_0 Timed out after 300 secsContainer killed by the ApplicationMaster.”。 |
3.3 HDFS小文件優化方法
HDFS
上每個文件都要在NameNode
上建立一個索引,這個索引的大小約爲150byte
,這樣當小文件比較多的時候,就會產生很多的索引文件,一方面會大量佔用NameNode
的內存空間,另一方面就是索引文件過大使得索引速度變慢。
- Hadoop Archive
是一個高效地將小文件放入HDFS
塊中的文件存檔工具,它能夠將多個小文件打包成-一個HAR文件,這樣就減少了NameNode的內存使用。 - Sequence File
Sequence File
由一系列的二進制key/value
組成,如果key
爲文件名,value
爲文件內容,則可以將大批小文件合併成一個大文件。 - CombineFilelnputFormat
CombineFileInputFormat
是一種新的InputFormat
, 用於將多個文件合併成一個單獨的Split
,另外,它會考慮數據的存儲位置。 - 開啓JVM重用.
對於大量小文件Job
,可以開啓JVM
重用會減少45%運行時間。
JVM
重用原理: 一個Map
運行在一個JVM
上,開啓重用的話,該Map
在JVM
上運行完畢後,JVM
繼續運行其他Map
。
具體設置:mapreduce.job.jvm.numtasks
值在10-20之間。