1. 程式人生 > >Hive over HBase和Hive over HDFS效能比較分析

Hive over HBase和Hive over HDFS效能比較分析

http://superlxw1234.iteye.com/blog/2008274

環境配置:

hadoop-2.0.0-cdh4.3.0 (4 nodes, 24G mem/node)

hbase-0.94.6-cdh4.3.0 (4 nodes,maxHeapMB=9973/node)

hive-0.10.0-cdh4.3.0

一、查詢效能比較:

    query1: 
        select count(1) from on_hdfs;
        select count(1) from on_hbase;
    query2(根據key過濾)
        select * from on_hdfs 
            where key = '13400000064_1388056783_460095106148962';
        select * from on_hbase 
            where key = '13400000064_1388056783_460095106148962';
    query3(根據value過濾)
        select * from on_hdfs where value = 'XXX';
        select * from on_hbase where value = 'XXX';

    on_hdfs (20萬記錄,150M,TextFile on HDFS)
    on_hbase(20萬記錄,160M,HFile on HDFS)

     

    on_hdfs (2500萬記錄,2.7G,TextFile on HDFS)
    on_hbase(2500萬記錄,3G,HFile on HDFS)

    

 

     從上圖可以看出,
            對於全表掃描,hive_on_hbase查詢時候如果不設定catching,效能遠遠不及hive_on_hdfs;
            根據rowkey過濾,hive_on_hbase效能上略好於hive_on_hdfs,特別是資料量大的時候;
            設定了caching之後,儘管比不設caching好很多,但還是略遜於hive_on_hdfs;

二、Hive over HBase原理

    Hive與HBase利用兩者本身對外的API來實現整合,主要是靠HBaseStorageHandler進行通訊,利用HBaseStorageHandler,Hive可以獲取到Hive表對應的HBase表名,列簇以及列,InputFormat和OutputFormat類,建立和刪除HBase表等。
    Hive訪問HBase中表資料,實質上是通過MapReduce讀取HBase表資料,其實現是在MR中,使用HiveHBaseTableInputFormat完成對HBase表的切分,獲取RecordReader物件來讀取資料。
    對HBase表的切分原則是一個Region切分成一個Split,即表中有多少個Regions,MR中就有多少個Map;
    讀取HBase表資料都是通過構建Scanner,對錶進行全表掃描,如果有過濾條件,則轉化為Filter。當過濾條件為rowkey時,則轉化為對rowkey的過濾;
    Scanner通過RPC呼叫RegionServer的next()來獲取資料;

三、效能瓶頸分析

1. Map Task

    Hive讀取HBase表,通過MR,最終使用HiveHBaseTableInputFormat來讀取資料,在getSplit()方法中對HBase表進行切分,切分原則是根據該表對應的HRegion,將每一個Region作為一個InputSplit,即,該表有多少個Region,就有多少個Map Task;
    每個Region的大小由引數hbase.hregion.max.filesize控制,預設10G,這樣會使得每個map task處理的資料檔案太大,map task效能自然很差;
    為HBase表預分配Region,使得每個Region的大小在合理的範圍;
    下圖是給該表預分配了15個Region,並且控制key均勻分佈在每個Region上之後,查詢的耗時對比,其本質上是Map數增加。

    

2. Scan RPC 呼叫:

  •     在Scan中的每一次next()方法都會為每一行資料生成一個單獨的RPC請求, query1和query3中,全表有2500萬行記錄,因此要2500萬次RPC請求;
  •     掃描器快取(Scanner Caching):HBase為掃描器提供了快取的功能,可以通過引數hbase.client.scanner.caching來設定;預設是1;快取的原理是通過設定一個快取的行數,當客戶端通過RPC請求RegionServer獲取資料時,RegionServer先將資料快取到記憶體,當快取的資料行數達到引數設定的數量時,再一起返回給客戶端。這樣,通過設定掃描器快取,就可以大幅度減少客戶端RPC呼叫RegionServer的次數;但並不是快取設定的越大越好,如果設定的太大,每一次RPC呼叫將會佔用更長的時間,因為要獲取更多的資料並傳輸到客戶端,如果返回給客戶端的資料超出了其堆的大小,程式就會終止並跑出OOM異常;

    所以,需要為少量的RPC請求次數和客戶端以及服務端的記憶體消耗找到平衡點。

    rpc.metrics.next_num_ops
    未設定caching,每個RegionServer上通過next()方法呼叫RPC的次數峰值達到1000萬:


    設定了caching=2000,每個RegionServer上通過next()方法呼叫RPC的次數峰值只有4000:



    設定了caching之後,幾個RegionServer上的記憶體消耗明顯增加:



 

  •     掃描器批量(Scanner Batch):快取是面向行一級的操作,而批量則是面向列一級的操作。批量可以控制每一次next()操作要取回多少列。比如,在掃描器中設定setBatch(5),則一次next()返回的Result例項會包括5列。
  •     RPC請求次數的計算公式如下:
    RPC請求次數 = 
    (錶行數 * 每行的列數)/ Min(每行的列數,批量大小)  / 掃描器快取

因此,在使用Hive over HBase,對HBase中的表做統計分析時候,需要特別注意以下幾個方面:

1. 對HBase表進行預分配Region,根據表的資料量估算出一個合理的Region數;

2. rowkey設計上需要注意,儘量使rowkey均勻分佈在預分配的N個Region上;

3. 通過set hbase.client.scanner.caching設定合理的掃描器快取;

4. 關閉mapreduce的推測執行:

   set mapred.map.tasks.speculative.execution = false;
   set mapred.reduce.tasks.speculative.execution = false;