【HBase】热点现象及 RowKey 设计(转)
原文鏈接:https://blog.csdn.net/qq_26803795/article/details/105994960?spm=a2c6h.12873639.0.0.62201019lo19Jq
RowKey 作為 HBase 的核心知識點,RowKey 設計會影響到數據在 HBase 中的分布,還會影響我們查詢效率,所以 RowKey 的設計質量決定了 HBase 的質量。是大數據從業者必知必會的,自然也是面試必問的考察點。
那么 Rowkey 到底是什么呢?原理是什么呢?怎么設計 RowKey 呢?使用場景是怎樣的呢?有哪些設計原則呢?又如何進行優化呢?
下面就讓我們帶著這些問題,一起探索 RowKey 的世界!
1.RowKey 的概念
RowKey 從字面意思來看是行鍵的意思,咱們知道 HBase 可以理解為一個nosql(not only sql)數據庫,既然是數據庫,那么咱們日常使用最多的就是增刪改查(curd)。其實在增刪改查的過程中 RowKey 就充當了主鍵的作用,它和眾多的 nosql 數據庫一樣,可以唯一的標識一行記錄。
RowKey 行鍵 (RowKey)可以是任意字符串,在 HBase 內部,RowKey 保存為字節數組。存儲時,數據按照 RowKey 的字典序(byte order)排序存儲。設計RowKey時,要充分利用排序存儲這個特性,將經常一起讀取的行存儲放到一起。
RowKey 的特點小結如下:
知識點補充:在 HBase 中檢索數據時使用到 RowKey 的一共有三種方式:
- get:通過指定單個RowKey來獲取對應的唯一一條記錄;
- like:通過RowKey的range來進行匹配;
- scan:通過設置startRow和stopRow參數來進行范圍匹配(注意:如果不設置就是全表掃描)。
2.RowKey 的作用
要了解 RowKey 的作用,首先我們需要知道在 HBase 中,一個 Region 就相當于一個數據分片,每個 Region 都有 StartRowKey 和 StopRowKey(用來表示 Region 存儲的 RowKey 的范圍),HBase 表里面的數據是按照 RowKey 來分散存儲到不同的 Region 里面的。
為了避免熱點現象咱們需要將數據記錄均衡的分散到不同的 Region 中去,因此需要 RowKey 滿足這種散列的特點。此外,在數據讀寫過程中也是與 RowKey 密切相關的。RowKey 的作用可以歸納如下:
那到底啥是熱點現象呢?咱們接著分析!
3.熱點現象
3.1 熱點現象怎么產生
我們知道 HBase 中的行是按照 Rowkey 的字典順序排序的,這種設計優化了 scan操作,可以將相關的行以及會被一起讀取的行存取在臨近位置,便于 scan 讀取。
然而萬事萬物都有兩面性,在咱們實際生產中,當大量請求訪問 HBase 集群的一個或少數幾個節點,造成少數 RegionServer 的讀寫請求過多,負載過大,而其他 RegionServer 負載卻很小,這樣就造成熱點現象(吐槽:其實和數據傾斜類似,還整這么高大上的名字)。
掌握了熱點現象的概念,我們就應該知道大量的訪問會使熱點 Region 所在的主機負載過大,引起性能下降,甚至導致 Region 不可用。所以我們在向 HBase 中插入數據的時候,應優化 RowKey 的設計,使數據被寫入集群的多個 region,而不是一個。盡量均衡地把記錄分散到不同的 Region 中去,平衡每個 Region 的壓力。
其實 RowKey 的優化主要就是在解決怎么避免熱點現象。那么有哪些避免熱點現象的方法呢?各有什么缺點?帶著問題,接著往下看。
3.2 如何避免熱點現象(RowKey的優化)
在日常使用中,主要有3個方法來避免熱點現象,分別是反轉,加鹽和哈希。聽起來很奇怪,下面咱們逐個舉例詳細分析:
3.2.1 反轉(Reversing)
第一種咱們要分析的方法是反轉,顧名思義它就是把固定長度或者數字格式的 rowkey 進行反轉,反轉分為一般數據反轉和時間戳反轉,其中以時間戳反轉較常見。
適用場景:
比如咱們初步設計出的 RowKey 在數據分布上不均勻,但 RowKey 尾部的數據卻呈現出了良好的隨機性(注意:隨機性強代表經常改變,沒意義,但分布較好),此時,可以考慮將 RowKey 的信息翻轉,或者直接將尾部的 bytes 提前到 RowKey 的開頭。
反轉可以有效的使 RowKey 隨機分布,但是反轉后有序性肯定就得不到保障了,因此它犧牲了 RowKey 的有序性。
缺點:
利于 Get 操作,但不利于 Scan 操作,因為數據在原 RowKey 上的自然順序已經被打亂。
舉例:
比如咱們通常會有需要快速獲取數據的最近版本的數據處理需求,這時候就需要把時間戳作為 RowKey 來查詢了,但是時間戳正常情況下是這樣的:
1588610367373 1588610367396 12前面這部分是相同的,在查詢的時候就容易造成熱點現象,因此需要使用時間戳反轉的方式來處理。實際生產中可以用 Long.Max_Value - timestamp 追加到 key 的末尾,比如 [key][reverse_timestamp], [key] 的最新值可以通過 scan [key]獲得[key]的第一條記錄,因為 HBase 中 RowKey 是有序的,所以第一條記錄是最后錄入的數據。
常見的場景,比如需要保存一個用戶的操作記錄,就可以按照操作時間倒序排序,在設計 rowkey 的時候,可以這樣設計 [反轉后的userId][Long.Max_Value - timestamp],在查詢用戶的所有操作記錄數據的時候,直接指定反轉后的 userId,startRow 是 [反轉后的userId][000000000000],stopRow 是 [反轉后的userId][Long.Max_Value - timestamp]。如果需要查詢某段時間的操作記錄,startRow 是[反轉后的userId[Long.Max_Value - 起始時間], stopRow 是[反轉后的userId][Long.Max_Value - 結束時間]。
3.2.2 加鹽(Salting)
第二種咱們要介紹的方法是加鹽,玩過密碼學的可能知道密碼學里也有加鹽的方法,但是咱們 RowKey 的加鹽和密碼學不一樣,它的原理是在原 RowKey 的前面添加固定長度的隨機數,也就是給 RowKey 分配一個隨機前綴使它和之前的 RowKey 的開頭不同。
適用場景:
比如咱們設計的 RowKey 是有意義的,但是數據類似,隨機性比較低,反轉也沒法保證隨機性,這樣就沒法根據 RowKey 分配到不同的 Region 里,這時候就可以使用加鹽的方式了。
需要注意隨機數要能保障數據在所有 Regions 間的負載均衡,也就是說分配的隨機前綴的種類數量應該和你想把數據分散到的那些 region 的數量一致。只有這樣,加鹽之后的 rowkey 才會根據隨機生成的前綴分散到各個 region 中,避免了熱點現象。
缺點:
大白話來理解就是加了鹽就嘗不到原有的味道了。因為添加的是隨機數,添加后如果還基于原 RowKey 查詢,就無法知道隨機數是什么,那樣在查詢的時候就需要去各個可能的 Region 中查找,同時加鹽對于讀取是利空的。并且加鹽這種方式增加了讀寫時的吞吐量。
3.2.3 哈希(Hashing)
最后介紹大家最熟悉的哈希方法,不管是學的啥技術,都會涉及到哈希,也都大同小異,比較簡單。
這里的哈希是基于 RowKey 的完整或部分數據進行 Hash,而后將哈希后的值完整替換或部分替換原 RowKey 的前綴部分。這里說的hash常用的有MD5、sha1、sha256 或 sha512 等算法。
適用場景:
其實哈希和加鹽的適用場景類似,但是由于加鹽方法的前綴是隨機數,用原 rowkey 查詢時不方便,因此出現了哈希方法,由于哈希是使用各種常見的算法來計算出的前綴,因此哈希既可以使負載分散到整個集群,又可以輕松讀取數據。
缺點:
與反轉類似,哈希也打亂了 RowKey 的自然順序,因此也不利于 Scan。
4.RowKey設計原則
通過前面的分析我們應該知道了 HBase 中 RowKey 設計的重要性了,為了幫助我們設計出完美的 RowKey,HBase 提出了 RowKey的設計原則,一共有四點:長度原則、唯一原則、排序原則,散列原則。
RowKey 在字段的選擇上,需要遵循的最基本原則是唯一原則,因為 RowKey 必須能夠唯一的識別一行數據。無論應用的負載特點是什么樣,RowKey 字段都應該首先考慮最高頻的查詢場景。數據庫通常都是以如何高效的讀取和消費數據為目的,而不僅僅是數據存儲本身。然后再結合具體的負載特點,再對選取的 RowKey 字段值進行改造,結合 RowKey 的優化,也就是避免熱點現象的那些方法來優化就可以了。
4.1 長度原則
RowKey 本質上是一個二進制碼的流,可以是任意字符串,最大長度為64kb,實際應用中一般為10-100byte,以byte[]數組形式保存,一般設計成定長。官方建議越短越好,不要超過16個字節,原因可以概括為如下幾點:
4.2 唯一原則
其實唯一原則咱們可以結合 HashMap 的源碼設計或者主鍵的概念來理解,由于 RowKey 用來唯一標識一行記錄,所以必須在設計上保證 RowKey 的唯一性。
需要注意:由于 HBase 中數據存儲的格式是 Key-Value 對格式,所以如果向 HBase 中同一張表插入相同 RowKey 的數據,則原先存在的數據會被新的數據給覆蓋掉(和HashMap效果相同)。
4.3 排序原則
HBase 會把 RowKey 按照 ASCII 進行自然有序排序,所以反過來我們在設計 RowKey 的時候可以根據這個特點來設計完美的RowKey,好好的利用這個特性就是排序原則。
4.4 散列原則
散列原則用大白話來講就是咱們設計出的 RowKey 需要能夠均勻的分布到各個 RegionServer 上。
比如設計 RowKey 的時候,當 Rowkey 是按時間戳的方式遞增,就不要將時間放在二進制碼的前面,可以將 Rowkey 的高位作為散列字段,由程序循環生成,可以在低位放時間字段,這樣就可以提高數據均衡分布在每個 Regionserver 實現負載均衡的幾率。
結合前面分析的熱點現象的起因,思考:
如果沒有散列字段,首字段只有時間信息,那就會出現所有新數據都在一個 RegionServer上堆積的熱點現象,這樣在做數據檢索的時候負載將會集中在個別 RegionServer上,不分散,就會降低查詢效率。
HBase 里的 RowKey 是按照字典序存儲,因此在設計 RowKey 時,咱們要充分利用這個排序特點,將經常一起讀取的數據存儲到一塊,將最近可能會被訪問的數據放在一塊。如果最近寫入 HBase 表中的數據是最可能被訪問的,可以考慮將時間戳作為 row key 的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE - timestamp作為 row key,這樣能保證新寫入的數據在讀取時可以被快速找到。
總結
看到這里 RowKey 的各個方面應該都已經搞懂了,本文從 RowKey 的原理,可能出現的問題,如何優化及各個優化措施對應的缺點和適用的場景,設計原則等角度對 RowKey 進行了詳細全面的解析,相信一定能對你有所幫助。
總結
以上是生活随笔為你收集整理的【HBase】热点现象及 RowKey 设计(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何防止uniswap/pancakes
- 下一篇: 解决PyQt5程序报错Process f