如果想要享受HBase飛快的查詢速度,與避免read/write的hotspot,好的RowKey Design是很重要的。

HBase的資料是儲存於Region Server並且以RowKey當作各Region分區的界線。由於RowKey是使用字典排序,當RowKey為連續字串時會導致資料傾斜,資料過度集中於某個region server。當這狀況發生時,如果有多個使用者同時對這個table發出請求(讀/寫),這個region server會無法接受過多的請求數量而過於忙碌,這時候(讀/寫)的效能就會下降,嚴重的會導致該region server被認定已經crash,觸發HBase容錯機制而讓整個HBase叢集更為忙碌…

RowKey Scan

假設有個RowKey的結構長成這樣:

<userId>-<date>-<messageId>-<attachementId>

前面有介紹過HBase在使用RoeKey當作filter時,使用Scan查詢速度最快可以到毫秒等級。一般使用者會搭配已模糊查詢的方式來查資料,而HBase的RowKey在模糊查詢上就會有個限制,就是只支援後面字串的模糊查詢。以上面的RowKey結構為例,在查詢時就只能使用這四種方式:

1. <userId>
2. <userId>-<date>
3. <userId>-<date>-<messageId>
4. <userId>-<date>-<messageId>-<attachementId>

Key Design Type

接下來會介紹下列四種RowKey設計方法:

  • Sequential/Time-serial key
  • Salted key
  • Field swap/promotion
  • Random key

Sequential/Time-serial key

如果使用Sequential/Time-serial key當作RowKey,資料會被寫入同一個region,此設計不適用於頻繁寫入的使用情境。

  • Sequential key : 假設使用員工編號當作RowKey
員工編號
A0001
A0002
A0003
A0004
  • Time-serial key : 假設以訂單紀錄當作RowKey,格式為:yyyy-mmdd-hhmmssss-productionId
訂單記錄
2010-0101-11562366-prdId1
2010-0101-23332187-prdId2
2010-0103-14224378-prdId1
···
2010-0301-08262299-prdId5
2010-0302-17260101-prdId7
···
2010-0801-11562377-prdId5
···

Salted key

俗稱的灑鹽巴使用演算法對RowKey加工,讓資料平均散佈到各個Region Server。

以員工編號為例

員工編號
A0001
A0002
A0003
A0004

使用String rowkey = id.reverse()方法灑完鹽巴後就會成這樣:

員工編號
1000A
2000A
3000A
4000A

Field swap/promotion key

假設RowKey的格式是這樣<date>-<userId>,Swap方式就是把這兩個欄位位置交換:

<date>-<userId> -> <userId>-<date>

而Promotion意指將某個cf:qualifier的值提升至RowKey的位置,與原來的RowKey形成一個新的複合RowKey:

Field_promotion_key_before.png

Field_promotion_key_after.png

Random key

Random Key,顧名思義就是隨機分布的RowKey,這種設計可以降低在寫入的情境發生hotspot的狀況。
例如可以使用MD5對timestamp加密後產生一組隨機的RowKey:

byte[] rowkey = MD5(timestamp)

效能

由下面的圖可以了解這幾種RowKey適用的情境與效能:

Rowkey_performance.png
From HBase: The Definitive Guide

最後

任何一種的RowKey設計沒有絕對好或是不好的分別,要看使用情境再決定要挑選哪種設定方式。
介紹完了RowKey設計後,接下來要來介紹HBase hello world api。