hbase的內部使用KeyValue的形式存儲,其key時rowKey:family:column:logTime,value是其存儲的內容。html
其在region內大多以升序的形式排列,惟一的時logTime是以降序的形式進行排列。java
因此,rowKey裏越靠近左邊的信息越容易被檢索到。其設計時,要考慮把重要的信息放左邊,不重要的信息放到右邊。這樣能夠提升查詢數據的速度。最重要的提升索引速度的就是設計合適的rowKey。git
在作RowKey設計時,請先考慮業務是讀比寫多,仍是讀比寫少,HBase自己是爲寫優化的,即使是這樣,也可能會出現熱點問題,而若是咱們讀比較多的話,除了考慮以上RowKey設計原則外,還能夠考慮HBase的Coprocessor甚至elasticSearch結合的方法,不管哪一種方式,都建議作實際業務場景下數據的壓力測試以獲得最優結果。github
rowKey是一個二進制,RowKey的長度被不少開發者建議說設計在10~100個字節,以byte[]形式保存,最大不能超過64kb。建議越短越好,不要超過16個字節。sql
太長的影響有幾點點:數據庫
注意:不只RowKey的長度是越短越好,並且列簇名、列名等儘可能使用短名字,由於HBase屬於列式數據庫,這些名字都是會寫入到HBase的持久化文件HFile中去,過長的RowKey、列簇、列名都會致使總體的存儲量成倍增長。設計模式
保證rowKey的惟一性。因爲在HBase中數據存儲是Key-Value形式,若HBase中同一表插入相同RowKey,則原先的數據會被覆蓋掉(若是表的version設置爲1的話)。緩存
設計的RowKey應均勻分佈在各個HBase節點上。如RowKey是按系統時間戳的方式遞增,RowKey的第一部分若是是時間戳的話,將形成全部新數據都在一個RegionServer堆積的熱點現象,也就是一般說的Region熱點問題,熱點發生在大量的client直接訪問集中在個別RegionServer上(訪問多是讀、寫或者其餘操做),致使單個RegionServer機器自身負載太高,引發性能降低甚至Region不可用,常見的是發生jvm full gc或者顯示region too busy異常狀況。網絡
當往HBase表寫入大量數據時,須要在RegionServer上分散負載來進行優化。這並不難,可是你可能不得不在讀模式優化上付出代價。好比,時間序列數據的例子,若是你的數據直接使用時間戳作行健,在寫入時在單個region上會遇到熱點問題。併發
許多使用場景下,並不須要基於單個時間戳訪問數據。你可能要運行一個做業在一個時間區間上作聚合計算,若是對時間延遲不敏感,能夠考慮跨多個region作並行掃描來完成任務。但問題是,應該如何把數據分散在多個region上呢?有幾個選項能夠考慮,答案取決於你想讓行健包含什麼信息。
每次當你須要訪問以這個散列值爲鍵的行時,須要精確知道「TheRealMT」。時間序列數據通常不這樣處理。當你訪問數據時,可能記住了一個時間範圍,但不大可能知道精確的時間戳。可是有些狀況下,可以計算散列值從而找到正確的行。爲了獲得一種跨全部region的、優秀的分佈策略,你可使用MD五、SHA-1或者其餘提供隨機分佈的散列數。
2.salting。當你思考行健的構成時,salting是另外一種技巧。讓咱們考慮以前的時間序列數據例子。假設你在讀取時知道時間範圍,但不想作全表掃描。對時間戳作散列運算而後把散列值做爲行健的作法須要作全表掃描,這是很低效的,尤爲是在你有辦法限制掃描範圍的時候。使用散列值做爲行健在這裏不是辦法,可是你能夠在時間戳前面加上一個隨機數前綴。
例如,你能夠先計算時間戳的散列碼,而後用RegionServer的數量取模來生成隨機salt數:
取到salt數後,加到時間戳的前面生成行健:
如今行健以下所示:
你能夠想到,這些行將會基於鍵的第一部分,也就是隨機salt數,分佈在各個region。
0|timestamp1,0|timestamp5和0|timestamp6將進入一個region,除非發生region拆分(拆分的狀況下會分散到兩個region)。1|timestamp2,1|timestamp9進入另外一個不一樣的region,2|timestamp4,2|timestamp8進入第三個region。連續時間戳的數據散列進入了多個region。
但並不是一切都是完美的。如今讀操做須要把掃描命令分散到全部region上來查找相應的行。由於它們再也不存儲在一塊兒,因此一個短掃描不能解決問題了。這是一種權衡,爲了搭建成功的應用你須要作出選擇。這是一個利用信息的位置來得到跨region分佈的經典例子。
3. Reverse反轉。針對固定長度的RowKey反轉後存儲,這樣可使RowKey中常常改變的部分放在最前面,能夠有效的隨機RowKey。反轉RowKey的例子一般以手機舉例,能夠將手機號反轉後的字符串做爲RowKey,這樣就避免了以手機號那樣比較固定開頭致使熱點問題。這樣作的缺點是犧牲了RowKey的有序性。
時間戳反轉。一個常見的數據處理問題是快速獲取數據的最新版本,使用反轉的時間戳做爲RowKey的一部分對這個問題十分有用,能夠用Long.Max_Value - timestamp追加到key的末尾。舉例,在設計推帖流表時,你的焦點是爲讀優化行健,目的是把推帖流裏最新的推帖存儲在一塊兒,以便於它們能夠被快速讀取,而不用作開銷很大的硬盤搜索。在推貼流表裏,你使用倒序時間戳(Long.MAX_VALUE - 時間戳)而後附加上用戶ID來構成行健。如今你基於用戶ID掃描緊鄰的n行就能夠找到用戶須要的n條最新推帖。這裏行健的結構對於讀性能很重要。把用戶ID放在開頭有助於你設置掃描,能夠輕鬆定義起始鍵。
設計模式:反轉+時間戳反轉
RowKey:reverser(order_id) + (Long.MAX_VALUE - timestamp)
這樣設計的好處一是經過reverse訂單號避免Region熱點,二是能夠按時間倒排顯示,能夠獲取到最新的訂單。
一樣適用於須要保存一個用戶的操做記錄,按照操做時間倒序排序。設計的rowKey爲:reverser(userId) + (Long.MAX_VALUE - timestamp)。若是須要查詢某段時間的操做記錄,startRow是[userId反轉][Long.MAX_VALUE - 起始時間],stopRow是[userId反轉][Long.MAX_VALUE - 結束時間]。
HBase只存儲了最近10分鐘的熱數據
設計模式:salt加鹽
RowKey:兩位隨機數Salt + eventId + Date + kafka的Offset
這樣設計的好處是:設計加鹽的目的是爲了增長查詢的併發性,假如Salt的範圍是0~n,那咱們在查詢的時候,能夠將數據分爲n個split同時作scan操做。通過咱們的屢次測試驗證,增長併發度可以將總體的查詢速度提高5~20倍以上。隨後的eventId和Date是用來作範圍Scan來使用的。在咱們的查詢場景中,大部分都是指定了eventId的,所以咱們在eventId放在了第二個位置上,同時呢,經過Salt + eventId的方式能夠保證不會造成熱點。把date放在RowKey的第三個位置上能夠實現date作scan,批量Scan性能甚至能夠作到毫秒級返回。
這樣的RowKey設計可以很好的支持以下幾個查詢場景:
數據庫查詢可簡單分解爲兩個步驟:1)鍵的查找;2) 數據的查找
因這兩種數據組織方式的不一樣,在RDBMS領域有兩種常見的數據組織表結構:
索引組織表:鍵與數據存放在一塊兒,查找到鍵所在的位置則意味着查找到數據自己。
堆表:鍵的存儲與數據的存儲是分離的。查找到鍵的位置,只能獲取到數據的物理地址,還須要基於該地址去獲取數據。
HBase數據表實際上是一種索引組織表結構:查找到RowKey所在的位置則意味着找到數據自己。所以,RowKey自己就是一種索引。
若是提供的查詢條件可以儘量豐富的描述RowKey的前綴信息,則查詢時延越能獲得保障。以下面幾種組合條件場景:
* Name + Phone + ID
* Name + Phone
* Name
若是查詢條件不能提供Name信息,則RowKey的前綴條件是沒法肯定的,此時只能經過全表掃描的方式來查找結果。
一種業務模型的用戶數據RowKey,只能採用單一結構設計。但事實上,查詢場景多是多緯度的。例如,在上面的場景基礎上,還須要單獨基於Phone列進行查詢。這是HBase二級索引出現的背景。即,二級索引是爲了讓HBase可以提供更多緯度的查詢能力。
注:HBase原生並不支持二級索引方案,但基於HBase的KeyValue數據模型與API,能夠輕易的構建出二級索引數據。Phoenix提供了兩種索引方案,而一些大廠家也都提供了本身的二級索引實現。
從0.94版本,HBase官方文檔已經提出了HBase上面實現二級索引的一種路徑:
業界比較知名的基於Coprocessor的開源方案:
Apache Phoenix在目前開源的方案中,是一個比較優的選擇,主打SQL On HBase,基於SQL能完成HBase的CRUD操做,支持JDBC協議。
選擇不基於Coprocessor開發,自行在外部構建和維護索引關係也是另一種方式。
常見的是採用底層基於Apache Lucene的ElasticSearch(下面簡稱ES)或Apache Solr,來構建強大的索引能力、搜索能力,例如支持模糊查詢、全文檢索、組合查詢、排序等。
其實對於在外部自定義構建二級索引的方式,有本身的大數據團隊的公司通常都會針對本身的業務場景進行優化,自行構建ES/Solr的搜索集羣。例如數說故事企業內部的百億級數據全量庫,就是基於ES構建海量索引和檢索能力的案例。主要有優化點包括:
下面顯示了數說基於ES作二級索引的兩種構建流程,包含:
數據查詢流程:
HBase表設計一般能夠是寬表(wide table)模式,即一行包括不少列。一樣的信息也能夠用高表(tall table)形式存儲,一般高表的性能比寬表要高出50%以上,因此推薦你們使用高表來完成表設計。表設計時,咱們也應該要考慮HBase數據庫的一些特性:
參考資料:
《HBase實戰》
https://www.cnblogs.com/parent-absent-son/p/10200202.html
https://blog.csdn.net/wangshuminjava/article/details/80575864
https://www.cnblogs.com/yuguoshuo/p/6265649.html
http://www.nosqlnotes.com/technotes/hbase/hbase-rowkey/
https://zhuanlan.zhihu.com/p/43972378