1. 程式人生 > >hbase系列-Hbase熱點問題、資料傾斜和rowkey的雜湊設計

hbase系列-Hbase熱點問題、資料傾斜和rowkey的雜湊設計

1、分散式與並行處理 

分散式系統
通常,我們說分散式系統的時候,我們都會想到Dubbo框架和SpringCloud框架。這兩個框架現在應該是國內用的比較多的兩個分散式框架了,特點都是很容易把服務部署在多臺機器組成一個高可用的服務叢集來應對高併發。所以,我們通常認為分散式系統就是多臺機器組成一個叢集對外提供服務,每個請求也會被分配到叢集中的一臺或者多臺機子上完成,而使用者是感覺不同整個系統封裝的細節。
多執行緒和並行處理
  我們都知道多執行緒是怎樣的一個概念,它就是一個並行處理的例子,它是在一臺計算機並行的。但是,在我們的認識範疇中,我們所知的並行是應該同時在運作的,但是,多執行緒的概念是,多個執行緒在搶佔資源,搶到了資源的執行緒會運作,其它的執行緒在等待,所以並不是真正意義上的並行,只是因為計算機的執行速度比較快,所以我們可以認為它是並行處理的。
Hadoop的HDFS檔案系統,Hbase等分散式系統就是並行處理的,多臺機器同時執行,同時儲存和讀取資料,最後把結果返回給使用者。

2、什麼是熱點和資料傾斜
熱點發生在大量的client直接訪問叢集的一個或極少數個節點(訪問可能是讀,寫或者其他操作)。大量訪問會使熱點region所在的單個機器超出自身承受能力,引起效能下降甚至region不可用,這也會影響同一個RegionServer上的其他region,由於主機無法服務其他region的請求,造成資源浪費。設計良好的資料訪問模式以使叢集被充分,均衡的利用。 
資料傾斜:Hbase可以被劃分為多個Region,但是預設建立時只有一個Region分佈在叢集的一個節點上,資料一開始時都集中在這個Region,也就是集中在這一個節點上,就算region儲存達到臨界值時被劃分,資料也是儲存在少數節點上。這就是資料傾斜。

3、hbase的儲存方式引起的熱點問題和資料傾斜
HBase中的行是按照rowkey的字典順序排序的,這種設計優化了scan操作,可以將相關的行以及會被一起讀取的行存取在臨近位置,便於scan。
rowkey設計是熱點的源頭。
HBase中,表會被劃分為1...n個Region,被託管在RegionServer中。Region有二個重要的屬性:StartKey與EndKey表示這個Region維護的rowKey範圍,當我們要讀/寫資料時,如果rowKey落在某個start-end key範圍內,那麼就會定位到目標region並且讀/寫到相關的資料。
預設的情況下,建立一張表是,只有1個region,start-end key沒有邊界,所有資料都在這個region裡裝,然而,當資料越來越多,region的size越來越大時,大到一定的閥值,hbase認為再往這個region裡塞資料已經不合適了,就會找到一個midKey將region一分為二,成為2個region,這個過程稱為分裂(region-split)。而midKey則為這二個region的臨界(這個中間值這裡不作討論是如何被選取的)。
此時,我們假設假設rowkey小於midKey則為陰被塞到1區,大於等於midKey則會被塞到2區,如果rowkey還是順序增大的,那資料就總會往2區裡面寫資料,而1區現在處於一個被冷落的狀態,而且是半滿的。2區的資料滿了會被再次分裂成2個區,如此不斷產生被冷落而且不滿的Region,當然,這些region有提供資料查詢的功能。
這種設計是分散式系統一個很大的弊端,而且這樣導致資料傾斜和熱點問題,從而導致叢集的資源得不到很好的利用。

3、預分割槽和rowkey的雜湊設計——解決資料傾斜和熱點問題
預分割槽
預分割槽,讓表的資料可以均衡的分散在叢集中,而不是預設只有一個region分佈在叢集的一個節點上。(預分割槽個數=節點的倍數,看資料量估算,region不足了會被分列,預分割槽後每個region的rowkey還是有序的)
一個RegionServer能管理10-1000個Region,0.92.x版本後,預設的Region大小為10G,向下可以支援256MB,向上可以支援到20G,也就是說,每個RegionServer能管理的資料量為2.5GB-20TB。
如果有5個節點,3年內資料量為5T,那麼分割槽數可以預設為:
5000G/10G=500個region
這500個Region就會被均衡的分佈在叢集各個節點上(具體分佈看機器的效能和儲存空間而定),機器硬碟不足可以新增硬碟,效能不足可以新增新節點(新增新機器)。

Rowkey長度原則(最好不超過16位元組)
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位元組的整數倍利用作業系統的最佳特性。

rowkey雜湊原則
把主鍵雜湊後當成rowkey的頭部

rowkey唯一原則
必須在設計上保證其唯一性,rowkey是按照字典順序排序儲存的,因此,設計rowkey的時候,要充分利用這個排序的特點,將經常讀取的資料儲存到一塊,將最近可能會被訪問的資料放到一塊。

時間戳反轉
如果資料需要保留多個版本,可以使用反轉的時間戳作為rowkey的一部分,用 Long.Max_Value - timestamp 追加到key的末尾,例如 [key][reverse_timestamp] , [key] 的最新值可以通過scan [key]獲得[key]的第一條記錄,因為HBase中rowkey是有序的,第一條記錄是最後錄入的資料。

整個rowkey(timestamp並不是必要的,視業務而定)
rowkey=雜湊(主鍵<遞增的id\手機號碼等>)+Long.Max_Value - timestamp

4、預分割槽splitkeys選取
(1)取樣,先隨機生成一定數量的rowkey(10萬、100萬),將取樣資料按升序排序放到一個集合裡。
(2)根據預分割槽的region個數,對整個集合平均分割,即是相關的splitkeys。
(3)HBaseAdmin.createTable(HTableDescriptor tableDescriptor,byte[][] splitkeys)可以指定預分割槽的splitkey,即指定region間的rowkey臨界值。

5、Column Family列族的設計數量不宜過多(建議不設定多個)
(1)這裡必須先知道Hbase的架構設計
HBase的表是由一到多個Region組成的;
Region是由一到多個HStore組成的,HStore對應列族,也就是表中有多個CF,就會有多個個HStore;而分列的時候是根據Region的大小切分的。

(2)現在已經知道必須要先做預分割槽和key的散列了,那麼,假設表中有多個列族,也就是多個CF,對應也就有多個HStore,而此時,假設多個列族的資料分配不均衡就會出現下面情況:
如果某個Region裡面的A HStore有1000萬條資料,而B HStore裡面只有100條資料。那麼,這100條資料會被分到多個region中,讀取B HStore的資料時,跨了多個region,導致查詢效率降低。

(3)Hbase的列族設計是為了加快讀取速度的,同一個表的資料,按列族把資料劃分後,資料查詢時能縮小資料的範圍(查詢資料時指定列族),查詢效率會加快,然而,如果資料分配不均衡就會導致效率降低,所以並不建議多個列族,可以建多個表,資料量小的表Region數量也可以設定小一點。

6、一對多設計和寬表
假設,現在有使用者表和銀行卡表,一個使用者對應多張銀行卡
傳統的關係型資料(RMDB),我們會設計成兩張表,通過關聯查詢獲取資料;
如果Hbase也設計成兩張表,那麼如果想獲取使用者和銀行卡的資料,就得查詢兩次才能獲取到資料。
如果設計成一張寬表,把使用者資料放到銀行卡的表上,也就是使用者的資料被存放了多次,但是獲取資料的時候只需要查詢一次就能把使用者和使用者銀行卡的資料查詢出來。

寬表的缺點:浪費儲存空間,如果修改使用者資料,那麼是覆蓋多條資料,操作繁瑣,但是並不影響效能。

寬表的優點:查詢效率提高。

兩種設計都有優點和缺點,浪費效能還是浪費儲存空間,這需要視具體情況而定,需要作出取捨。

原始碼:https://gitee.com/boat824109722/hbase-api-demo
原文:https://blog.csdn.net/weixin_41279060/article/details/78855679