HBase Rowkey 設計指南

HBase Rowkey 設計指南

 

爲何Rowkey這麼重要

RowKey 究竟是什麼

HBase Rowkey 設計指南
若是想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公共賬號: iteblog_hadoop

咱們常說看一張 HBase 表設計的好很差,就看它的 RowKey 設計的好很差。可見 RowKey 在 HBase 中的地位。那麼 RowKey 究竟是什麼?RowKey 的特色以下:html

  • 相似於 MySQL、Oracle中的主鍵,用於標示惟一的行;
  • 徹底是由用戶指定的一串不重複的字符串;
  • HBase 中的數據永遠是根據 Rowkey 的字典排序來排序的。

RowKey的做用

  • 讀寫數據時經過 RowKey 找到對應的 Region;
  • MemStore 中的數據按 RowKey 字典順序排序;
  • HFile 中的數據按 RowKey 字典順序排序。

Rowkey對查詢的影響

若是咱們的 RowKey 設計爲 uid+phone+name,那麼這種設計能夠很好的支持如下的場景:算法

  • uid = 111 AND phone = 123 AND name = iteblog
  • uid = 111 AND phone = 123
  • uid = 111 AND phone = 12?
  • uid = 111

難以支持的場景:緩存

  • phone = 123 AND name = iteblog
  • phone = 123
  • name = iteblog

Rowkey對Region劃分影響

HBase 表的數據是按照 Rowkey 來分散到不一樣 Region,不合理的 Rowkey 設計會致使熱點問題。熱點問題是大量的 Client 直接訪問集羣的一個或極少數個節點,而集羣中的其餘節點卻處於相對空閒狀態。微信

HBase Rowkey 設計指南
若是想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公共賬號: iteblog_hadoop

如上圖,Region1 上的數據是 Region 2 的5倍,這樣會致使 Region1 的訪問頻率比較高,進而影響這個 Region 所在機器的其餘 Region。oop

RowKey設計技巧

咱們如何避免上面說到的熱點問題呢?這就是這章節談到的三種方法。ui

避免熱點的方法 - Salting

這裏的加鹽不是密碼學中的加鹽,而是在rowkey 的前面增長隨機數。具體就是給 rowkey 分配一個隨機前綴 以使得它和以前排序不一樣。分配的前綴種類數量應該和你想使數據分散到不一樣的 region 的數量一致。 若是你有一些 熱點 rowkey 反覆出如今其餘分佈均勻的 rwokey 中,加鹽是頗有用的。考慮下面的例子:它將寫請求分散到多個 RegionServers,可是對讀形成了一些負面影響。spa

假如你有下列 rowkey,你表中每個 region 對應字母表中每個字母。 以 'a' 開頭是同一個region, 'b'開頭的是同一個region。在表中,全部以 'f'開頭的都在同一個 region, 它們的 rowkey 像下面這樣:操作系統

foo0001
foo0002
foo0003
foo0004

如今,假如你須要將上面這個 region 分散到 4個 region。你能夠用4個不一樣的鹽:'a', 'b', 'c', 'd'.在這個方案下,每個字母前綴都會在不一樣的 region 中。加鹽以後,你有了下面的 rowkey:設計

a-foo0003
b-foo0001
c-foo0004
d-foo0002

因此,你能夠向4個不一樣的 region 寫。理論上說,若是這四個 Region 存放在不一樣的機器上,通過加鹽以後你將擁有以前4倍的吞吐量。code

如今,若是再增長一行,它將隨機分配a,b,c,d中的一個做爲前綴,並以一個現有行做爲尾部結束:

a-foo0003
b-foo0001
c-foo0003
c-foo0004
d-foo0002

由於分配是隨機的,因此若是你想要以字典序取回數據,你須要作更多工做。加鹽這種方式增長了寫時的吞吐量,可是當讀時有了額外代價。

避免熱點的方法 - Hashing

Hashing 的原理是計算 RowKey 的 hash 值,而後取 hash 的部分字符串和原來的 RowKey 進行拼接。這裏說的 hash 包含 MD五、sha一、sha256或sha512等算法。好比咱們有以下的 RowKey:

foo0001
foo0002
foo0003
foo0004

咱們使用 md5 計算這些 RowKey 的 hash 值,而後取前 6 位和原來的 RowKey 拼接獲得新的 RowKey:

95f18cfoo0001
6ccc20foo0002
b61d00foo0003
1a7475foo0004

優缺點:能夠必定程度打散整個數據集,可是不利於 Scan;好比咱們使用 md5 算法,來計算Rowkey的md5值,而後截取前幾位的字符串。subString(MD5(設備ID), 0, x) + 設備ID,其中x通常取5或6。

避免熱點的方法 - Reversing

Reversing 的原理是反轉一段固定長度或者所有的鍵。好比咱們有如下 URL ,並做爲 RowKey:

flink.iteblog.com
www.iteblog.com
carbondata.iteblog.com
def.iteblog.com

這些 URL 其實屬於同一個域名,可是因爲前面不同,致使數據不在一塊兒存放。咱們能夠對其進行反轉,以下:

moc.golbeti.knilf
moc.golbeti.www
moc.golbeti.atadnobrac
moc.golbeti.fed

通過這個以後,這些 URL 的數據就能夠放一塊兒了。

RowKey的長度

RowKey 能夠是任意的字符串,最大長度64KB(由於 Rowlength 佔2字節)。建議越短越好,緣由以下:

  • 數據的持久化文件HFile中是按照KeyValue存儲的,若是rowkey過長,好比超過100字節,1000w行數據,光rowkey就要佔用100*1000w=10億個字節,將近1G數據,這樣會極大影響HFile的存儲效率;
  • MemStore將緩存部分數據到內存,若是rowkey字段過長,內存的有效利用率就會下降,系統不能緩存更多的數據,這樣會下降檢索效率;
  • 目前操做系統都是64位系統,內存8字節對齊,控制在16個字節,8字節的整數倍利用了操做系統的最佳特性。

RowKey 設計案例剖析

交易類表 Rowkey 設計

  • 查詢某個賣家某段時間內的交易記錄
    sellerId + timestamp + orderId
  • 查詢某個買家某段時間內的交易記錄
    buyerId + timestamp +orderId
  • 根據訂單號查詢
    orderNo
  • 若是某個商家賣了不少商品,能夠以下設計 Rowkey 實現快速搜索
    salt + sellerId + timestamp 其中,salt 是隨機數。
    能夠支持的場景:

     

    • 全表 Scan
    • 按照 sellerId 查詢
    • 按照 sellerId + timestamp 查詢

金融風控 Rowkey 設計

查詢某個用戶的用戶畫像數據

  • prefix + uid
  • prefix + idcard
  • prefix + tele

其中 prefix = substr(md5(uid),0 ,x), x 取 5-6。uid、idcard以及 tele 分別表示用戶惟一標識符、身份證、手機號碼。

車聯網 Rowkey 設計

  • 查詢某輛車在某個時間範圍的交易記錄
    carId + timestamp
  • 某批次的車太多,形成熱點
    prefix + carId + timestamp 其中 prefix = substr(md5(uid),0 ,x)

查詢最近的數據

查詢用戶最新的操做記錄或者查詢用戶某段時間的操做記錄,RowKey 設計以下:
uid + Long.Max_Value - timestamp
支持的場景

  • 查詢用戶最新的操做記錄
    Scan [uid] startRow [uid][000000000000] stopRow [uid][Long.Max_Value - timestamp]
  • 查詢用戶某段時間的操做記錄
    Scan [uid] startRow [uid][Long.Max_Value – startTime] stopRow [uid][Long.Max_Value - endTime]

OpenTSDB 的 Rowkey 設計

參見 《OpenTSDB 底層 HBase 的 Rowkey 是如何設計的》

若是 RowKey 沒法知足咱們的需求,能夠嘗試二級索引。Phoenix、Solr 以及 ElasticSearch 均可以用於構建二級索引。

相關文章
相關標籤/搜索