2. RowKey行鍵設計規范
2.1. RowKey四大特性
2.1.1 字符串類型
雖然行鍵在HBase中是以byte[]字節數組的形式存儲的,但是建議在系統開發過程中將其數據類型設置為String類型,保證通用性;如果在開發過程中將RowKey規定為其他類型,譬如Long型,那么數據的長度將可能受限於編譯環境等所規定的數據長度。
常用的行鍵字符串有以下幾種:
- 純數字字符串,譬如9559820140512;
- 數字+特殊分隔符,譬如95598-20140512;
- 數字+英文字母,譬如city20140512;
- 數字+英文字母+特殊分隔符,譬如city_20140512。
2.1.2 有明確意義
RowKey的主要作用是為了進行數據記錄的唯一性標示,但是唯一性並不是其全部,具有明確意義的行鍵對於應用開發、數據檢索等都具有特殊意義。譬如上面的數字字符串9559820140512,其實際意義是這樣:95598(電網客服電話)+20140512(日期)。
行鍵往往由多個值組合而成,而各個值的位置順序將影響到數據存儲和檢索效率,所以在設計行鍵時,需要對日后的業務應用開發有比較深入的了解和前瞻性預測,才能設計出可盡量高效率檢索的行鍵。
2.1.3 具有有序性
RowKey是按照字典序存儲,因此,設計RowKey時,要充分利用這個排序特點,將經常一起讀取的數據存儲到一塊,將最近可能會被訪問的數據放在一塊。
舉個例子:如果最近寫入HBase表中的數據是最可能被訪問的,可以考慮將時間戳作為RowKey的一部分,由於是字典序排序,所以可以使用Long.MAX_VALUE – timestamp作為RowKey,這樣能保證新寫入的數據在讀取時可以被快速命中。
2.1.4 具有定長性
行鍵具有有序性的基礎便是定長,譬如20140512080500、20140512083000,這兩個日期時間形式的字符串是遞增的,不管后面的秒數是多少,我們都將其設置為14位數字形式,如果我們把后面的0去除了,那么201405120805將大於20140512083,其有序性發生了變更。所以我們建議,行鍵一定要設計成定長的。
2.2. RowKey設計原則
2.2.1 RowKey長度原則
Rowkey是一個二進制碼流,Rowkey的長度被很多開發者建議說設計在10~100個字節,不過建議是越短越好,不要超過16個字節。
原因如下:
(1)數據的持久化文件HFile中是按照KeyValue存儲的,如果Rowkey過長比如100個字節,1000萬列數據光Rowkey就要占用100*1000萬=10億個字節,將近1G數據,這會極大影響HFile的存儲效率;
(2)MemStore將緩存部分數據到內存,如果Rowkey字段過長內存的有效利用率會降低,系統將無法緩存更多的數據,這會降低檢索效率。因此Rowkey的字節長度越短越好。
(3)目前操作系統是都是64位系統,內存8字節對齊。控制在16個字節,8字節的整數倍利用操作系統的最佳特性。
2.2.2 RowKey散列原則
如果Rowkey是按時間戳的方式遞增,不要將時間放在二進制碼的前面,建議將Rowkey的高位作為散列字段,由程序循環生成,低位放時間字段,這樣將提高數據均衡分布在每個Regionserver實現負載均衡的幾率。如果沒有散列字段,首字段直接是時間信息將產生所有新數據都在一個RegionServer上堆積的熱點現象,這樣在做數據檢索的時候負載將會集中在個別RegionServer,降低查詢效率。
2.2.3 RowKey唯一原則
必須在設計上保證其唯一性。
2.3. RowKey應用場景
基於Rowkey的上述3個原則,應對不同應用場景有不同的Rowkey設計建議。
2.3.1 針對事務數據的RowKey設計
事務數據是帶時間屬性的,建議將時間信息存入到Rowkey中,這有助於提示查詢檢索速度。對於事務數據建議缺省就按天為數據建表,這樣設計的好處是多方面的。按天分表后,時間信息就可以去掉日期部分只保留小時分鍾毫秒,這樣4個字節即可搞定。加上散列字段2個字節一共6個字節即可組成唯一Rowkey。如下圖所示:
事務數據Rowkey設計 |
||||||
第0字節 |
第1字節 |
第2字節 |
第3字節 |
第4字節 |
第5字節 |
… |
散列字段 |
時間字段(毫秒) |
擴展字段 |
||||
0~65535(0x0000~0xFFFF) |
0~86399999(0x00000000~0x05265BFF) |
這樣的設計從操作系統內存管理層面無法節省開銷,因為64位操作系統是必須8字節對齊。但是對於持久化存儲中Rowkey部分可以節省25%的開銷。也許有人要問為什么不將時間字段以主機字節序保存,這樣它也可以作為散列字段了。這是因為時間范圍內的數據還是盡量保證連續,相同時間范圍內的數據查找的概率很大,對查詢檢索有好的效果,因此使用獨立的散列字段效果更好,對於某些應用,我們可以考慮利用散列字段全部或者部分來存儲某些數據的字段信息,只要保證相同散列值在同一時間(毫秒)唯一。
2.3.2 針對統計數據的RowKey設計
統計數據也是帶時間屬性的,統計數據最小單位只會到分鍾(到秒預統計就沒意義了)。同時對於統計數據我們也缺省采用按天數據分表,這樣設計的好處無需多說。按天分表后,時間信息只需要保留小時分鍾,那么0~1400只需占用兩個字節即可保存時間信息。由於統計數據某些維度數量非常龐大,因此需要4個字節作為序列字段,因此將散列字段同時作為序列字段使用也是6個字節組成唯一Rowkey。如下圖所示:
統計數據Rowkey設計 |
||||||
第0字節 |
第1字節 |
第2字節 |
第3字節 |
第4字節 |
第5字節 |
… |
散列字段(序列字段) |
時間字段(分鍾) |
擴展字段 |
||||
0x00000000~0xFFFFFFFF) |
0~1439(0x0000~0x059F) |
同樣這樣的設計從操作系統內存管理層面無法節省開銷,因為64位操作系統是必須8字節對齊。但是對於持久化存儲中Rowkey部分可以節省25%的開銷。預統計數據可能涉及到多次反復的重計算要求,需確保作廢的數據能有效刪除,同時不能影響散列的均衡效果,因此要特殊處理。
2.3.3 針對通用數據的RowKey設計
通用數據采用自增序列作為唯一主鍵,用戶可以選擇按天建分表也可以選擇單表模式。這種模式需要確保同時多個入庫加載模塊運行時散列字段(序列字段)的唯一性。可以考慮給不同的加載模塊賦予唯一因子區別。設計結構如下圖所示。
通用數據Rowkey設計 |
||||
第0字節 |
第1字節 |
第2字節 |
第3字節 |
… |
散列字段(序列字段) |
擴展字段(控制在12字節內) |
|||
0x00000000~0xFFFFFFFF) |
可由多個用戶字段組成 |
2.3.4 支持多條件查詢的RowKey設計
HBase按指定的條件獲取一批記錄時,使用的就是scan方法。 scan方法有以下特點:
(1)scan可以通過setCaching與setBatch方法提高速度(以空間換時間);
(2)scan可以通過setStartRow與setEndRow來限定范圍。范圍越小,性能越高。
通過巧妙的RowKey設計使我們批量獲取記錄集合中的元素挨在一起(應該在同一個Region下),可以在遍歷結果時獲得很好的性能。
(3)scan可以通過setFilter方法添加過濾器,這也是分頁、多條件查詢的基礎。
在滿足長度、三列、唯一原則后,我們需要考慮如何通過巧妙設計RowKey以利用scan方法的范圍功能,使得獲取一批記錄的查詢速度能提高。
作者:商兵兵
單位:河南省電力科學研究院智能電網所
QQ:52190634