版權聲明:本套技術專欄是做者(秦凱新)平時工做的總結和昇華,經過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和集羣環境容量規劃等內容,請持續關注本套博客。QQ郵箱地址:1120746959@qq.com,若有任何技術交流,可隨時聯繫。算法
網上的Hbase調優資料良莠不齊,實在是不忍卒讀,有些都是拼湊且版本過期的東西,我這裏決定綜合全部優質資源進行整合,寫一份最全,最有深度,不過期的技術博客。辛苦成文,各自珍惜,謝謝!版權聲明:禁止轉載,歡迎學習,侵權必究!數據庫
數據塊編碼主要是針對 Key/Value 中的 Key 進行編碼,減小 Key 存儲所佔用的空間,由於不少 Key 的前綴都是重複的。舉例以下:緩存
若是使用前綴編碼做爲數據塊編碼方式,那麼它只會存儲第一個 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
複製代碼
差別編碼方式默認是不啓用的。爲何?由於太慢了,每條數據都要這樣計算一下,獲取數據的速度很慢。除非你要追求極致的壓縮比,可是不考慮讀取性能的時候可使用它,好比你想要把這部分數據看成歸檔數據的時候,能夠考慮使用差別編碼。網絡
差別編碼(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,若有任何技術交流,可隨時聯繫。學習
快速差別編碼(Fast Diff)借鑑了 Diff 編碼的思路,也考慮到了差別編碼速度慢的致命缺陷。快速差別編碼的 KeyValue 結構跟差別編碼如出一轍,只有 Flag 的存儲規則不同,而且優化了 Timestamp 的計算。Fast Diff 的實現比 Diff 更快,也是比較推薦的算法優化
不過這個「快速」只是相對原本的差別算法而言的,因爲仍是有不少計算過程存在,因此快速差別算法的速度依然屬於比較慢的。ui
前綴樹編碼(Prefix Tree)是前綴算法的變體,它是 0.96 版本以後才加入的特性。前綴樹編碼最大的做用就是提升了隨機讀的能力,可是其複雜的算法相對地下降了寫入的速度,消耗了更多的 CPU 資源,使用時須要在資源的消耗和隨機讀的性能之間進行取捨。
壓縮器的做用是能夠把 HBase 的數據按壓縮的格式存儲,這樣能夠更節省磁盤空間。固然這徹底是可選的,不過推薦你們仍是安裝 Snappy 壓縮器,這是 HBase 官方目前排名比較高的壓縮器。
hbase> alter 'mytable',{NAME =>'mycf',COMPRESSION=>'snappy'}
Snappy 是 Google 開發的壓縮器,有如下特色:
快速:壓縮速度達到 250MB/s;
穩定:已經用於 Google 多個產品長達數年;
健壯:Snappy 的解壓器能夠保證在數據被損壞的時候也不會太糟;
免費開源。
複製代碼
推薦將 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();
}
}
複製代碼
// 已廢棄,不推薦使用
// HTable table = new HTable(config, "mytable");
// 官方推薦
try (Connection connection = ConnectionFactory.createConnection(config)) {
connection.getTable(TableName.valueOf("tb1"));
}
複製代碼
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)
複製代碼
保證原子性的狀況下,把數據庫中的某個列的數字進行數學運算
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);
複製代碼
把添加一列的時候同時刪除另外一列的操做放在同一個原子操做中
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);
複製代碼
客戶端寫緩衝區就是一個在客戶端 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();
複製代碼
HBase 提供了專門針對批量 put 的操做方法:void put(List puts);其實內部也是用 batch 來實現的。須要注意的是,當一部分數據插入成功,可是另外一部分數據插入失敗,好比某個 RegionServer 服務器出現了問題,這時會返回一個 IOException,操做會被放棄,不過插入成功的數據不會被回滾。
對於插入失敗的數據,服務器會嘗試着再次去插入或者換一個 RegionServer,當嘗試的次數大於定義的最大次數會拋出 RetriesExhaustedWithDetailsException 異常,該異常包含了不少錯誤信息,包括有多少操做失敗了,失敗的緣由以及服務器名和重試的次數。
如今的 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>
複製代碼
本文解決了連個問題包括HBase數據塊編碼壓縮機制調優以及客戶端API 新版本最佳實踐
版權聲明:本套技術專欄是做者(秦凱新)平時工做的總結和昇華,經過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和集羣環境容量規劃等內容,請持續關注本套博客。QQ郵箱地址:1120746959@qq.com,若有任何技術交流,可隨時聯繫。
參考文檔及鏈接:Hbase不睡覺書 及官方文檔資料
複製代碼
秦凱新 於深圳 201801102252