本文為《大資料分析師入門課程》系列的第6篇,主要講解大資料分析師在工作中需要用到的HIVE進階知識,主要包括:
視窗函式資料傾斜效能調優explain替換引擎那,就直接開講了。
視窗函式
要講HIVE進階,視窗函式不得不提,作者之前的文章《Hive視窗函式進階指南》已經很詳細地講解了這部分內容,為了省去大家點連結跳來跳去的麻煩,下面將其核心內容摘錄出來,如下所示。
視窗函式也稱為OLAP(OnlineAnalytical Processing)函式,是對一組值進行操作,不需要使用Group by子句對資料進行分組,還能在同一行返回原來行的列和使用聚合函式得到的聚合列。
SQL語法<視窗函式>() OVER ( [PARTITIONBY <列清單>] [ORDER BY<排序用清單列>] [ASC/DESC] (ROWS |RANGE) <範圍條件>)
如上程式碼所示,視窗函式的語法分為四個部分:
函式子句:指明具體操作,如sum-求和,first_value-取第一個值;
partition by子句:指明分割槽欄位,如果沒有,則將所有資料作為一個分割槽;
order by子句:指明瞭每個分割槽排序的欄位和方式,也是可選的,沒有就是按照表中的預設順序;
視窗子句:指明相對當前記錄的計算範圍,可以向上(preceding),可以向下(following),也可以使用between指明,上下邊界的值,沒有的話預設為當前分割槽。有些場景比較特殊,後文會講到這種場景。
分類按照視窗函式的功能分為:計算、取值、排序、序列四種
使用場景結合實際場景看看怎麼用視窗函式來解決問題。下面針對不同的使用場景,將視窗函式的使用呈現給大家。
所有例子的資料均來自下圖這張表。
用於輔助計算
主要的用法是在原有表的基礎上,增加一列聚合後的值,輔以後續的計算。
例如:統計出不同產品型別售價最高的產品。
具體程式碼如下:
--使用視窗函式maxselect a.product_type,a.product_namefrom( selectproduct_name,product_type,sale_price ,max(sale_price) over ( partitionby product_type ) as max_sale_price --增加一列為聚合後的最高售價 fromproduct) a where a.sale_price = a.max_sale_price; --保留與最高售價相同的記錄數
執行結果:
累積計算
標準聚合函式作為視窗函式配合order by使用,可以實現累積計算。
例如:sum視窗函式配合order by,可以實現累積和。
具體程式碼如下:
SELECT product_id,product_name ,product_type,sale_price ,SUM(sale_price) OVER ( ORDER BYproduct_id ) AS current_sumFROM product;
執行結果:
相應的AVG視窗函式配合order by,可以實現累積平均,max可以實現累積最大值,min可以實現累積最小值,count則可以實現累積計數。
注意,只有計算類的視窗函式可以實現累積計算。
標準聚合函式作為視窗函式使用的時候,在指明order by的情況下,如果沒有Window子句,則Window子句預設為:RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(上邊界不限制,下邊界到當前行)。
移動計算
移動計算是在分割槽和排序的基礎上,對計算範圍進一步做出限定。
例如:按照產品ID排序,將最近3條的銷售價格進行彙總平均。
具體程式碼如下:
SELECT product_id,product_name ,sale_price ,AVG(sale_price) over ( ORDER BY product_id rows 2 preceding ) AS moving_avgFROM product;
rows 2 preceding的意思就是“截止到之前2行”。也就是將作為彙總物件的記錄限定為如下的最靠近的3行。
執行結果如下:
取一欄位值
取值的視窗函式有:first_value/last_value、lag/lead。
first_value(欄位名)-取出分割槽中的第一條記錄的任意一個欄位的值,可以排序也可以不排序,此處也可以進一步指明Window子句。
lag(欄位名,N,預設值)-取出當前行之上的第N條記錄的任意一個欄位的值,這裡的N和預設值都是可選的,預設N為1,預設值為null。
使用first_value取出每個分類下的最貴的產品,如下:
select distinct product_type,first_value(product_name) over (partition by product_typeorder by sale_price desc) as max_price_productfrom product
執行結果如下:
排序
排序對應的四個視窗函式為:rank、dense_rank、row_number、ntitle
rank:計算排序時,如果存在相同位次的記錄,則會跳過之後的位次。
e.g. 有三條記錄排在第1位時:1位、1位、1位、4位......
dense_rank:計算排序時,即使存在相同位次的記錄,也不會跳過之後的位次。
e.g. 有三條記錄排在第1位時:1位、1位、1位、2位......
row_number:賦予唯一的連續位次。
e.g. 有三條記錄排在第1位時:1位、2位、3位、4位...
ntitle:用於將分組資料按照順序切分成n片,返回當前切片值
e.g. 對於一組數字(1,2,3,4,5,6),ntile(2)切片後為(1,1,1,2,2,2)
1)統計所有產品的售價排名
具體程式碼如下:
SELECT product_name,product_type ,sale_price, RANK () OVER ( ORDER BY sale_price ) AS rankingFROM product;
執行結果如下:
2)統計各產品型別下各產品的售價排名
具體程式碼如下:
SELECT product_name,product_type ,sale_price, RANK () OVER ( PARTITION BY product_type ORDER BY sale_price ) AS rankingFROM product;
執行結果如下:
對比一下dense_rank、row_number、ntile
具體程式碼如下:
SELECT product_name,product_type,sale_price, RANK ()OVER (ORDER BY sale_price) AS ranking, DENSE_RANK () OVER (ORDER BY sale_price) AS dense_ranking, ROW_NUMBER () OVER (ORDER BY sale_price) AS row_num, ntile(3)OVER (ORDER BY sale_price) as nt1, ntile(30)OVER (ORDER BY sale_price) as nt2 --切片大於總記錄數FROM product;
執行結果如下:
從結果可以發現,當ntile(30)中的切片大於了總記錄數時,切片的值為記錄的序號。
序列
序列中的兩個視窗函式cume_dist和percent_rank,透過例項來看看它們是怎麼使用的。
1)統計小於等於當前售價的產品數,所佔總產品數的比例
具體程式碼如下:
SELECT product_type,product_name,sale_price,CUME_DIST() OVER(ORDER BY sale_price) AS rn1,CUME_DIST() OVER( PARTITIONBY product_type ORDER BYsale_price) AS rn2 FROM product;
執行結果如下:
rn1: 沒有partition,所有資料均為1組,總行數為8,
第一行:小於等於100的行數為1,因此,1/8=0.125
第二行:小於等於500的行數為3,因此,3/8=0.375
rn2: 按照產品型別分組,product_type=廚房用品的行數為4,
第三行:小於等於500的行數為1,因此,1/4=0.25
2)統計每個產品的百分比排序
當前行的RANK值-1/分組內總行數-1
具體程式碼如下:
SELECT product_type,product_name,sale_price,percent_rank() OVER (ORDER BY sale_price) AS rn1,percent_rank() OVER ( PARTITIONBY product_type ORDER BYsale_price) AS rn2 FROM product;
執行結果如下:
rn1: 沒有partition,所有資料均為1組,總行數為8,
第一行:排序為1,因此,(1-1)/(8-1)= 0
第二行:排序為2,因此,(2-1)/(8-1)= 0.14
rn2: 按照產品型別分組,product_type=廚房用品的行數為4,
第三行:排序為1,因此,(1-1)/(4-1)= 0
第四行:排序為1,因此,(2-1)/(4-1)= 0.33
資料傾斜
什麼是資料傾斜資料傾斜就是資料的分佈不平衡,某些地方特別多,某些地方又特別少,導致在處理資料的時候,有些很快就處理完了,而有些又遲遲未能處理完,導致整體任務最終遲遲無法完成,這種現象就是資料傾斜。
針對mapreduce的過程來說主要表現是:任務進度長時間維持在 99%或者 100%的附近,檢視任務監控頁面,發現只有少量 reduce 子任務未完成,因為其處理的資料量和其他的 reduce 差異過大。單一 reduce 處理的記錄數和平均記錄數相差太大,通常達到好幾倍之多,最長時間遠大於平均時長。
哪些操作容易造成資料傾斜?關鍵字 |
場景 |
結果 |
join |
其中一個表較小,但是key集中 |
分發到某一個或者幾個Reduce上的資料遠高平均值 |
都是大表,但是有0值和空值過多 |
0值或者空值由一個Reduce處理 | |
不同資料型別關聯 |
型別轉換的時候會產生null值,太多的null值在一個Reduce上處理 | |
group by |
維度過小,某個值的量太大 |
處理該值的Reduce壓力大 |
count distinct |
特殊值過多 |
處理特殊值的Reduce壓力大 |
結合資料傾斜的場景,可以總結出產生資料傾斜的原因
1. key 分佈不均勻
2. 業務資料本身的特性
3. 建表考慮不周全,如partition的數量過少
4. 某些 HQL 語句本身就容易產生資料傾斜,如join
最佳化方法既然已經知道了哪些情況可能會產生資料傾斜以及產生資料傾斜的原因,那麼如何去規避資料傾斜問題呢?
下面結合具體的場景來說說
特殊值產生的資料傾斜
在日誌中,常會有欄位值丟失的問題,比如日誌中的 user_id,如果取其中的 user_id 和使用者表中的 user_id 相關聯,就會碰到資料傾斜的問題。
解決方案 1:user_id 為空的不參與關聯
select * from log a join user b on a.user_id is not null and a.user_id = b.user_idunion allselect * from log c where c.user_id is null;
解決方案 2:賦予空值新的 key 值
select * from log a left outer join user b on case when a.user_id is null thenconcat('null_',rand()) else a.user_id end = b.user_id
方法 2 比方法 1 效率更好,不但 IO 少了,而且作業數也少了。
方案 1 中,log 表 讀了兩次,job數肯定是 2,而方案 2 job數是 1。
方法 2 使本身為 null 的所有記錄不會擁擠在同一個 reduceTask 了,加上隨機字串值,會分散到了多個 reduceTask 中,由於 null 值關聯不上,處理後並不影響最終結果。
大小表關聯查詢產生資料傾斜
對於這種資料傾斜一般的做法是使用MapJoin-將其中做連線的小表(全量資料)分發到所有 MapTask 端進行 Join,從而避免了 reduceTask,前提要求是記憶體足以裝下該全量資料。
以大表 a 和小表 b 為例,所有的 maptask 節點都裝載小表 b 的所有資料,然後大表 a 的 一個數據塊資料比如說是 a1 去跟 b 全量資料做連結,就省去了 reduce 做彙總的過程。
所以相對來說,在記憶體允許的條件下使用 map join 比直接使用 MapReduce 效率還高些, 當然這隻限於做 join 查詢的時候。
其實對於多表join,是否開啟MapJoin,可以進行設定的,具體引數如下:
set hive.auto.convert.join=true; //設定 MapJoin 最佳化自動開啟set hive.mapjoin.smalltable.filesize=25000000 //設定小表不超過多大時開啟 mapjoin 最佳化
也可以人為指定開啟MapJoin,請看下面的程式碼:
select /* +mapjoin(b) */ a.id aid, name, age from a join b on a.id = b.id;
因為加了/* +mapjoin(b) */這一段程式碼,執行的時候就會將b表讀入記憶體中,但是要求b表必須是小表,資料量不能太大。
效能調優
由於Hive的執行依賴於底層的MapReduce作業,因此對MapReduce作業的調整最佳化是提高Hive效能的基礎。所以可以從以下幾個方面進行一系列的調優,來大幅度地提高Hive的查詢效能。
啟用壓縮在Hive中對中間資料或最終資料做壓縮,是提高資料吞吐量和效能的一種手段。對資料做壓縮,可以大量減少磁碟的儲存空間,比如基於文字的資料檔案,可以將檔案壓縮40%或更多。同時壓縮後的檔案在網路間傳輸I/O也會大大減少;當然壓縮和解壓縮也會帶來額外的CPU開銷,但是卻可以節省更多的I/O和使用更少的記憶體開銷。
常見的壓縮方式有:GZIP、BZIP2、LZO、Snappy等。
那這麼多種壓縮方式,使用哪一種呢?可以透過壓縮比、壓縮速度、是否可分割來決定選哪一種,壓縮比和壓縮速度都好理解,是否可分割是指壓縮後的檔案是否可以再分割:可以分割的格式允許單一檔案由多個Mapper程式同時讀取,可以做到更好的並行化。
下表是各種壓縮方式的對比:
壓縮方式 |
壓縮比 |
壓縮速度 |
是否可分割 |
GZIP |
中 |
中 |
否 |
BZIP2 |
小 |
慢 |
是 |
LZO |
大 |
快 |
是 |
SNAPPY |
大 |
快 |
是 |
如何設定
前文有提到在Hive中對中間資料或最終資料做壓縮,那分別來看看如何設定。
中間資料壓縮
set hive.exec.compress.intermediate=trueset mapred.map.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
hive.exec.compress.intermediate:預設該值為false,設定為true為啟用中間資料壓縮功能。HiveQL語句最終會被編譯成Hadoop的Mapreduce job,開啟Hive的中間資料壓縮功能,就是在MapReduce的shuffle階段對mapper產生的中間結果資料壓縮。在這個階段,優先選擇一個低CPU開銷的演算法。
mapred.map.output.compression.codec:該引數是具體的壓縮演算法實現類的配置引數,SnappyCodec是比較適合這種場景的編解碼器,該演算法會帶來很好的壓縮比和較低的CPU開銷。
最終資料壓縮
set hive.exec.compress.output=truesetmapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
hive.exec.compress.output:該引數控制最終資料壓縮的啟用與禁用,設定為true來宣告將結果檔案進行壓縮。
mapred.output.compression.codec:選擇一個合適的編解碼器,如選擇SnappyCodec。
避免全域性排序Hive中使用order by子句實現全域性排序。order by只用一個Reducer產生結果,對於大資料集,這種做法效率很低。
如果不需要全域性有序,則可以使用sort by子句,該子句為每個reducer生成一個排好序的檔案。如果需要控制一個特定資料行流向哪個reducer,可以使用distribute by子句,例如:
select id, name, salary, dept from employee distribute by dept sort by id asc, name desc;
屬於一個dept的資料會分配到同一個reducer進行處理,同一個dept的所有記錄按照id、name列排序。最終的結果集是區域性有序的。
最佳化limit操作預設時limit操作仍然會執行整個查詢,然後返回限定的行數。在有些情況下這種處理方式很浪費,因此可以透過設定下面的屬性避免此行為。
<property> <name>hive.limit.optimize.enable</name> <value>true</value></property> <property> <name>hive.limit.row.max.size</name> <value>100000</value></property><property> <name>hive.limit.optimize.limit.file</name> <value>10</value></property><property> <name>hive.limit.optimize.fetch.max</name> <value>50000</value> </property>
說明:
hive.limit.optimize.enable:是否啟用limit最佳化。當使用limit語句時,對源資料進行抽樣。
hive.limit.row.max.size:在使用limit做資料的子集查詢時保證的最小行資料量。
hive.limit.optimize.limit.file:在使用limit做資料子集查詢時,取樣的最大檔案數。
hive.limit.optimize.fetch.max:使用簡單limit資料抽樣時,允許的最大行數。
啟用並行每條HiveQL語句都被轉化成一個或多個執行階段,可能是一個MapReduce階段、取樣階段、歸併階段、限制階段等。預設時,Hive在任意時刻只能執行其中一個階段。
如果組成一個特定作業的多個執行階段是彼此獨立的,那麼它們可以並行執行,從而整個作業得以更快完成。透過設定下面的屬性啟用並行執行。
<property> <name>hive.exec.parallel</name> <value>true</value></property> <property> <name>hive.exec.parallel.thread.number</name> <value>8</value> </property>
說明:
hive.exec.parallel:是否並行執行作業。
hive.exec.parallel.thread.number:最多可以並行執行的作業數。
啟用MapReduce嚴格模式Hive提供了一個嚴格模式,可以防止使用者執行那些可能產生負面影響的查詢。透過設定下面的屬性啟用MapReduce嚴格模式。
<property> <name>hive.mapred.mode</name> <value>strict</value></property>
嚴格模式禁止3種類型的查詢:
1)對於分割槽表,where子句中不包含分割槽欄位過濾條件的查詢語句不允許執行。
2)對於使用了order by子句的查詢,要求必須使用limit子句,否則不允許執行。
3)限制笛卡爾積查詢。
控制並行Reduce任務Hive透過將查詢劃分成一個或多個MapReduce任務達到並行的目的。確定最佳的mapper個數和reducer個數取決於多個變數,例如輸入的資料量以及對這些資料執行的操作型別等。
如果有太多的mapper或reducer任務,會導致啟動、排程和執行作業過程中產生過多的開銷,而如果設定的數量太少,那麼就可能沒有充分利用好叢集內在的並行性。對於一個Hive查詢,可以設定下面的屬性來控制並行reduce任務的個數。
<property> <name>hive.exec.reducers.bytes.per.reducer</name> <value>256000000</value></property> <property> <name>hive.exec.reducers.max</name> <value>1000</value> </property>
說明:
hive.exec.reducers.bytes.per.reducer:每個reducer的位元組數,預設值為256MB。Hive是按照輸入的資料量大小來確定reducer個數的。例如,如果輸入的資料是1GB,將 使用4個reducer。
hive.exec.reducers.max:將會使用的最大reducer個數。
啟用向量化向量化特性在Hive 0.13.1版本中被首次引入。透過查詢執行向量化,使Hive從單行處理資料改為批次處理方式,具體來說是一次處理1024行而不是原來的每次只處理一行,這大大提升了指令流水線和快取的利用率,從而提高了表掃描、聚合、過濾和連線等操作的效能。可以設定下面的屬性啟用查詢執行向量化。
<property> <name>hive.vectorized.execution.enabled</name> <value>true</value></property> <property> <name>hive.vectorized.execution.reduce.enabled</name> <value>true</value> </property><property> <name>hive.vectorized.execution.reduce.groupby.enabled</name> <value>true</value></property>
說明:
hive.vectorized.execution.enabled:如果該標誌設定為true,則開啟查詢執行的向量模式,預設值為false。
hive.vectorized.execution.reduce.enabled:如果該標誌設定為true,則開啟查詢執行reduce端的向量模式,預設值為true。
hive.vectorized.execution.reduce.groupby.enabled:如果該標誌設定為true,則開啟查詢執行reduce端groupby操作的向量模式,預設值為true。
啟用基於成本的最佳化器Hive 0.14版本開始提供基於成本最佳化器(CBO)特性。使用過Oracle資料庫的讀者對CBO一定不會陌生。與Oracle類似,Hive的CBO也可以根據查詢成本制定執行計劃,例如確定表連線的順序、以何種方式執行連線、使用的並行度等。設定下面的屬性啟用基於成本最佳化器。
<property> <name>hive.cbo.enable</name> <value>true</value></property> <property> <name>hive.compute.query.using.stats</name> <value>true</value> </property><property> <name>hive.stats.fetch.partition.stats</name> <value>true</value></property> <property> <name>hive.stats.fetch.column.stats</name> <value>true</value> </property>
說明:
hive.cbo.enable:控制是否啟用基於成本的最佳化器,預設值是true。Hive的CBO使用Apache Calcite框架實現。
hive.compute.query.using.stats:該屬性的預設值為false。如果設定為true,Hive在執行某些查詢時,例如select count(1),只利用元資料儲存中儲存的狀態資訊返回結果。為了收集基本狀態資訊,需要將hive.stats.autogather屬性配置為true。為了收集更多的狀態資訊,需要執行analyze table查詢命令,例如下面的語句收集sales_order_fact表的統計資訊。
analyze tablesales_order_fact compute statistics forcolumns;
hive.stats.fetch.partition.stats:該屬性的預設值為true。操作樹中所標識的統計資訊,需要分割槽級別的基本統計,如每個分割槽的行數、資料量大小和檔案大小等。分割槽統計資訊從元資料儲存中獲取。如果存在很多分割槽,要為每個分割槽收集統計資訊可能會消耗大量的資源。這個標誌可被用於禁止從元資料儲存中獲取分割槽統計。當該標誌設定為false時,Hive從檔案系統獲取檔案大小,並根據表結構估算行數。
hive.stats.fetch.column.stats:該屬性的預設值為false。操作樹中所標識的統計資訊,需要列統計。列統計資訊從元資料儲存中獲取。如果存在很多列,要為每個列收 集統計資訊可能會消耗大量的資源。這個標誌可被用於禁止從元資料儲存中獲取列統計。
EXPLAIN
explain-解釋計劃,透過explain命令可以知道hive將會如何執行所寫的查詢語句,需要注意的是查詢語句並沒有執行哦,只是告訴你將會怎麼樣執行。
這對於HIVE SQL的調優是很重要的,一個複雜的SQL如果執行的時間過長,可以根據解釋計劃來看具體執行的步驟,進而找到可以最佳化的地方。
下面就結合例子看看如何檢視解釋計劃,程式碼中的註釋部分是要重點關注的。
EXPLAIN select student,sum(score) FROM test.class GROUP BY student
執行上述的程式碼:
ExplainPlan optimized by CBO.--CBO是開啟的,計劃基於CBO最佳化 Vertex dependency in root stageReducer 2 <- Map 1 (SIMPLE_EDGE)--簡單的依賴關係,一個Map2個Reducer Stage-0 Fetch Operator limit:-1 Stage-1 Reducer 2 File Output Operator [FS_6] Group By Operator[GBY_4] (rows=9 width=16) --reducer端的聚合 Output:["_col0","_col1"],aggregations:["sum(VALUE._col0)"],keys:KEY._col0 <-Map 1 [SIMPLE_EDGE]//發生在job的 map 處理階段過程 SHUFFLE [RS_3] PartitionCols:_col0 Group ByOperator [GBY_2] (rows=18 width=16) --map端的聚合 Output:["_col0","_col1"],aggregations:["sum(score)"],keys:student Select Operator [SEL_1] (rows=18 width=16) Output:["student","score"] TableScan [TS_0] (rows=18 width=16) --讀取表的資料 test@class,class,Tbl:COMPLETE,Col:NONE,Output:["student","score"]
上述列印的就是解釋計劃,主要關注的是Stage部分,需要注意的是這一部分是從下往上進行檢視的,最先檢視到的是讀取表的資料(18條記錄)及選取的欄位,然後可以看出在Map端先做了一次聚合,然後在recucer端又進行了一次聚合。
EXPLAIN後面可以加不同關鍵字來針對性的檢視,DEPENDENCY|AUTHORIZATION在實際工作中比較常用,我們著重介紹下這兩個關鍵字。
DEPENDENCY
EXPLAIN DEPENDENCYselect *FROM test.test_view --是一個測試檢視
Explain{"input_tables":[{"tablename":"test@test_view","tabletype":"VIRTUAL_VIEW"},{"tablename":"test@product","tabletype":"MANAGED_TABLE","tableParents":"[test@test_view]"}],"input_partitions":[]}
EXPLAIN DEPENDENCY用於描述整個sql需要依賴的輸入資料,為了直觀的看出它的結構,我將輸出的JSON格式化後展開如上圖所示:分為兩部分input_tables和input_partitions,顧名思義就是輸入的表和分割槽, 實際運用場景:
1)排錯,排查某個程式可能在執行過程略過了某個分割槽
2)理清程式依賴的表的輸入,理解程式的執行,特別是理解在倆表join的情況下的依賴輸入
AUTHORIZATION
ExplainINPUTS: test@classOUTPUTS: hdfs://hans/tmp/hive/spark/da7f94b3-b9e2-46f1-8bee-8a367f62a753/hive_2019-05-30_10-58-00_447_6351031319937169270-1/-mr-10001CURRENT_USER: sparkOPERATION: QUERYAUTHORIZATION_FAILURES: Permission denied: Principal [name=spark,type=USER] does not have following privileges for operation QUERY [[SELECT] onObject [type=TABLE_OR_VIEW, name=test.class]]
用來表達CURRENT_USER的使用者對哪些INPUTS有讀操作,對哪些OUTPUTS有寫操作。
上面的解釋計劃是spark的使用者,讀取test@class的資料,查詢出來的結果會暫時存放到hdfs://hans/tmp/hive/spark/da7f94b3-b9e2-46f1-8bee-8a367f62a753/hive_2019-05-30_10-58-00_447_6351031319937169270-1/-mr-10001檔案中。
替換引擎
為什麼要替換HIVE的預設執行引擎是MapReduce,MapReduce是一種離線計算框架,將一個演算法抽象成Map和Reduce兩個階段進行處理,每個階段都是用鍵值對(key/value)作為輸入和輸出,非常適合資料密集型計算。
但是缺點也很明顯,最直觀的感受就是執行時間長,它在計算時會對磁碟進行多次的讀寫操作,這樣啟動多輪job的代價略有些大,不僅佔用資源,更耗費大量的時間。
本篇前面在效能調優部分,所講解的最佳化措施就是針對MapReduce的,如果現在有另外一個引擎可以代替MapReduce並且自帶最佳化策略,你換不換?
替換成什麼?目前的主流選擇是Tez,Tez是Apache開源的支援DAG作業的計算框架,它直接源於MapReduce框架,核心思想是將Map和Reduce兩個操作進一步拆分,即Map被拆分成Input、Processor、Sort、Merge和Output, Reduce被拆分成Input、Shuffle、Sort、Merge、Processor和Output等,這樣,這些分解後的元操作可以任意靈活組合,產生新的操作,這些操作經過一些控制程式組裝後,可形成一個大的DAG作業。
總結起來,Tez在執行績效上有以下特點:
(1)比MapReduce更好的效能提升
(2)最佳資源管理
(3)執行中重新配置計劃
(4)動態物理資料流決策
從上面Tez的介紹來看,Tez的確有很多優點。
下面我們單單從執行過程來看,傳統的MR(包括Hive,Pig和直接編寫MR程式),假設有四個有依賴關係的MR作業(1個較為複雜的Hive SQL語句或者Pig指令碼可能被翻譯成4個有依賴關係的MR作業),執行過程如下(其中,綠色是Reduce Task,需要寫HDFS;雲狀表示寫遮蔽(write barrier,一種核心機制,持久寫);綠色的圓圈代表一個job):
MR需要4個job來完成計算,而Tez可以將多個有依賴的作業轉換為一個作業(這樣只需寫一次HDFS,且中間節點較少),從而大大提升DAG作業的效能。
怎麼替換肯定是要先安裝起來,這裡就不具體說明怎麼安裝了,網上相關的文章很多。安裝好了之後,只需對hive-site.xml中修改如下配置:
<property> <name>hive.execution.engine</name> <value>tez</value></property>
看到這裡,大家可以去檢視下自己的工作或者學習的HIVE平臺的引擎是什麼,如何還是mr建議換掉,在hive的命令列輸入下面的程式碼,即可檢視。
set hive.execution.engine;
總結
本篇HIVE進階講述的內容,可能在實際工作中不是全部很常用,但是對於更高效的利用HIVE、寫出高效和簡潔的HIVE SQL程式碼、程式調錯調優是非常重要的,所以掌握這些知識無疑是提升工作效率的一劑良藥。
參考文獻:
[7] Tez官網 - http://tez.apache.org