引語node
上一篇介紹了關於Hive優化的一些基本概念,這一篇主要講hive性能優化的一些具體事項,這篇主要將對數據傾斜問題的優化,以及其餘的方面的一些優化。apache
在Hadoop當項目中,數據傾斜能夠說是損害Hadoop性能的罪魁禍首。在運行Hadoop的任務過程中,咱們可能由於業務的須要,避免不了須要按照某個字段分組,去重,進行多表鏈接等操做,在這些操做當中一旦有些使用不當,就會很容易形成數據傾斜。一樣,當一個模型設計不合理時,job數量指定過多或者分區不恰當時也很容易影響Hadoop的性能。那麼什麼是數據傾斜?怎樣避免或者處理數據傾斜問題呢?接下來就爲你們介紹具體的關於解決數據傾斜問題的具體方案。性能優化
數據傾斜就是key分佈不均勻,致使分發到不一樣的reduce上,個別reduce任務特別重,致使其餘reduce都完成,而這些個別的reduce遲遲不完成的狀況 。網絡
key分佈不均勻。jvm
map端數據傾斜,輸入文件太多且大小不一 。分佈式
reduce端數據傾斜,分區器問題。oop
業務數據自己的特徵。性能
任務長時間維持在99%(或100%),查看任務監控頁面,發現只有少許(1個或幾個)reduce子任務未完成。大數據
查看子任務,能夠看到本地讀寫數據量積累很是大,一般超過10GB能夠認定發生了數據傾斜。優化
平均記錄數超過50w且最大記錄數超過平均記錄數的4配
最長時長超過平均時長4分鐘,且最大時長超過平均時長的2倍
通常來講集羣的總體性能,是由執行任務時間最長的那個節點決定的。因此,有效地解決數據傾斜問題,就能有效地提升整個集羣的性能。接下來咱們來看一下具體的解決方法吧。
有時join超時是由於某些key對應的數據太多,而相同key對應的數據都會發送到相同的reducer上,從而致使內存不夠。此時咱們應該仔細分析這些異常的key,不少狀況下,這些key對應的數據是異常數據,咱們須要在SQL語句中進行過濾。同時當有篩選條件時,應該先按照條件進行過濾,而後在進行join,這樣能夠減小數據量。
緣由:Hive在進行join時是以左邊的表爲準的,在join左邊的表的數據會首先讀入內存,若是左邊的表key比較集中,而表的數據量又比較大,這樣就會致使加入內存的數據過大,最終就會出現嚴重的數據傾斜。相反若是左邊的表,key相對分散,那麼讀入內存的數據會比較小,join任務執行會比較快,就不會出現數據傾斜的現象。
解決思路:
將key相對分散,而且將數據量小的表放在join的左邊,這樣能夠有效減小內存溢出錯誤發生的概率。
使用map join讓小的維度表先進內存。使用map join,會將其中作鏈接的小表(全量數據)分發到全部 MapTask 端進行 Join,從 而避免reduceTask,前提要求是內存足以裝下該全量數據。
緣由:作count distinct時,該字段存在大量值爲NULL或空的記錄。
思路:count distinct時,將值爲空的狀況單獨處理,若是是計算count distinct,能夠不用處理,直接過濾,在最後結果中加1。 若是還有其餘計算,須要進行group by,能夠先將值爲空的記錄單獨處理,再和其餘計算結果進行union。
同步執行hive的多個階段,hive在執行過程,將一個查詢轉化成一個或者多個階段。某個特定的job可能包含衆多的階段,而這些階段可能並不是徹底相互依賴的,也就是說能夠並行執行的,這樣可能使得整個job的執行時間縮短。hive執行開啓:set hive.exec.parallel=true
Hive 在集羣上查詢時,默認是在集羣上N臺機器上運行, 須要多個機器進行協調運行,這個方式很好地解決了大數據量的查詢問題。可是當 Hive 查詢處理的數據量比較小時,其實沒有必要啓動分佈式模式去執行,由於以分佈式方式執行就涉及到跨網絡傳輸、多節點協調 等,而且消耗資源。這個時間能夠只使用本地模式來執行 mapreduce job,只在一臺機器上執行,速度會很快。啓動本地模式能夠經過配置參數來達到這個目的:
參數名 | 默認值 | 做用 |
---|---|---|
set hive.exec.mode.local.auto | false | 是否讓hive在本地運行 |
hive.exec.mode.local.auto.input.files.max | 4 | 是否啓用本地模式的task的最大個數 |
hive.exec.mode.local.auto.inputbytes.max | 128M | 是否啓動本地模式最大文件輸入大小 |
參數說明:
set hive.exec.mode.local.auto=true 開啓本地mr,只是打開 hive 自動判斷是否啓動本地模式的開關,也就是打開這個參數並不能保證啓動本地模式,是否啓動還要取決於 map 任務數量。
set hive.exec.mode.local.auto.input.files.max 設置local mr的最大輸入文件個數,當輸入文件個數小於這個值時採用local mr的方式,默認爲4。
hive.exec.mode.local.auto.inputbytes.max 當指定大小時,纔會啓動本地模式,不指定則默認不啓動。 若是當輸入文件大小小於此閾值時能夠自動在本地模式運行,默認是 128兆。
Hive中提供有嚴格模式,爲了防止一些查詢。出現很差的影響。例如笛卡兒積,在嚴格模式下是不能運行的。配置以下:
<property>
<name>hive.mapred.mode</name>
<value>strict</value>
</property>
說明
默認值爲:非嚴格模式 nonstrict
開啓嚴格模式: strict
開啓了嚴格模式,會對查詢語句進行一些限制:
1 對於分區表: 必須存在where語句對分區表中分區字段進行條件過濾,不然,不容許執行該查詢。
2 對於使用order by的語句必須使用limit 進行限定,因爲order by 以後全部的數據都會被分到一個reduce中那這樣reduce操做的數據量太多了,可能時間過長卡死。因此爲了防止reduce時間過長,在order by的時候必須給定 limit 減小redue處理的數據量。
3 限制了笛卡兒積的查詢,主要在多表join中會出現。笛卡兒積的出現會形成性能極大的消耗。
在Hadoop中,做業完成時間取決於最慢的任務完成時間。一個做業由若干個Map任務和Reduce任務構成。因集羣中的資源分配不均等、硬件老化、軟件Bug等,會致使某個任務運行的時間快或者某個任務運行的時間慢,或者某個任務在運行的時候直接卡死了。;爲了防止某些任務,在運行過程當中,拖慢了整個MR任務的進度。在運行慢的任務節點上開啓相同的任務,若是時間比原來的任務運行的快則直接輸出推測運行的任務 。
典型案例:系統中有99%的Map任務都完成了,只有少數幾個Map總是進度很慢,完不成,怎麼辦?
推測執行機制
發現拖後腿的任務,好比某個任務運行速度遠慢於任務平均速度。爲拖後腿任務啓動一個備份任務,同時運行。誰先運行完,則採用誰的結果。
執行推測任務的前提條件
(1)每一個task只能有一個備份任務;
(2)當前job已完成的task必須不小於0.05(5%)
(3)開啓推測執行參數設置。Hadoop2.7.2 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> mapred.map.tasks.speculative.execution boolean true 若是任務運行變慢,該屬性決定了是否要啓動一個map任務的另一個實力 mapred.reduce.tasks.speculative.execution boolean true 若是任務運行變慢,該屬性決定這是否須要啓動一個reduce任務
Hive中提供的能夠查看Hql語句的執行計劃,在執行計劃中會生成抽象語法樹,在語法樹中會顯示HQL語句之間的依賴關係以及執行過程。經過這些執行的過程和依賴能夠對HQL語句進行優化
正常狀況下,MapReduce啓動的JVM在完成一個task以後就退出了,可是若是任務花費時間很短,又要屢次啓動JVM的狀況下(好比對很大數據量進行計數操做),JVM的啓動時間就會變成一個比較大的overhead。在這種狀況下,可使用jvm重用的參數:set Mapred.Job.reuse.jvm.num.tasks = 5; 。其做用是讓一個jvm運行屢次任務以後再退出,節約JVM的啓動時間。
大量的小文件致使文件數目過多,例如當一個文件是130MB的時候,Hadoop會將這個文件分紅2個默認塊,一個是128MB剩餘的分一個2MB另外分一個,這樣就會給HDFS帶來壓力,對hive處理的效率影響比較大,對於小文件問題有兩種處理方法。
設置hive參數,將額外啓動一個MR Job打包小文件
hive.merge.mapfiles=true(默認值爲真) 是否合併Map輸出文件 hive.merge.mapredfiles=false(默認值爲假)是否合併Reduce 端輸出文件 hive.merge.size.per.task=256*1000*1000(默認值爲 256000000)合併文件的大小
使用Combinefileinputformat,將多個小文件打包做爲一個總體的inputsplit,減小map任務數。前面三個參數肯定合併文件塊的大小,大於文件塊大小128m的,按照128m來分隔,小於128m,大於100m的,按照100m來分隔,把那些小於100m的(包括小文件和分隔大文件剩下的)進行合併
set mapred.max.split.size=100000000; set mapred.min.split.size.per.node=100000000 set Mapred.min.split.size.per.rack=100000000 set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
建立表時,儘可能使用 orc、parquet 這些列式存儲格式,由於列式存儲的表,每一列的數據在物理上是存儲在一塊兒的,Hive查詢時會只遍歷須要列數據,大大減小處理的數據量。同時因爲parquet文件是以二進制存儲的,所以能夠減小文件的序列化和法序列化的操做,從而節省時間。
Hive 最終是轉爲 MapReduce 程序來執行的,而MapReduce 的性能瓶頸在於網絡 IO 和 磁盤 IO,要解決性能瓶頸,最主要的是減小數據量,對數據進行壓縮是個好的方式。壓縮 雖然是減小了數據量,可是壓縮過程要消耗CPU的,可是在Hadoop中, 每每性能瓶頸不在於CPU,CPU壓力並不大,因此壓縮充分利用了比較空閒的 CPU。
對於一個job可以完成的任務,儘可能不要使用兩個job來完成,從而減小job初始化所須要的時間。
熟練使用SQL提升查詢,寫出高效率的查詢語句。