1. 程式人生 > >HBase學習之路 (十)HBase表的設計原則

HBase學習之路 (十)HBase表的設計原則

建議 ima 是否 屬性 循環 列族 將在 serve sch

建表高級屬性

  下面幾個 shell 命令在 hbase 操作中可以起到很大的作用,且主要體現在建表的過程中,看 下面幾個 create 屬性

1、 BLOOMFILTER

  默認是 NONE 是否使用布隆過慮及使用何種方式,布隆過濾可以每列族單獨啟用 使用 HColumnDescriptor.setBloomFilterType(NONE | ROW | ROWCOL) 對列族單獨啟用布隆

  Default = ROW 對行進行布隆過濾

  對 ROW,行鍵的哈希在每次插入行時將被添加到布隆

  對 ROWCOL,行鍵 + 列族 + 列族修飾的哈希將在每次插入行時添加到布隆

  使用方法: create ‘table‘,{BLOOMFILTER =>‘ROW‘}

  作用:用布隆過濾可以節省讀磁盤過程,可以有助於降低讀取延遲

2、 VERSIONS

  默認是 1 這個參數的意思是數據保留 1 個 版本,如果我們認為我們的數據沒有這麽大 的必要保留這麽多,隨時都在更新,而老版本的數據對我們毫無價值,那將此參數設為 1 能 節約 2/3 的空間

  使用方法: create ‘table‘,{VERSIONS=>‘2‘}

  附:MIN_VERSIONS => ‘0‘是說在 compact 操作執行之後,至少要保留的版本

3、 COMPRESSION

  默認值是 NONE 即不使用壓縮,這個參數意思是該列族是否采用壓縮,采用什麽壓縮算 法,方法: create ‘table‘,{NAME=>‘info‘,COMPRESSION=>‘SNAPPY‘} ,建議采用 SNAPPY 壓縮算 法 ,HBase 中,在 Snappy 發布之前(Google 2011 年對外發布 Snappy),采用的 LZO 算法,目標是達到盡可能快的壓縮和解壓速度,同時減少對 CPU 的消耗;

  在 Snappy 發布之後,建議采用 Snappy 算法(參考《HBase: The Definitive Guide》),具體 可以根據實際情況對 LZO 和 Snappy 做過更詳細的對比測試後再做選擇。

技術分享圖片

  如果建表之初沒有壓縮,後來想要加入壓縮算法,可以通過 alter 修改 schema

4、 TTL

  默認是 2147483647 即:Integer.MAX_VALUE 值大概是 68 年,這個參數是說明該列族數據的存活時間,單位是 s

  這個參數可以根據具體的需求對數據設定存活時間,超過存過時間的數據將在表中不在 顯示,待下次 major compact 的時候再徹底刪除數據

  註意的是 TTL 設定之後 MIN_VERSIONS=>‘0‘ 這樣設置之後,TTL 時間戳過期後,將全部 徹底刪除該 family 下所有的數據,如果 MIN_VERSIONS 不等於 0 那將保留最新的 MIN_VERSIONS 個版本的數據,其它的全部刪除,比如 MIN_VERSIONS=>‘1‘ 屆時將保留一個 最新版本的數據,其它版本的數據將不再保存。

5、 alter

使用方法:

  如 修改壓縮算法

disable table

alter table,{NAME=>info,COMPRESSION=>snappy}

enable table

  但是需要執行 major_compact ‘table‘ 命令之後 才會做實際的操作。

6、 describe/desc

  這個命令查看了 create table 的各項參數或者是默認值。

  使用方式:describe ‘user_info‘

7、 disable_all/enable_all

  disable_all ‘toplist.*‘ disable_all 支持正則表達式,並列出當前匹配的表的如下:

 toplist_a_total_1001
 toplist_a_total_1002
 toplist_a_total_1008
 toplist_a_total_1009
 toplist_a_total_1019
 toplist_a_total_1035
 ...
 Disable the above 25 tables (y/n)? 並給出確認提示

8、 drop_all

  這個命令和 disable_all 的使用方式是一樣的

9、 hbase 預分區

  默認情況下,在創建 HBase 表的時候會自動創建一個 region 分區,當導入數據的時候, 所有的 HBase 客戶端都向這一個 region 寫數據,直到這個 region 足夠大了才進行切分。一 種可以加快批量寫入速度的方法是通過預先創建一些空的 regions,這樣當數據寫入 HBase 時,會按照 region 分區情況,在集群內做數據的負載均衡。

命令方式:

# create table with specific split points
hbase>create table1,f1,SPLITS => [\x10\x00, \x20\x00, \x30\x00, \x40\x00]
# create table with four regions based on random bytes keys
hbase>create table2,f1, { NUMREGIONS => 8 , SPLITALGO => UniformSplit }
# create table with five regions based on hex keys
hbase>create table3,f1, { NUMREGIONS => 10, SPLITALGO => HexStringSplit } 

  也可以使用 api 的方式:

hbase org.apache.hadoop.hbase.util.RegionSplitter test_table HexStringSplit -c 10 -f info

hbase org.apache.hadoop.hbase.util.RegionSplitter splitTable HexStringSplit -c 10 -f info

參數:

  test_table 是表名

  HexStringSplit 是split 方式

  -c 是分 10 個 region

  -f 是 family

可在 UI 上查看結果,如圖:

技術分享圖片

  這樣就可以將表預先分為 15 個區,減少數據達到 storefile 大小的時候自動分區的時間 消耗,並且還有以一個優勢,就是合理設計 rowkey 能讓各個 region 的並發請求平均分配(趨 於均勻) 使 IO 效率達到最高,但是預分區需要將 filesize 設置一個較大的值,設置哪個參數 呢 hbase.hregion.max.filesize 這個值默認是 10G 也就是說單個 region 默認大小是 10G

  這個參數的默認值在 0.90 到 0.92 到 0.94.3 各版本的變化:256M--1G--10G

  但是如果 MapReduce Input 類型為 TableInputFormat 使用 hbase 作為輸入的時候,就要註意 了,每個 region 一個 map,如果數據小於 10G 那只會啟用一個 map 造成很大的資源浪費, 這時候可以考慮適當調小該參數的值,或者采用預分配 region 的方式,並將檢測如果達到 這個值,再手動分配 region。

表設計

1、列簇設計

  追求的原則是:在合理範圍內能盡量少的減少列簇就盡量減少列簇。

  最優設計是:將所有相關性很強的 key-value 都放在同一個列簇下,這樣既能做到查詢效率 最高,也能保持盡可能少的訪問不同的磁盤文件。

  以用戶信息為例,可以將必須的基本信息存放在一個列族,而一些附加的額外信息可以放在 另一列族。

2、RowKey 設計

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

  那怎麽快速精準的定位到我們想要操作的數據,就在於我們的 rowkey 的設計了

Rowkey 設計三原則

1、 rowkey 長度原則

  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 字節的整數 倍利用操作系統的最佳特性。

2、rowkey 散列原則

  如果 Rowkey 是按時間戳的方式遞增,不要將時間放在二進制碼的前面,建議將 Rowkey 的高位作為散列字段,由程序循環生成,低位放時間字段,這樣將提高數據均衡分布在每個 Regionserver 實現負載均衡的幾率。如果沒有散列字段,首字段直接是時間信息將產生所有 新數據都在一個 RegionServer 上堆積的熱點現象,這樣在做數據檢索的時候負載將會集中 在個別 RegionServer,降低查詢效率。

3、 rowkey 唯一原則

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

數據熱點

  HBase 中的行是按照 rowkey 的字典順序排序的,這種設計優化了 scan 操作,可以將相 關的行以及會被一起讀取的行存取在臨近位置,便於 scan。然而糟糕的 rowkey 設計是熱點 的源頭。 熱點發生在大量的 client 直接訪問集群的一個或極少數個節點(訪問可能是讀, 寫或者其他操作)。大量訪問會使熱點 region 所在的單個機器超出自身承受能力,引起性能 下降甚至 region 不可用,這也會影響同一個 RegionServer 上的其他 region,由於主機無法服 務其他 region 的請求。 設計良好的數據訪問模式以使集群被充分,均衡的利用。 為了避免寫熱點,設計 rowkey 使得不同行在同一個 region,但是在更多數據情況下,數據 應該被寫入集群的多個 region,而不是一個。

防止數據熱點的有效措施

  加鹽

  這裏所說的加鹽不是密碼學中的加鹽,而是在 rowkey 的前面增加隨機數,具體就是給 rowkey 分配一個隨機前綴以使得它和之前的 rowkey 的開頭不同。分配的前綴種類數量應該 和你想使用數據分散到不同的 region 的數量一致。加鹽之後的 rowkey 就會根據隨機生成的 前綴分散到各個 region 上,以避免熱點。

  哈希

  哈希會使同一行永遠用一個前綴加鹽。哈希也可以使負載分散到整個集群,但是讀卻是 可以預測的。使用確定的哈希可以讓客戶端重構完整的 rowkey,可以使用 get 操作準確獲取 某一個行數據

  反轉

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

  反轉 rowkey 的例子以手機號為 rowkey,可以將手機號反轉後的字符串作為 rowkey,這 樣的就避免了以手機號那樣比較固定開頭導致熱點問題

  時間戳反轉

  一個常見的數據處理問題是快速獲取數據的最近版本,使用反轉的時間戳作為 rowkey 的一部分對這個問題十分有用,可以用 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 是[user 反轉][Long.Max_Value - 起始時間], stopRow 是[userId 反轉][Long.Max_Value - 結束時間]

HBase學習之路 (十)HBase表的設計原則