1、rowKey設計原則:
(1)rowkey 長度原則:
rowkey是一個二進制碼流,可以為任意字符串,最大長度為64kb,實際應用中一般為10-100bytes,它以byte[]形式保存,一般設定成定長。一般越短越好,不要超過16個字節,注意原因如下:
1、目前操作系統都是64位系統,內存8字節對齊,控制在16字節,8字節的整數倍利用了操作系統的最佳特性。
2、hbase將部分數據加載到內存當中,如果rowkey過長,內存的有效利用率就會下降。
(2)rowkey 散列原則:
如果rowkey按照時間戳的方式遞增,不要將時間放在二進制碼的前面,建議將rowkey的高位字節采用散列字段處理,由程序隨即生成。低位放時間字段,這樣將提高數據均衡分布,各個regionServer負載均衡的幾率。
如果不進行散列處理,首字段直接使用時間信息,所有該時段的數據都將集中到一個regionServer當中,這樣當檢索數據時,負載會集中到個別regionServer上,造成熱點問題,會降低查詢效率。
(3)rowkey 唯一原則:
必須在設計上保證其唯一性,rowkey是按照字典順序排序存儲的,因此,設計rowkey的時候,要充分利用這個排序的特點,將經常讀取的數據存儲到一塊,將最近可能會被訪問的數據放到一塊。但是這里的量不能太大,如果太大需要拆分到多個節點上去。
所以良好的rowkey設計,應當遵循三大原則,並且能讓數據分散,從而避免熱點問題。
2、rowKey設計方法:
(1)加鹽:
這里所說的加鹽並非密碼學中的加鹽,而是在rowkey的前面分配隨機數,當給rowkey隨機前綴后,它就能分布到不同的region中,這里的前綴應該和你想要數據分散的不同的region的數量有關。
為了讓同學們更好的理解加鹽(salting)這個rowkey設計方法。我們以電信公司為例。當我們去電信公司打印電話詳單也就是通話記錄。對於通話記錄來說,每個人每月可能都有很多通話記錄,而使用電信的用戶也是億計。這種信息,我們就能存入hbase當中。
對於通話記錄,我們有什么信息需要保存呢?首先,肯定應該有主叫和被叫,然后有主叫被叫之間的通話時長,以及通話時間。除此之外,還應該有主叫的位置信息,和被叫的位置信息。
由此,我們的通話記錄表需要記錄的信息就出來了:主叫、被叫、時長、時間、主叫位置、被叫位置。
我們該如何來設計一張hbase表呢?首先,hbase表是依靠rowkey來定位的,我們應該將盡可能多的將查詢的信息編入rowkey當中。hbase的元數據表mate表就給我們了一個很好的示例。它包括了namespace,表名,startKey,時間戳,計算出來的碼(用於分散數據)。
所以,當我們設計通話記錄的rowkey時,需要將能唯一確定該條記錄的數據編入rowkey當中。即是需要將主叫、被叫、時間編入。
如下所示:
17765657979 18688887777 201806121502 #主叫,被叫,時間
但是我們能否將我們設計的rowkey真正應用呢?當然是可以的,但是熱點問題便會隨之而來。
例如你的電話是以177開頭,電信的hbase集群有500台,你的數據就只可能被存入一台或者兩台機器的region當中,當你需要打印自己的通話記錄時,就只有一台機器為你服務。而若是你的數據均勻分散到500機器中,就是整個集群為你服務。兩者之間效率速度差了不止一個數量級。
注意:由於我們的regionServer就只有一台,沒有集群環境,所以我們只介紹方法和理論操作,不提供實際結果
因為我們設定整個hbase集群有500台,所以我們隨機在0-499之間中隨機數字,添加到rowkey首部。
如下所示:
12 17765657979 18688887777 201806121502 #隨機數,主叫,被叫,時間
在插入數據時,判斷首部隨機數字,選擇對應的region存入,由於rowkey首部數字隨機,所以數據也將隨機分布到不同的regionServer中。這樣就能很好的避免熱點問題了。
補充:
1、加鹽后的數據如何讀取
https://blog.csdn.net/qq_22473611/article/details/103781548
(2)預分區
通常hbase會自動處理region拆分,當region的大小到達一定閾值后,region將被拆分成兩個,之后在兩個region都能繼續增長數據。
然而在這個過程當中,會出現兩個問題:
第一點,就是我們所說的熱點問題,數據會繼續往一個region中寫,出現寫熱點問題;
第二點,則是拆分合並風暴,當用戶的region大小以恆定的速度增長,region的拆分會在同一時間發生,因為同時需要壓縮region中的存儲文件,這個過程會重寫拆分后的region,這將會引起磁盤I/O上升 。
壓縮:hbase支持大量的壓縮算法,而且通常開啟壓縮,因為cpu壓縮和解壓的時間比從磁盤讀寫數據的時間消耗的更短,所以壓縮會帶來性能的提升。
對於拆分合並風暴,通常我們需要關閉hbase的自動管理拆分。然后手動調用hbase的split(拆分)和major_compact(壓縮),對其進行時間控制,來分散I/O負載。但是其中的split操作同樣是高I/O的操作。
為了解決這些問題,預分區就是一種很好的方法,通常它和加鹽結合起來使用。
所謂預分區,就是預先創建hbase表分區。這需要我們明確rowkey的取值范圍和構成邏輯。
比如前面我們所列舉的電信電話詳單表。通過加鹽我們得到的 rowkey構成是:隨機數+主叫+被叫+時間,如果我們現在並沒有500台機器,只有10台,但是按照我們的計划,未來將擴展到500台的規模。所以我們仍然設計0到499的隨機數,但是將以主叫177開頭的通話記錄分配到十個region當中,所以我們將隨機數均分成十個區域,范圍如下:
-50,50-100,100-150,150-200,200-250,250-300,300-350,350-400,400-450,450-
然后我們將我們的預分區存入數組當中,當插入數據時,先根據插入數據的首部隨機數,判斷分區位置,再進行插入數據。同樣,這樣也能使得各台節點負載均衡。
(3)哈希
細心的同學可能會發現,在我們剛剛提出的加鹽與預分區rowkey設計方法中,並沒有完整運用到rowkey設計的散列原則。
更一步思考下,我們會發現如果只運用加鹽與預分區rowkey設計方法,數據會真正無序隨即分布在hbase集群當中,這並沒有讓我們利用到hbase根據字典順序排序的這一特點。
由此,哈希這一設計理念便順理成章的出現在我們眼前。
同樣以電信通話記錄為例,我們想將某一天的通話記錄存入同一region當中,所以我們利用哈希函數算出哈希值,再模以我們需要存入region數量,我們就能將相同輸入的數據,存入同一region當中。
在主叫,被叫,時間rowkey當中,我們將callerID(主叫)與 20180612(某一天的時間)作為參賽,傳入哈希函數當中,將得到的哈希值模以500,余數添加到rowkey首部中,再結合預分區設計方法,就能將數據均勻分布到regionServer當中。
同時,我們還能將相同rowkey的數據收集到一台節點上,在避免熱點問題的情況下,充分利用hbase字典排序的優點。
(4)反轉
對於以手機號碼這樣比較固定開頭的rowkey(例如開頭177,159,138),但是它的后幾位都是隨機的,沒有規律的。我們可以將手機號反轉之后作為rowkey,這樣就避免了熱點問題。
這就是rowkey設計的另一種方法反轉,通過反轉固定長度或者數字格式的rowkey。這樣可以使得rowkey中經常改變的部分(最沒有意義的部分)放在前面。這樣可以有效的隨機rowkey,但是犧牲了rowkey的有序性。
3、row key設計實例
使用HBase查詢訂單歷史:
轉發博客:https://blog.csdn.net/qq_38180223/article/details/80864778