《HBase 不睡覺》第四章 – 客戶端 API 入門

rochy_he發表於2018-11-26

《HBase 不睡覺書》是一本讓人看了不會睡著的 HBase 技術書籍,寫的非常不錯,為了加深記憶,決定把書中重要的部分整理成讀書筆記,便於後期查閱,同時希望為初學 HBase 的同學帶來一些幫助。

目錄

一、最佳實踐

1、建立 HBase 連線

建立 HBase 連線請注意以下幾點:

  • 把 HBase 配置資料夾中的 hbase-site.xml 和 Hadoop 配置資料夾中的 core-site.xml 配置檔案從伺服器上拖下來放到專案 resources 資料夾內;
  • 如果建立連線失敗,請先排查一下本機的 hosts 檔案中是不是忘記配置了伺服器的 IP 和 hostname 對映,導致計算機無法找到這些伺服器;
  • 操作執行關閉後,記得關閉資源,推薦使用 JDK7 的 try-with-resources 特性;
  • 常規情況下,推薦將 Configuration 做為單例;Connection 隨建隨用,用完及時關閉。

不推薦將 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();

}
}複製程式碼

2、HTable 類和 Table 介面

早期的教程會教大家使用 HTable 類,而且使用這個類的時候不需要去手動地獲取 Connection,只需要把 Configuration 類作為構建引數傳給 HTable 類,它會自動地去連線並完成操作。這個方法看起來操作很簡單,實則隱含著很多效能和安全問題,所以這個類被廢棄了

官方建議大家先手動獲取 Connection,然後再從 Connection 中獲取 Table 介面(注意:不是 HTable 類,而是 Table 介面):

// 已廢棄,不推薦使用// HTable table = new HTable(config, "mytable");
// 官方推薦try (Connection connection = ConnectionFactory.createConnection(config)) {
connection.getTable(TableName.valueOf("tb1"));

}複製程式碼

二、幾個重要的方法

1、checkAndPut(資料一致性)

在你讀出資料之後和修改資料中間這段時間,如果有別人也修改了這個資料,就會發生資料不一致的問題,checkAndPut 方法就是為了解決這個問題而產生的。

checkAndPut 方法只是把檢查和寫入這兩個步驟合二為一了,checkAndPut 方法在寫入前會先比較目前存在的資料是否與你傳入的資料一致,如果一致則進行 put 操作,並返回 true;如果不一致,則返回 false,但不寫入資料。

最新版本中 checkAndPut 已經棄用了,官方推薦使用 checkAndMutate。

2、checkAndMutate

checkAndPut 與 checkAndDelete 在最新的 API 中已經不推薦使用了,官方推薦使用 Table.checkAndMutate(byte[], byte[])。checkAndMutate 會在執行 Put/Delete/RowMutations 操作前檢查 row/family/qualifier value 是否與預期的值匹配,如果不匹配則不執行操作。

table.checkAndMutate(row, family).qualifier(qualifier).ifNotExists().thenPut(put);
複製程式碼

3、increment

保證原子性的情況下,把資料庫中的某個列的數字加 N(N 可以是正數或者負數)。

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);
複製程式碼

4、批量操作(batch)

當需要一次性操作(Put、Get、Delete)很多條資料的時候,為了操作方便並且提高效能,可以使用 batch 方法;這裡的操作列表 actions 裡面的操作可以是 Put、Get、Delete 中的任意一種;第二個引數的 results 是操作的結果,results 中的結果順序是跟傳入的操作列表順序一一對應的。

void batch(List<
Row>
actions, Object[] results)複製程式碼

最好不要把針對同一個單元格的 Put 和 Delete 放到同一個 actions 列表裡面,因為 HBase 不一定是順序地執行這些操作的,你可能會得到意想不到的結果。

5、批量 put 操作

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

插入失敗的重試

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

如果定義了錯誤的列族,則只會嘗試一次,因為如果連列族都錯了,就沒必要再繼續嘗試下去了,HBase 會直接返回 NoSuchColumnFamilyException。

寫緩衝區

插入失敗的資料會繼續被放到本地的寫緩衝區,並在下次插入的時候重試,你甚至可以操作它們,比如清除這些資料。

6、BufferedMutator

客戶端寫緩衝區就是一個在客戶端 JVM 裡面的快取機制,可以把多個 Put 操作攢到一起通過單個 RPC 請求傳送給客戶端,目的是節省網路握手帶來的 IO 消耗。這個緩衝區可以通過呼叫 HTable.setAutoFlush(false) 來開啟。

最新版的 API 中 setAutoFlush 被廢棄了,每個表自帶的 writeBuffer 也被廢棄了,但是客戶端寫緩衝區還是存在的,只是轉而使用 BufferedMutator 物件。

BufferedMutator bm = connection.getBufferedMutator(TableName.valueOf("tb1"));
// 然後用BufferedMutator物件來提交Put操作bm.mutate(put);
// 然後呼叫 flush 或者 close 方法都可以把請求批量地提交給服務端bm.flush();
bm.close();
複製程式碼

大部分情況下我們不需要直接呼叫到 BufferedMutator,也不推薦直接呼叫 BufferedMutator。

7、Scan 快取

早期的 HBase 在掃描的時候預設是不開啟快取的,但是經過了廣大使用者許多次的實踐後,現在的 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>
200<
/value>
<
/property>
複製程式碼

意思是每次 next 操作都獲取 200 條資料,預設配置是100。

可以使用 Scan.setCaching(int caching)方法在掃描層面修改快取,這個配置優先順序比配置檔案內的高,可以複寫這個配置值。快取固然好,但是帶來的危害就是會佔用大量記憶體,最糟糕的就是直接出現 OutOfMemoryException,所以也不要盲目的調大快取。


Any Code,Code Any!

掃碼關注『AnyCode』,程式設計路上,一起前行。

《HBase 不睡覺》第四章 – 客戶端 API 入門

來源:https://juejin.im/post/5bfc03ace51d4522143b851a#comment

相關文章