天天看點

Hbase 的rowkey的 設計

Rowkey就是行鍵,hbase是nosql資料庫,即然是資料庫,最多就是增删改查。RowKey的字典序(byte order)排序存儲,設計rowkey時,要充分利用排序存儲的這個特性,将經常一起讀取的行存儲在一起。

rowkey從字面意思看行鍵的意思,hbase可以了解為一個nosql資料庫,那麼日常最多的就是增删改查。其實在增删改查的過程中rowkey就充當了主鍵的作用,它和衆多的nosql資料庫一樣,可以唯一的辨別一行記錄。

roweky行鍵可以是任意字元串,在hbase内部,rowkey儲存為位元組數組,存儲時,資料按照rowkey的字典序排序存儲。設計rowkey時,要充分利用排序存儲這個特性,将經常一起讀取的行存儲放到一起。

rowkey的特點小結如下:

rowkey類似于主鍵,可以唯一辨別一行記錄。

由于資料按照rowkey的字典序(byte order)排序存儲,是以hbase中的資料永遠都是有序的。

rowkey可以由使用者自定指定,隻要保證這個字元串不重複就可以了:

rowkey的查詢一共有三種方式:

    1)get 通過指定單個rowkey來擷取對應的唯一一條記錄。

    2)like:通過rowkey的range來進行比對。

    4) scan:通過設定startRow和stopRow參數來進行範圍比對(注意:如果不設就是全表掃描)。

RowKey作為hbase的核心知識點,RowKey的設計會影響資料在Hbase的分布,還會影響查詢效率,RowKey的設計品質決定了Hbase的品質。關系到後期的查詢效率。

rowkey的作用:

    要了解rowkey的作用,首先我們需要知識hbase中,一個region就相當于一個資料分片,每個region都有startRowKey和stopRowKey(用來表示region存儲的rowkey範圍),hbase表裡面的資料是按照rowkey來分散存儲到不同的region裡面的。

    為了避免熱點現象,需要将資料記錄均衡的分散到不同的Region中去,是以需要rowkey滿足這種散列的特點,此外,在資料需要通過rowkey找到對應的region

    memstore和HFile中的資料都是按照rowkey的字典序排序。

    熱點現象是怎麼産生:

    hbase中的行是按照rowkey的字典排序的,這種設計優化scan操作,可以将相關的行以及會被一起讀取的行存取在監控位置,便于scan讀取。

四、熱點現象

4.1、熱點現象怎麼産生

我們知道HBase中的行是按照rowkey的字典順序排序的,這種設計優化了 scan操作,可以将相關的行以及會被一起讀取的行存取在臨近位置,便于 scan讀取。

然而萬事萬物都有兩面性,在咱們實際生産中,當大量請求通路HBase叢集的一個或少數幾個節點,造成少數RegionServer的讀寫請求過多,負載過大,而其他RegionServer負載卻很小,這樣就造成熱點現象(吐槽:其實和資料傾斜類似,還整這麼高大上的名字)。

掌握了熱點現象的概念,我們就應該知道大量的通路會使熱點Region所在的主機負載過大,引起性能下降,甚至導緻Region不可用。是以我們在向HBase中插入資料的時候,應優化RowKey的設計,使資料被寫入叢集的多個region,而不是一個。盡量均衡地把記錄分散到不同的Region中去,平衡每個Region的壓力。

其實RowKey的優化主要就是在解決怎麼避免熱點現象。那麼有哪些避免熱點現象的方法呢?各有什麼缺點?帶着問題,接着往下看。

4.2、如何避免熱點現象(RowKey的優化)

在日常使用中,主要有3個方法來避免熱點現象,分别是反轉,加鹽和哈希。聽起來很奇怪,下面咱們逐個舉例詳細分析:

4.2.1、反轉(Reversing)

第一種咱們要分析的方法是反轉,顧名思義它就是把固定長度或者數字格式的 rowkey進行反轉,反轉分為一般資料反轉和時間戳反轉,其中以時間戳反轉較常見。

适用場景:

比如咱們初步設計出的RowKey在資料分布上不均勻,但RowKey尾部的資料卻呈現出了良好的随機性(注意:随機性強代表經常改變,沒意義,但分布較好),此時,可以考慮将RowKey的資訊翻轉,或者直接将尾部的bytes提前到RowKey的開頭。反轉可以有效的使RowKey随機分布,但是反轉後有序性肯定就得不到保障了,是以它犧牲了RowKey的有序性。

缺點:

利于Get操作,但不利于Scan操作,因為資料在原RowKey上的自然順序已經被打亂。

舉例:

比如咱們通常會有需要快速擷取資料的最近版本的資料處理需求,這時候就需要把時間戳作為RowKey來查詢了,但是時間戳正常情況下是這樣的:

1588610367373

1588610367396

1

2

前面這部分是相同的,在查詢的時候就容易造成熱點現象,是以需要使用時間戳反轉的方式來處理。實際生産中可以用 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 - 結束時間]。

4.2.2、加鹽(Salting)

第二種咱們要介紹的方法是加鹽,玩過密碼學的可能知道密碼學裡也有加鹽的方法,但是咱們RowKey的加鹽和密碼學不一樣,它的原理是在原RowKey的前面添加強定長度的随機數,也就是給RowKey配置設定一個随機字首使它和之前的RowKey的開頭不同。

比如咱們設計的RowKey是有意義的,但是資料類似,随機性比較低,反轉也沒法保證随機性,這樣就沒法根據RowKey配置設定到不同的Region裡,這時候就可以使用加鹽的方式了。

需要注意随機數要能保障資料在所有Regions間的負載均衡,也就是說配置設定的随機字首的種類數量應該和你想把資料分散到的那些region的數量一緻。隻有這樣,加鹽之後的rowkey才會根據随機生成的字首分散到各個region中,避免了熱點現象。

大白話來了解就是加了鹽就嘗不到原有的味道了。因為添加的是随機數,添加後如果還基于原RowKey查詢,就無法知道随機數是什麼,那樣在查詢的時候就需要去各個可能的Region中查找,同時加鹽對于讀取是利空的。并且加鹽這種方式增加了讀寫時的吞吐量。

4.2.3、哈希(Hashing)

最後介紹大家最熟悉的哈希方法,不管是學的啥技術,都會涉及到哈希,也都大同小異,比較簡單。

這裡的哈希是基于RowKey的完整或部分資料進行Hash,而後将哈希後的值完整替換或部分替換原RowKey的字首部分。這裡說的hash常用的有MD5、sha1、sha256 或 sha512 等算法。

其實哈希和加鹽的适用場景類似,但是由于加鹽方法的字首是随機數,用原rowkey查詢時不友善,是以出現了哈希方法,由于哈希是使用各種常見的算法來計算出的字首,是以哈希既可以使負載分散到整個叢集,又可以輕松讀取資料。

與反轉類似,哈希也打亂了RowKey的自然順序,是以也不利于Scan。

五、RowKey設計原則

通過前面的分析我們應該知道了HBase中RowKey設計的重要性了,為了幫助我們設計出完美的RowKey,HBase提出了RowKey的設計原則,一共有四點:長度原則、唯一原則、排序原則,散列原則。

RowKey在字段的選擇上,需要遵循的最基本原則是唯一原則,因為RowKey必須能夠唯一的識别一行資料。無論應用的負載特點是什麼樣,RowKey字段都應該首先考慮最高頻的查詢場景。資料庫通常都是以如何高效的讀取和消費資料為目的,而不僅僅是資料存儲本身。然後再結合具體的負載特點,再對選取的RowKey字段值進行改造,結合RowKey的優化,也就是避免熱點現象的那些方法來優化就可以了。

5.1、長度原則

RowKey本質上是一個二進制碼的流,可以是任意字元串,最大長度為64kb,實際應用中一般為10-100byte,以byte[]數組形式儲存,一般設計成定長。官方建議越短越好,不要超過16個位元組,原因可以概括為如下幾點:

**影響HFile的存儲效率:**HBase裡的資料在持久化檔案HFile中其實是按照Key-Value對形式存儲的。這時候如果RowKey很長,比如達到了200byte,那麼僅僅1000w行的記錄,隻考慮RowKey就需占用近2GB的空間,極大的影響了HFile的存儲效率。

**降低檢索效率:**由于MemStore會緩存部分資料到記憶體中,如果RowKey比較長,就會導緻記憶體的有效使用率降低,也就不能緩存更多的資料,進而降低檢索效率。

**16位元組是64位作業系統的最佳選擇:**64位系統,記憶體8位元組對齊,控制在16位元組,8位元組的整數倍利用了作業系統的最佳特性。

5.2、唯一原則

其實唯一原則咱們可以結合HashMap的源碼設計或者主鍵的概念來了解,由于RowKey用來唯一辨別一行記錄,是以必須在設計上保證RowKey的唯一性。

需要注意:由于HBase中資料存儲的格式是Key-Value對格式,是以如果向HBase中同一張表插入相同RowKey的資料,則原先存在的資料會被新的資料給覆寫掉(和HashMap效果相同)。

5.3、排序原則

HBase會把RowKey按照ASCII進行自然有序排序,是以反過來我們在設計RowKey的時候可以根據這個特點來設計完美的RowKey,好好的利用這個特性就是排序原則。

5.4、散列原則

散列原則用大白話來講就是咱們設計出的RowKey需要能夠均勻的分布到各個RegionServer上。

比如設計RowKey的時候,當Rowkey 是按時間戳的方式遞增,就不要将時間放在二進制碼的前面,可以将 Rowkey 的高位作為散列字段,由程式循環生成,可以在低位放時間字段,這樣就可以提高資料均衡分布在每個Regionserver實作負載均衡的幾率。

結合前面分析的熱點現象的起因,思考: