「從零單排HBase 12」HBase二級索引Phoenix使用與最佳實踐

Phoenix是構建在HBase上的一個SQL層,能讓咱們用標準的JDBC APIs對HBase數據進行增刪改查,構建二級索引。固然,開源產品嘛,天然須要注意「避坑」啦,阿丸會把使用方式和最佳實踐都告訴你。 1.什麼是Phoenix

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

Phoenix徹底使用Java編寫,將SQL查詢轉換爲一個或多個HBase掃描,並編排執行以生成標準的JDBC結果集。Phoenix主要能作如下這些事情:php

  • 將SQL查詢編譯爲HBase掃描scanhtml

  • 肯定scan的開始和中止位置shell

  • 將scan並行執行數據庫

  • 將where子句中的謂詞推送到服務器端進行過濾apache

  • 經過服務器端掛鉤(稱爲協處理器co-processors)執行聚合查詢服務器

除了這些以外,phoenix還進行了一些有趣的加強,以進一步優化性能:微信

  • 二級索引,以提升非行鍵查詢的性能(這也是咱們引入phoenix的主要緣由)數據結構

  • 跳過掃描過濾器來優化IN,LIKE和OR查詢架構

  • 可選的對行鍵進行加鹽以實現負載均衡,避免熱點併發

2.Phoniex架構

Phoenix結構上劃分爲客戶端和服務端兩部分:

  • 客戶端包括應用程序開發,將SQL進行解析優化生成QueryPlan,進而轉化爲HBase Scans,調用HBase API下發查詢計算請求,並接收返回結果;

  • 服務端主要是利用HBase的協處理器,處理二級索引、聚合及JOIN計算等。

Phoiex的舊版架構採用重客戶端的模式,在客戶端執行一系列的parser、query plan的過程,以下圖所示。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

這種架構存在使用上的缺陷:

  • 應用程序與Phoenix core綁定使用,須要引入Phoenix內核依賴,一個單獨Phoenix重客戶端集成包已達120多M;

  • 運維不便,Phoenix仍在不斷優化和發展,一旦Phoenix版本更新,那麼應用程序也須要對應升級版本並從新發布;

  • 僅支持Java API,其餘語言開發者不能使用Phoenix。

所以,社區進行改造,引入了新的「輕客戶端」模式。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

輕客戶端架構將Phoenix分爲兩部分:

  • 客戶端是用戶最小依賴的JDBC驅動程序,與Phoenix依賴進行解耦,支持Java、Python、Go等多種語言客戶端;

  • 將QueryServer部署爲一個獨立的的HTTP服務,接收輕客戶端的請求,對SQL進行解析、優化、產生執行計劃;

3.基本使用

傳送門:https://phoenix.apache.org/language/index.html(平時多參考官方的語法)

3.1 建表

在phoenix shell上建的表默認只有一個region,建表時要注意預分區

// step1: 【phoenix shell】若是沒有建立過namespace的話,須要這一步
create schema "MDW_NS";
或者
create schema mdw_ns;


// step2: 【hbase shell】在原生HBase上建立一個表,爲何須要這一步(可使用預分區的功能,phoenix的建表語句在分區上的支持比較弱)
create 'MDW_NS:TABLE_DEMO', 'F1', {NUMREGIONS => 16, SPLITALGO => 'HexStringSplit'}


// step3: 【phoenix shell】建立一個同步的phoenix表
craete table if not exists mdw_ns.table_demo (
    id varchar not null primary key,
    f1.a varchar,
    f1.b varchar,
    f1.c varchar,
    f1.d varchar,
    f1.e varchar,
    f1.f varchar,
    f1.g varchar,
    f1.h varchar
)
TTL=86400,
UPDATE_CACHE_FREQUENCY=900000;
3.2 建索引

須要關注索引表的散列問題

// 方式1:split分區(適用於索引列知足散列條件)
create index table_demo_a on mdw_ns.table_demo(f1.a) split on ('10000000','20000000','30000000','40000000','50000000','60000000','70000000','80000000','90000000','a0000000','b0000000','c0000000','d0000000','e0000000','f0000000');


// 方式2:salt分區(適用於索引列不知足散列條件)
create index table_demo_a on mdw_ns.table_demo(f1.a) salt_buckets = 16;


// 注意:索引列DESC的使用是不支持的,但對原表的主鍵是支持desc的
[x] create index table_demo_a on mdw_ns.table_demo(f1.a desc)
[√] craete table if not exists mdw_ns.table_demo (
    f1.a varchar,
    f1.b varchar,
    f1.c varchar,
    f1.d varchar,
    f1.e varchar,
    f1.f varchar,
    f1.g varchar,
    f1.h varchar,
    constraint pk primary key(a, b desc)
    );
3.3 select查詢
[√] select * from mdw_ns.table_demo limit 10;
// 主鍵查詢
[√] select * from mdw_ns.table_demo where id = '0000000000';
// 二級索引查詢必須指定列名
[x] select * from mdw_ns.table_demo where a = '0000000000';
[√] select id, a, b, c, d, e from mdw_ns.table_demo where a = '0000000000'

 

4.最佳實踐 4.1 大小寫問題

注意點:phoenix對於(表名,列名,namespace,cf)是區分大小寫,默認都會轉爲成大寫。若是要屏蔽轉換,須要在對應的字符上用雙引號(")。數據類型是字符串的話,要用單引號(')包含。

// case1: 查詢「mdw_ns」(namespace)下「table_demo」(table),其中「f1」(列簇)+ 「A」(列名)爲字符串「'0000000000'」 的記錄
select id, a, b, c from "mdw_ns"."table_demo" where "f1".a = '0000000000'


// case2: 查詢PS_NS(namespace)下「MODULE_REVISION」(table)的記錄
select * from ps_ns.module_revision;

 

4.2 加鹽注意事項

加鹽一般用來解決數據熱點和範圍查詢同時存在的場景,原理介紹能夠參考社區文檔。

通常咱們只在同時知足如下需求的時候,才使用加鹽:

  • 寫熱點或寫不均衡

  • 須要範圍查詢

有熱點就要打散,但打散就難以作範圍查詢。所以,要同時知足這對相互矛盾的需求,必須有一種折中的方案:既能在必定程度上打散,又能保證必定程度的有序。這個解決方案就是加鹽,其實叫分桶(salt buckets)更準確。數據在桶內保序,桶之間隨機。寫入時按桶個數取模,數據隨機落在某個桶裏,保證寫請求在桶之間是均衡的。查詢時讀取全部的桶來保證結果集的有序和完備。

反作用:

寫瓶頸:因爲桶內保序,因此即便region不斷split變多,全表實際上仍是隻有數量爲buckets的region用於承擔寫入。當業務體量不斷增加時,由於沒法調整bucket數量,不能有更多的region幫助分擔寫,會致使寫入吞吐沒法隨集羣擴容而線性增長。致使寫瓶頸,從而限制業務發展。

讀擴散:select會按buckets數量進行拆分和併發,每一個併發都會在執行時佔用一個線程。select自己一旦併發過多會致使線程池迅速耗盡或致使QueryServer因太高的併發而FGC。同時,本應一個RPC完成的簡單查詢,如今也會拆分紅多個,使得查詢RT大大增長。

這兩個反作用會制約業務的發展,尤爲對於大致量的、發展快速的業務。由於桶個數不能修改,寫瓶頸會影響業務的擴張。讀擴散帶來的RT增長也大大下降了資源使用效率。

 

必定不要爲了預分區而使用加鹽特性,要結合業務的讀寫模式來進行表設計。

Buckets個數跟機型配置和數據量有關係,能夠參考下列方式計算,其中 N 爲 Core/RS 節點數量:

單節點內存 8G: 2*N

單節點內存 16G: 3*N

單節點內存 32G: 4*N

單節點內存 64G: 5*N

單節點內存 128G: 6*N

注意:索引表默認會繼承主表的鹽值;bucket的數目不能超過256;一個空的Region在內存中的數據結構大概2MB,用戶能夠評估下單個RegionServer承載的總Region數目,有用戶發生過在低配置節點上,建大量加鹽表直接把集羣內存耗光的問題。

 

4.3 慎用掃全表、OR、Join和子查詢

雖然Phoenix支持各類Join操做,可是Phoenix主要仍是定位爲在線數據庫,複雜Join,好比子查詢返回數據量特別大或者大表Join大表,在實際計算過程當中十分消耗系統資源,會嚴重影響在線業務,甚至致使OutOfMemory異常。對在線穩定性和實時性要求高的用戶,建議只使用Phoenix的簡單查詢,且查詢都命中主表或者索引表的主鍵。另外,建議用戶在運行SQL前都執行下explain,確認是否命中索引,或者主鍵,參考explain社區文檔。

4.4 Phoenix不支持複雜查詢

Phoenix 的二級索引本質仍是前綴匹配,用戶能夠建多個二級索引來增長對數據的查詢模式,二級索引的一致性是經過協處理器實現的,索引數據能夠實時可見,但也會影響寫性能,特別是建多個索引的狀況下。對於複雜查詢,好比任意條件的and/or組合,模糊查找,分詞檢索等Phoenix不支持,建議使用搜索引擎(如solr、es等)。固然,搜索引擎採用後臺異步索引,必然會影響實時性,須要仔細權衡。

4.5 Phoenix不支持複雜分析

Phoenix定位爲操做型分析(operational analytics),對於複雜分析,好比前面提到的複雜join則不適合,這種建議用Spark這種專門的大數據計算引擎來實現。

4.6 Phoenix支持映射已經存在的HBase表

用戶能夠經過Phoenix建立視圖或者表映射已經存在的HBase表,注意若是使用表的方式映射HBase表,在Phoenix中執行DROP TABLE語句一樣也會刪除HBase表。另外,因爲column family和列名是大小寫敏感的,必須一一對應才能映射成功。另外,Phoenix的字段編碼方式大部分跟HBase的Bytes工具類不同,通常建議若是隻有varchar類型,才進行映射,包含其餘類型字段時不要使用映射。

 

5.使用規範建議

  • 大小寫約定:因爲phoenix對大小寫敏感,默認又會轉換成大寫,咱們建表的時候都以大寫做爲規範,避免沒必要要的麻煩。

  • 索引名命名:每一個索引都會在hbase集羣建一張索引表,便於識別索引的歸屬,建議索引名按 {表名}_{索引標識} 的規範命名(如表名TABLE_DEMO,索引名能夠爲TABLE_DEMO_C)。

  • 原表分區原則:建議使用原生HBase的預分區方式。

  • 索引表分區原則:建議使用salt_buckets的分區方式。

  • select使用原則:建議不要使用select * 方式。

  • 建表注意點:不要使用默認的UPDATE_CACHE_FREQUENCY策略(ALWAYS),改爲UPDATE_CACHE_FREQUENCY = 60000。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

                                                                      

 

 

本文分享自微信公衆號 - 阿丸筆記(aone_note)。若有侵權,請刪除。

相關文章
相關標籤/搜索