1. 程式人生 > 其它 >HBase 與 Phoenix 基礎

HBase 與 Phoenix 基礎

HBase 架構與讀取流程

HBase RowKey 設計

HBase 是三維有序儲存的,通過rowkey,column key(column family qulifier) 和TimeStamp 這三個維度確定唯一的cell 資料。
HBase中rowkey可標識一行記錄,在HBase中共有2種方式提供查詢:

  • 通過get方式,指定rowkey獲取唯一一條記錄
  • 通過scan方式,是指startRow和stopRow引數進行範圍匹配
    全表掃描,直接掃描整張表中所有行記錄

rowkey長度原則
rowkey是一個二進位制碼流,可以是任意字串,最大長度64kb,一般設計成定長,不超過16個位元組。
資料的持久化檔案HFile中是按照KeyValue儲存的,如果rowkey過長,比如超過100位元組,1000w行資料,光rowkey就要佔用100*1000w=10億個位元組,將近1G資料,這樣會極大影響HFile的儲存效率;
MemStore將快取部分資料到記憶體,如果rowkey欄位過長,記憶體的有效利用率就會降低,系統不能快取更多的資料,這樣會降低檢索效率。
目前作業系統都是64位系統,記憶體8位元組對齊,控制在16個位元組,8位元組的整數倍利用了作業系統的最佳特性。

rowkey唯一原則
必須在設計上保證其唯一性,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 - 結束時間

二級索引種類

  1、建立單列索引

  2、同時建立多個單列索引

  3、建立聯合索引(最多同時支援3個列)

  4、只根據rowkey建立索引

Phoenix 二級索引

全域性索引

全域性索引適合讀多寫少的場景。如果使用全域性索引,讀資料基本不損耗效能,所有的效能損耗都來源於寫資料。資料表的新增、刪除和修改都會更新相關的索引表(資料刪除了,索引表中的資料也會刪除;資料增加了,索引表的資料也會增加)

注意: 對於全域性索引在預設情況下,在查詢語句中檢索的列如果不在索引表中,Phoenix不會使用索引表將,除非使用hint。

示例

# 建立DIANXIN.sql
CREATE TABLE IF NOT EXISTS DIANXIN (
     mdn VARCHAR ,
     start_date VARCHAR ,
     end_date VARCHAR ,
     county VARCHAR,
     x DOUBLE ,
     y  DOUBLE,
     bsid VARCHAR,
     grid_id  VARCHAR,
     biz_type VARCHAR, 
     event_type VARCHAR , 
     data_source VARCHAR ,
     CONSTRAINT PK PRIMARY KEY (mdn,start_date)
) column_encoded_bytes=0;

# 上傳資料DIANXIN.csv

# 匯入資料
psql.py master,node1,node2 DIANXIN.sql DIANXIN.csv
-- 建立全域性索引
CREATE INDEX DIANXIN_INDEX ON DIANXIN ( end_date );

-- 查詢資料 ( 索引未生效)
select * from DIANXIN where end_date = '20180503154014';

-- 強制使用索引 (索引生效) hint
select /*+ INDEX(DIANXIN DIANXIN_INDEX) */  * from DIANXIN where end_date = '20180503154014';

select /*+ INDEX(DIANXIN DIANXIN_INDEX) */  * from DIANXIN where end_date = '20180503154014'  and start_date = '20180503154614';

-- 取索引列,(索引生效)
select end_date from DIANXIN where end_date = '20180503154014';

-- 建立多列索引
CREATE INDEX DIANXIN_INDEX1 ON DIANXIN ( end_date,COUNTY );

-- 多條件查詢 (索引生效)
select end_date,MDN,COUNTY from DIANXIN where end_date = '20180503154014' and COUNTY = '8340104';

-- 查詢所有列 (索引未生效)
select  * from DIANXIN where end_date = '20180503154014'  and COUNTY = '8340104';

-- 查詢所有列 (索引生效)
select /*+ INDEX(DIANXIN DIANXIN_INDEX1) */ * from DIANXIN where end_date = '20180503154014' and COUNTY = '8340104';

-- 單條件  (索引未生效)
select end_date from DIANXIN where  COUNTY = '8340103';

-- 單條件  (索引生效) end_date 在前
select COUNTY from DIANXIN where end_date = '20180503154014';

-- 刪除索引
drop index DIANXIN_INDEX on DIANXIN;