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

版權聲明:本套技術專欄是做者(秦凱新)平時工做的總結和昇華,經過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和集羣環境容量規劃等內容,請持續關注本套博客。QQ郵箱地址:1120746959@qq.com,若有任何技術交流,可隨時聯繫。算法

網上的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)比前綴編碼更進一步,差別編碼甚至把如下字段也一塊兒進行了差別化的編碼。app

鍵長度(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郵箱地址:1120746959@qq.com,若有任何技術交流,可隨時聯繫。學習

1.3 快速差別編碼(Fast Diff)

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

不過這個「快速」只是相對原本的差別算法而言的,因爲仍是有不少計算過程存在,因此快速差別算法的速度依然屬於比較慢的。ui

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.八、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郵箱地址:1120746959@qq.com,若有任何技術交流,可隨時聯繫。

參考文檔及鏈接:Hbase不睡覺書 及官方文檔資料
複製代碼

秦凱新 於深圳 201801102252

相關文章
相關標籤/搜索