以往工作中HBase存儲海量數(shù)據(jù)時候幔虏,因為歷史原因主鍵使用自增長序列,數(shù)據(jù)遷移到HBase中時捂掰,并沒有改變主鍵策略敢会。導(dǎo)致數(shù)據(jù)全部寫入一個region,造成數(shù)據(jù)熱點这嚣。當時也沒有采用預(yù)分區(qū)鸥昏,數(shù)據(jù)增長過快,region過大時姐帚,在系統(tǒng)低負載時段需手動切分region吏垮。這些原因?qū)е录赫w效率低。
現(xiàn)在要求
目前正好有一個新的數(shù)據(jù)存儲場景開始設(shè)計罐旗,對數(shù)據(jù)需要增量順序讀(如:增量構(gòu)建全文索引等)膳汪,中等規(guī)模隨機讀。能按照區(qū)間范圍順序查詢九秀,并能控制查詢的開始和結(jié)束遗嗽。以方便增量或重新構(gòu)建索引或控制區(qū)間化數(shù)據(jù)讀取需求等等」难眩總結(jié)歷史經(jīng)驗和教訓(xùn)痹换, 現(xiàn)在需要考慮的2種場景:
- 海量文本數(shù)據(jù)A征字,天入庫數(shù)據(jù)量在30-200W左右,文本格式長娇豫,需要保存原文匙姜。(數(shù)量現(xiàn)對小,單文本容量比較大冯痢,需要保存原文)
- 海量文本數(shù)據(jù)B氮昧,天數(shù)據(jù)量在500w-5000w之間,文本格式短小系羞。(數(shù)量現(xiàn)對多郭计,單文本容量相對小 )
HBase基本情況
表和索引組成
HBase一般由行鍵(row key)、列鍵(column qualifier )椒振、列族(column family)組成昭伸。行鍵對應(yīng)關(guān)鍵數(shù)據(jù)庫中主鍵,HBase為行鍵建立了索引澎迎,列鍵歸屬列族庐杨。通過行鍵/列鍵/列族定位到一個唯一記錄。
HBase中使用.META內(nèi)部表存儲region的分布情況以及每個region的詳細信息夹供。region中記錄了rowkey范圍灵份,region分散在不同服務(wù)器中。通過region server提供訪問數(shù)據(jù)訪問服務(wù)哮洽,region server可服務(wù)多個region填渠,來自不同region server上的region組合成表格的整體邏輯視圖。
獲取記錄方式
- 通過get方式鸟辅,指定rowkey獲取唯一記錄
- 通過scan方式氛什,設(shè)置startRow和stopRow參數(shù)進行范圍匹配
- 通過scan方式,全表掃描匪凉,并通過RowFilter過濾出數(shù)據(jù)
基本可歸納為順序讀和隨機讀枪眉。
rowkey原則
長度原則
行鍵長度盡量短和合理,因為持久化文件HFile中使用KeyValue形式保存數(shù)據(jù)再层,column family/column qualifier/rowkey會記錄到每一條數(shù)據(jù)中贸铜,導(dǎo)致存儲文件過大,也會導(dǎo)MemStore內(nèi)存有效利用率降低聂受。rowkey使用byte[]保存數(shù)據(jù)蒿秦,使用數(shù)值(long)比字符(String)占用更小空間。64為系統(tǒng)內(nèi)存8字節(jié)對齊蛋济,控制在16個字節(jié)渤早,盡量使用8為倍數(shù)。
散列原則避免熱點
- 加鹽
在rowkey前按規(guī)則加隨機數(shù)瘫俊,使數(shù)據(jù)分散到不同region上避免熱點鹊杖。也可通過業(yè)務(wù)規(guī)則分段比如:userid-service-timestamp,把不同userid或不同業(yè)務(wù)數(shù)據(jù)切分到不同region扛芽。 - 哈希
生成哈下畋停或使用UUID散列它。 - 反轉(zhuǎn)
如果是順序序列可以反轉(zhuǎn)它川尖,讓他經(jīng)常改變的部分排到前面避免數(shù)據(jù)集中登下。時間反轉(zhuǎn)也可以考慮Long.Max_Value - timestamp。
唯一原則
主鍵都必須保證唯一叮喳。
分布式主鍵算法
分布式主鍵算法要求
- 毫秒級的快速響應(yīng)
- 可用性強
- prefix有連續(xù)性方便DB順序存儲
- 體積小被芳,8字節(jié)為佳
目前分布式主鍵算法比較
UUID
16字節(jié),JAVA自帶馍悟,好用畔濒,占用空間大。
Twitter Snowflake
Snowflake: timestamp + work id + seq number
8字節(jié)锣咒,可用性強侵状,速度快。占用空間小毅整,如果考慮復(fù)雜環(huán)境work id需要更好處理趣兄。twitter默認實現(xiàn)需要引入zookeeper 和獨立的snowflake專用服務(wù)器,UC實現(xiàn)通過配置文件確定work id悼嫉。
MongoDB ObjectId
ObjectId:timestamp + machine + pid + seq number
12字節(jié),可用性強艇潭,速度快。占用空間中等戏蔑,用空間降低實現(xiàn)復(fù)雜度蹋凝,基本沒有其他依賴。
業(yè)務(wù)rowkey設(shè)計
業(yè)務(wù)的需求
- 大文本A每分鐘最多1388條辛臊,每秒23條仙粱。
- 小文本B每分鐘最多34722條,每秒578條彻舰。
考慮到大量順序讀伐割,需要做到局部連續(xù),全局分散刃唤。每秒極端情況寫數(shù)據(jù)量不多隔心,可考慮按照分鐘分區(qū)。一共60個分區(qū)尚胞。獲取一天數(shù)據(jù)時候通過60*24=1440 按照1440個局部連續(xù)批來獲取數(shù)據(jù)硬霍。
rowkey規(guī)則1
參考snowflake和ObjectId原理,感覺它并不好直觀分區(qū)笼裳,所以:
partition + timestamp + work id+ seq number 增加分區(qū)唯卖,減少時間和work id范圍粱玲。
0-000000-01111111 10111111 11111000 00111100-00000000 0-00000000 00000000
1bit 不用
6bit 分區(qū),可支持63個分區(qū)拜轨,可使用秒或分鐘做分區(qū)
32bit 時間 System.currentTimeMillis()到秒(可以用到2099年)
9bit 區(qū)分機器和進程抽减,需要在存儲空間和復(fù)雜度上找平衡
16bit seq(最大65535)
全長64Bit,8Byte可做到不依賴其他服務(wù)橄碾。
分區(qū)可表示為:
0-000000-0000000 000000000 00000000 00000000-00000000 0-00000000 00000000
0-000001-0000000 000000000 00000000 00000000-00000000 0-00000000 00000000
0-000010-0000000 000000000 00000000 00000000-00000000 0-00000000 00000000
0-000011-0000000 000000000 00000000 00000000-00000000 0-00000000 00000000
rowkey規(guī)則2
規(guī)則1太復(fù)雜實現(xiàn)和可讀性低簡卵沉,簡化下
reverse timestamp(mmHHddMMyyyy)+ seq number(0-99999)
seq number使用redis保證全局唯一,每個客戶端使用步長減少redis訪問頻次法牲。
例如:rowkey=20170719213012345表示為:30211907201712345使用分鐘做分區(qū)30表示分區(qū)史汗。
分區(qū)可表示為:
1000000000000000L:11100011010111111010100100110001101000000000000000
3000000000000000L:111000110101111110101001001100011010000000000000000
59000000000000000L:11010001100111000010111111111001101111111000000000000000
56Bit,7Byte 依賴redis服務(wù) 簡單直觀可讀性好拒垃。
rowkey規(guī)則2順序讀取數(shù)據(jù)方式
假如我需要scan查詢2017/07/19數(shù)據(jù)停撞,我需要從201707190000~201707192359
60*24=1440做循環(huán)。2017/07/19/ 21:35為例子恶复, StartRow和StopRow設(shè)置如下:
StartRow=35211907201700000L
StopRow=35211907201799999L
最終選擇規(guī)則2作為rowkey規(guī)則怜森,隨然依賴redis服務(wù),但是存儲空間小谤牡、可讀性高副硅、可理解性好、方便使用和維護翅萤。
其他
不考慮HBase RowFilter方式恐疲,希望的效果就是直接利用rowkey內(nèi)部索引和.META表。對于其他復(fù)雜組合查詢套么,我傾向使用全文索引ES或Solr培己。
可以參考算法源碼
UC Snowflake
https://github.com/sumory/uc/blob/master/src/com/sumory/uc/id/IdWorker.java
MaongoDB ObjectID
https://github.com/mongodb/mongo-java-driver/blob/master/bson/src/main/org/bson/types/ObjectId.java
Email:wei.liu@qq.com
劉威 2017年7月19日 長沙