設(shè)計(jì)HBase RowKey需要注意的二三事

在HBase中,定位一條數(shù)據(jù)(即一個(gè)Cell)需要4個(gè)維度的限定:行鍵(RowKey)、列族(Column Family)、列限定符(Column Qualifier)、時(shí)間戳(Timestamp)。其中,RowKey是最容易出現(xiàn)問題的。除了根據(jù)業(yè)務(wù)和查詢需求來設(shè)計(jì)之外,還需要注意以下三點(diǎn)。

  1. 打散RowKey
    HBase中的行是按照RowKey字典序排序的。這對(duì)Scan操作非常友好,因?yàn)镽owKey相近的行總是存儲(chǔ)在相近的位置,順序讀的效率比隨機(jī)讀要高。但是,如果大量的讀寫操作總是集中在某個(gè)RowKey范圍,那么就會(huì)造成Region熱點(diǎn),拖累RegionServer的性能。因此,要適當(dāng)?shù)貙owKey打散。
  • 加鹽(salting)+哈希(hashing)
    這里的“加鹽”與密碼學(xué)中的“加鹽”不是一回事。它是指在RowKey的前面增加一些前綴。加鹽的前綴種類越多,RowKey就被打得越散。
    前綴不可以是隨機(jī)的,因?yàn)楸仨氁尶蛻舳四軌蛲暾刂貥?gòu)RowKey。我們一般會(huì)拿原RowKey或其一部分計(jì)算hash值,然后再對(duì)hash值做運(yùn)算作為前綴。
  • 反轉(zhuǎn)固定格式的數(shù)值
    以手機(jī)號(hào)為例,手機(jī)號(hào)的前綴變化比較少(如152、185等),但后半部分變化很多。如果將它反轉(zhuǎn)過來,可以有效地避免熱點(diǎn)。不過其缺點(diǎn)就是失去了有序性。
  • 反轉(zhuǎn)時(shí)間
    這個(gè)操作嚴(yán)格來講不算“打散”,但可以調(diào)整數(shù)據(jù)的時(shí)間排序。如果將時(shí)間按照字典序排列,最近產(chǎn)生的數(shù)據(jù)會(huì)排在舊數(shù)據(jù)后面。如果用一個(gè)大值減去時(shí)間(比如用99999999減去yyyyMMdd,或者Long.MAX_VALUE減去時(shí)間戳),最新的數(shù)據(jù)就可以排在前面了。
  1. 控制RowKey長度
    在HBase中,RowKey、列族、列名等都是以byte[]形式傳輸?shù)摹owKey的最大長度限制為64KB,但在實(shí)際應(yīng)用中最多不會(huì)超過100B。設(shè)計(jì)短RowKey有以下兩方面考慮:
  • 在HBase的底層存儲(chǔ)HFile中,RowKey是KeyValue結(jié)構(gòu)中的一個(gè)域。假設(shè)RowKey長度100B,那么1000萬條數(shù)據(jù)中,只算RowKey就占用掉將近1G空間,會(huì)影響HFile的存儲(chǔ)效率。


    HFile簡單結(jié)構(gòu)示意
  • HBase中設(shè)計(jì)有MemStore和BlockCache,分別對(duì)應(yīng)列族/Store級(jí)別的寫入緩存,和RegionServer級(jí)別的讀取緩存。如果RowKey過長,緩存中存儲(chǔ)數(shù)據(jù)的密度就會(huì)降低,影響數(shù)據(jù)落地或查詢效率。


    MemStore與BlockCache

另外,我們目前使用的服務(wù)器操作系統(tǒng)都是64位系統(tǒng),內(nèi)存是按照8B對(duì)齊的,因此設(shè)計(jì)RowKey時(shí)一般做成8B的整數(shù)倍,如16B或者24B,可以提高尋址效率。
同樣地,列族、列名的命名在保證可讀的情況下也應(yīng)盡量短。HBase官方不推薦使用3個(gè)以上列族,因此實(shí)際上列族命名幾乎都用一個(gè)字母,比如‘c’或‘f’。

  1. 保證RowKey唯一性
    這個(gè)就是顯而易見的了,不再贅述。

舉個(gè)例子
我們的業(yè)務(wù)中,有一部分是用戶在日歷上記錄自己的行為。需要儲(chǔ)存在RowKey中的維度有:用戶ID(uid,不會(huì)超過十億)、日歷上的日期(date,yyyyMMdd格式)、記錄行為的類型(type,0~99之間)。記錄的詳細(xì)數(shù)據(jù)則存儲(chǔ)在列f:data中。根據(jù)查詢邏輯,我們設(shè)計(jì)的RowKey格式如下:

9~79809782~05~0008839540

長度正好是24B。以字符‘~’為分界(‘~’的ASCII碼是最大的,方便),各個(gè)部分的含義如下:

  • uid.toString().hashCode() % 10
  • 99999999 - date
  • StringUtils.leftPad(type, 2, "0")
  • StringUtils.leftPad(uid, 10, "0")

基于這種設(shè)計(jì),我們在建表階段就可以將其預(yù)分區(qū),使得數(shù)據(jù)在一開始就均勻分布在不同的Region上。建表語句參考:

create 'user_calendar_record', {
  NAME => 'f',
  VERSIONS => '1',
  BLOCKCACHE => 'true',
  BLOCKSIZE => '65536', 
  BLOOMFILTER => 'row',
  COMPRESSION => 'SNAPPY'
}, {
  SPLITS => ['1', '2', '3', '4', '5', '6', '7', '8', '9']
}

如果不做預(yù)分區(qū),那么表剛開始只會(huì)有一個(gè)Region。隨著數(shù)據(jù)量增大,就會(huì)頻繁觸發(fā)Region split,影響效率。關(guān)于Region split應(yīng)該另外寫文章討論,這里就不提了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、Region 概念 Region是表獲取和分布的基本元素,由每個(gè)列族的一個(gè)Store組成。對(duì)象層級(jí)圖如下: T...
    達(dá)微閱讀 1,582評(píng)論 0 1
  • 本文首先簡單介紹了HBase,然后重點(diǎn)講述了HBase的高并發(fā)和實(shí)時(shí)處理數(shù)據(jù) 、HBase數(shù)據(jù)模型、HBase物理...
    達(dá)微閱讀 2,827評(píng)論 1 13
  • 簡介 HBase是高可靠性,高性能,面向列,可伸縮的分布式存儲(chǔ)系統(tǒng),利用HBase技術(shù)可在廉價(jià)PC Serve...
    九世的貓閱讀 2,370評(píng)論 1 6
  • 馬上就要到畢業(yè)考試了,老師天天領(lǐng)我們做卷講卷兒,好不容易有一個(gè)放風(fēng)的時(shí)間,我和同學(xué)們對(duì)這來之不易機(jī)會(huì)倍感珍惜。相...
    圖圖2006閱讀 486評(píng)論 0 1
  • 小時(shí)候,總想著當(dāng)長大了一定要到處走走,去到與自己從小所處不同的世界去看看。 后來,因?yàn)榉N種原因,我與所想的大學(xué)失之...
    醉雪Ariel閱讀 1,465評(píng)論 0 6

友情鏈接更多精彩內(nèi)容