天天看點

Hbase熱點産生及解決辦法

HBase熱點

什麼是熱點

HBase中的行是按照rowkey的字典順序排序的,這種設計優化了scan操作,可以将相關的行以及會被一起讀取的行存取在臨近位置,便于scan。然而糟糕的rowkey設計是熱點的源頭。 熱點發生在大量的client直接通路叢集的一個或極少數個節點(通路可能是讀,寫或者其他操作)。 大量通路會使熱點region所在的單個機器超出自身承受能力,引起性能下降甚至region不可用,這 也會影響同一個RegionServer上的其他region,由于主機無法服務其他region的請求。

産生的原因

Hbase 建立表預設隻有一個分區

Rowkey 設計不合理

解決方案

Hbase 建立表時指定分區

合理設計Rowkey

Hbase 預分區

分區

HBase中,表會被劃分為1…n個Region,被托管在RegionServer中。Region二個重要的屬性:StartKey與 EndKey表示這個Region維護的rowKey範圍,當我們要讀/寫資料時,如果rowKey落在某個start-end key範圍内,那麼就會定位到目标region并且讀/寫到相關的資料。

預設地,當我們隻是通過HBaseAdmin指定TableDescriptor來建立一張表時,start-end key無邊界,region的size越來越大時,大到一定的閥值,就會找到一個midKey将region一分為二,成為2個region,這個過程稱為分裂,而midKey則為這二個region的臨界。

缺點

總是往最大start-key的region寫記錄,之前分裂出來的region不會再被寫資料,它們都處于半滿狀态

split是比較耗時耗資源

優點

合理設計rowkey 能讓各個region 的并發請求 平均配置設定(趨于均勻) 使IO 效率達到最高

預分區

shell建立

create ‘table1’,‘cf1’ ,SPLITS=>[‘10’,‘20’,‘30’,‘40’]

建立5個regin,每個region都有個startKey和endKey,第一個region沒有startKey,最後一個沒有endKey:

第一個region:" to 10"

第二個region:“10 t0 20”

第三個region:“20 t0 30”

第四個region:“30 t0 40”

第五個region:"40 t0 "

java api createTable并預分區

在hbase包的Admin類中提供了4個create表的方法(前三個為同步建立,第四個為異步):

一.直接根據描述建立表

這裡是直接根據表描述建立表,不指定分區。

void createTable(HTableDescriptor desc) throws IOException;

二.根據描述和region個數以及startKey以及endKey自動配置設定

根據表描述以及指定startKey和endKey和region個數建立表,這裡hbase會自動建立region個數,并且會為你的每一個region指定key的範圍,但是所有的範圍都是連續的且均勻的,如果業務key的某些範圍内資料量很多有的很少,這樣就會造成資料的資料的傾斜,這樣的場景就必須自己指定分區的範圍,可以用第三種或者第四種方式預分區。

void createTable(HTableDescriptor desc, byte[] startKey, byte[] endKey, int numRegions)

throws IOException;

三.根據表的描述和自定義的分區設定建立表(同步)

根據表的描述和自定義的分區設定建立表,這個就可以自己自定義指定region執行的key的範圍,比如:

byte[][] splitKeys = new byte[][] { Bytes.toBytes(“100000”),

Bytes.toBytes(“200000”), Bytes.toBytes(“400000”),

Bytes.toBytes(“500000”) };

調用接口的時候splitKeys傳入上面的值,那麼他會自動建立5個region并且為之配置設定key的分區範圍。

void createTable(final HTableDescriptor desc, byte[][] splitKeys) throws IOException;

四.根據表的描述和自定義的分區設定建立表(異步)

void createTableAsync(final HTableDescriptor desc, final byte[][] splitKeys) throws IOException;

Hbase Rowkey設計原則

rowkey長度原則

rowkey是一個二進制碼流,rowkey的長度被很多開發者建議說設計在10~100個位元組,不過建議是越短越好,不要超過16個位元組。

原因如下

資料的持久化檔案HFile中是按照KeyValue存儲的,如果Rowkey過長比如100個位元組,1000萬列資料光Rowkey就要占用100*1000萬=10億個位元組,将近1G資料,這會極大影響HFile的存儲效率.

MemStore将緩存部分資料到記憶體,如果Rowkey字段過長記憶體的有效使用率會降低,系統将無法緩存更多的資料,這會降低檢索效率。是以Rowkey的位元組長度越短越好。

目前作業系統是都是64位系統,記憶體8位元組對齊。控制在16個位元組,8位元組的整數倍利用作業系統的最佳特性。

rowkey唯一原則

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

rowkey散列原則

如果rowkey按照時間戳的方式遞增,不要将時間放在二進制碼的前面,建議将rowkey的高位作為 散列字段,由程式随機生成,低位放時間字段,這樣将提高資料均衡分布在每個RegionServer, 以實作負載均衡的幾率。如果沒有散列字段,首字段直接是時間資訊,所有的資料都會集中在一個 RegionServer上,這樣在資料檢索的時候負載會集中在個别的RegionServer上,造成熱點問題, 會降低查詢效率。

Hbase 常見避免熱點問題方法

加鹽

在rowkey的前面增加随機數。具體就是給rowkey配置設定一個随機字首以使得它和之前排序不同。配置設定的字首種類數量應該和你想使資料分散到不同的region的數量一緻。 如果你有一些熱點rowkey反複出現在其他分布均勻的rowkey 中,加鹽是很有用的。

假如你有下列 rowkey,你表中每一個 region 對應字母表中每一個字母。 以 ‘a’ 開頭是同一個 region, ‘b’開頭的是同一個region。在表中,所有以 ‘f’開頭的都在同一個 region, 它們的 rowkey 像下面這樣:

foo0001

foo0002

foo0003

foo0004

現在,假如你需要将上面這個 region 分散到 4個 region。你可以用4個不同的鹽:’a’, ‘b’, ‘c’, ‘d’. 在這個方案下,每一個字母字首都會在不同的 region 中。加鹽之後,你有了下面的 rowkey:

a-foo0003

b-foo0001

c-foo0004

d-foo0002

是以,你可以向4個不同的 region 寫,理論上說,如果所有人都向同一個region 寫的話,你将擁 有之前4倍的吞吐量。

現在,如果再增加一行,它将随機配置設定a,b,c,d中的一個作為字首,并以一個現有行作為尾部結束:

a-foo0003

b-foo0001

c-foo0003

c-foo0004

d-foo0002

因為配置設定是随機的,是以如果你想要以字典序取回資料,你需要做更多工作。加鹽這種方式增加了寫時的吞吐量,但是當讀時有了額外代價。

哈希

哈希會使同一行永遠用同一個字首加鹽。哈希也可以使負載分散到整個叢集,但是讀卻是可以預測的。使用确定的哈希可以讓用戶端重構完成的rowkey,使用Get操作擷取正常的擷取某一行資料。

翻轉

第三種防止熱點的方法時反轉固定長度或者數字格式的rowkey。這樣可以使得rowkey中經常改變 的部分(最沒有意義的部分)放在前面。這樣可以有效的随機rowkey,但是犧牲了rowkey的有序性。

反轉rowkey的例子

以手機号為rowkey,可以将手機号反轉後的字元串作為rowkey,這樣就避免了以手機号那樣比較固定開頭導緻熱點問題

繼續閱讀