1. 程式人生 > >HBase資料塊編碼壓縮機制調優及客戶端API 新版本最佳實踐-OLAP商業環境實戰

HBase資料塊編碼壓縮機制調優及客戶端API 新版本最佳實踐-OLAP商業環境實戰

版權宣告:本套技術專欄是作者(秦凱新)平時工作的總結和昇華,通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。QQ郵箱地址:[email protected],如有任何技術交流,可隨時聯絡。

網上的Hbase調優資料參差不齊,實在是不忍卒讀,有些都是拼湊且版本過時的東西,我這裡決定綜合所有優質資源進行整合,寫一份最全,最有深度,不過時的技術部落格。辛苦成文,各自珍惜,謝謝!版權宣告:禁止轉載,歡迎學習,侵權必究!

1 HBase 資料塊編碼Key優化

資料塊編碼主要是針對 Key/Value 中的 Key 進行編碼,減少 Key 儲存所佔用的空間,因為很多 Key 的字首都是重複的。舉例如下:

1.1 字首編碼(Prefix)

如果使用字首編碼作為資料塊編碼方式,那麼它只會儲存第一個 Key 的完整字串,後面的 key 只儲存跟第一個 key 的差異字元,重新編碼過的資料如下所示。如下例所示:

     最上面的key值為:
     myrow001:mycf:col1
     
     針對於key而言,後續的可以之儲存差異值:
     myrow001:mycf:col2就變為2
     myrow001:mycf:col3就變為3
     myrow002:mycf:col3就變為 2:mycf:col1 (變為最上面)
     
     myrow003:mycf:col3就變為 3
複製程式碼

1.2 差異編碼(Diff)

差異編碼方式預設是不啟用的。為什麼?因為太慢了,每條資料都要這樣計算一下,獲取資料的速度很慢。除非你要追求極致的壓縮比,但是不考慮讀取效能的時候可以使用它,比如你想要把這部分資料當作歸檔資料的時候,可以考慮使用差異編碼。

差異編碼(Diff)比字首編碼更進一步,差異編碼甚至把以下欄位也一起進行了差異化的編碼。

    鍵長度(KeyLen);
    值長度(ValueLen);
    時間戳(Timestamp),也即是Version;
    型別(Type),也即是鍵型別。
複製程式碼

採用了差異編碼後的 KeyValue 結構為:

    1 byte:標誌位;
    1-5 bytes:Key 長度(KeyLen);
    1-5 bytes:Value 長度(ValLen);
    1-5 bytes:字首長度(Prefix Len);
    ... bytes:剩餘的部分;
    ... bytes:真正的 Key 或者只是有差異的 key 字尾部分;
    1-8 bytes:時間戳(timestamp)或者時間戳的差異部分;
    1 byte:Key 型別(type);
    ... bytes:值(value)。
複製程式碼

版權宣告:本套技術專欄是作者(秦凱新)平時工作的總結和昇華,通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。QQ郵箱地址:[email protected],如有任何技術交流,可隨時聯絡。

1.3 快速差異編碼(Fast Diff)

快速差異編碼(Fast Diff)借鑑了 Diff 編碼的思路,也考慮到了差異編碼速度慢的致命缺陷。快速差異編碼的 KeyValue 結構跟差異編碼一模一樣,只有 Flag 的儲存規則不一樣,並且優化了 Timestamp 的計算。Fast Diff 的實現比 Diff 更快,也是比較推薦的演算法

不過這個“快速”只是相對本來的差異演算法而言的,由於還是有很多計算過程存在,所以快速差異演算法的速度依然屬於比較慢的。

1.4 字首樹編碼(Prefix Tree)

字首樹編碼(Prefix Tree)是字首演算法的變體,它是 0.96 版本之後才加入的特性。字首樹編碼最大的作用就是提高了隨機讀的能力,但是其複雜的演算法相對地降低了寫入的速度,消耗了更多的 CPU 資源,使用時需要在資源的消耗和隨機讀的效能之間進行取捨。

2 基於Value的壓縮器啟用

壓縮器的作用是可以把 HBase 的資料按壓縮的格式儲存,這樣可以更節省磁碟空間。當然這完全是可選的,不過推薦大家還是安裝 Snappy 壓縮器,這是 HBase 官方目前排名比較高的壓縮器。

    hbase> alter 'mytable',{NAME =>'mycf',COMPRESSION=>'snappy'}
    
    Snappy 是 Google 開發的壓縮器,有以下特點:
    
    快速:壓縮速度達到 250MB/s;
    穩定:已經用於 Google 多個產品長達數年;
    健壯:Snappy 的解壓器可以保證在資料被損壞的時候也不會太糟;
    免費開源。
複製程式碼

3 客戶端API 新版本最佳實踐

3.1 Connection 連線例項出世

推薦將 Configuration 做為單例;Connection 隨建隨用,用完及時關閉。

public static void main(String[] args) throws URISyntaxException, IOException {
    //獲取配置檔案
    Configuration config = HBaseConfiguration.create();
    config.addResource(new Path(ClassLoader.getSystemResource("hbase-site.xml").toURI()));
    config.addResource(new Path(ClassLoader.getSystemResource("core-site.xml").toURI()));
    
    //建立連線
    try (Connection connection = ConnectionFactory.createConnection(config); Admin admin = connection.getAdmin()) {
        //定義表名
        TableName tableName = TableName.valueOf("tb1");
        //定義列族
        ColumnFamilyDescriptor myCf = ColumnFamilyDescriptorBuilder.of("cf1");
        //定義表
        TableDescriptor table = TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(myCf).build();
        //執行建立表動作
        admin.createTable(table);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}
複製程式碼

3.2 new HTable已廢棄,新用法

// 已廢棄,不推薦使用
// HTable table = new HTable(config, "mytable");

// 官方推薦
try (Connection connection = ConnectionFactory.createConnection(config)) {
    connection.getTable(TableName.valueOf("tb1"));
}
複製程式碼

3.3 checkAndPut(資料一致性)方法

    Put put =new Put(Bytes.toBytes("qinkaixinRowkeys"))
    put.addColumn(Bytes.toBytes("mycf"),Bytes.toBytes("name"),Bytes.toBytes("ted"));
    
    boolean result = table.checkAndput(
                                        Bytes.toBytes("row3"),
                                        Bytes.toBytes("mycf"),
                                        Bytes.toBytes("name"),
                                        Bytes.toBytes("ted"),
                                        put)
複製程式碼

3.4 increment方法

保證原子性的情況下,把資料庫中的某個列的數字進行數學運算

Table table = connection.getTable(TableName.valueOf("tb1"));
Increment inc = new Increment(Bytes.toBytes("row1"));
inc.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"), 1L);
table.increment(inc);
複製程式碼

3.5 Mutation 方法

把新增一列的時候同時刪除另一列的操作放在同一個原子操作中

    Delete delete =new Delete(Bytes.toBytes("qinkaixinRowkeys"))
    delete.addColumn(Bytes.toBytes("mycf"),Bytes.toBytes("name"),Bytes.toBytes("ted"));
    
    Put put =new Put(Bytes.toBytes("qinkaixinRowkeys"))
    put.addColumn(Bytes.toBytes("mycf"),Bytes.toBytes("name"),Bytes.toBytes("ted"));
    
    RowMutations rowMutations =new RowMutations(Bytes.toBytes("ted"));
    rowMutations.add(delete);
    rowMutations.add(put);
    table.mutateRow(rowMutations);
複製程式碼

3.6 BufferedMutator批量操作(batch)()

客戶端寫緩衝區就是一個在客戶端 JVM 裡面的快取機制,可以把多個 Put 操作攢到一起通過單個 RPC 請求傳送給客戶端,目的是節省網路握手帶來的 IO 消耗。這個緩衝區可以通過呼叫 HTable.setAutoFlush(false) 來開啟。 最新版的 API 中 setAutoFlush 被廢棄了,每個表自帶的 writeBuffer 也被廢棄了,但是客戶端寫緩衝區還是存在的,只是轉而使用 BufferedMutator 物件。

    最好不要把針對同一個單元格的 Put 和 Delete 放到同一個 actions 列表裡面,因為 HBase 不一定是順序地執行這些操作的,你可能會得到意想不到的結果。
    
    connection.getTable(TableName.valueOf("tb1")
    Table table = connection.getBufferedMutator(TableName.valueOf("mytable"));
    bm.mutate(put);
    
    bm.flush();
    bm.close();
複製程式碼

3.7 批量 put 操作

HBase 提供了專門針對批量 put 的操作方法:void put(List puts);其實內部也是用 batch 來實現的。需要注意的是,當一部分資料插入成功,但是另一部分資料插入失敗,比如某個 RegionServer 伺服器出現了問題,這時會返回一個 IOException,操作會被放棄,不過插入成功的資料不會被回滾。

對於插入失敗的資料,伺服器會嘗試著再次去插入或者換一個 RegionServer,當嘗試的次數大於定義的最大次數會丟擲 RetriesExhaustedWithDetailsException 異常,該異常包含了很多錯誤資訊,包括有多少操作失敗了,失敗的原因以及伺服器名和重試的次數。

3.8、Scan 快取優化

現在的 HBase 在掃描的時候已經預設開啟了快取。

每一次的 next() 操作都會產生一次完整的 RPC 請求,而這次 RPC 請求可以獲取多少資料是通過 hbase-site.xml 中的 hbase.client.scanner.caching 引數配置的。比如你如果配置該項為 1,那麼當你遍歷了 10 個結果就會發送 10 次請求,顯而易見這是比較消耗效能的,尤其是當單條的資料量較小的時候。

hbase-site.xml引數調優:

    <property>
        <name>hbase.client.scanner.caching</name>
        <value>100</value>
    </property>
複製程式碼

4 總結

本文解決了連個問題包括HBase資料塊編碼壓縮機制調優以及客戶端API 新版本最佳實踐

版權宣告:本套技術專欄是作者(秦凱新)平時工作的總結和昇華,通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。QQ郵箱地址:[email protected],如有任何技術交流,可隨時聯絡。

    參考文件及連線:Hbase不睡覺書 及官方文件資料
複製程式碼

秦凱新 於深圳 201801102252