Phoenix 原理 以及 Phoenix在HBase中的应用
一、前言
業(yè)務(wù)使用HBase已經(jīng)有一段時間了,期間也反饋了很多問題,其中反饋最多的是HBase是否支持SQL查詢和二級索引,由于HBase在這兩塊上目前暫不支持,導(dǎo)致業(yè)務(wù)在使用時無法更好的利用現(xiàn)有的經(jīng)驗來查詢HBase。雖然HBase本身不支持SQL,但業(yè)界還是有現(xiàn)成的方案來支持,如Hive、Impala、Phoenix等。眾多方案各有各的優(yōu)勢,本文主要對Phoenix作一個大概的介紹。
Phoenix中文翻譯為鳳凰, 其最早是Salesforce的一個開源項目,Salesforce背景是一個搞ERP的,ERP軟件一個很大的特點就是數(shù)據(jù)庫操作,所以能搞出一個數(shù)據(jù)庫中間件也是很正常的。而后,Phoenix成為Apache基金的頂級項目。
Phoenix具體是什么呢,其本質(zhì)是用Java寫的基于JDBC API操作HBase的開源SQL引擎。它有如下幾個功能特性:
?
圖1.phoenix功能特性
?
我覺得值得關(guān)注的幾個特性主要有以下幾塊:
- 通過JDBC API實現(xiàn)了大部分的java.sql接口,包括元數(shù)據(jù)API
- DDL支持:通過CREATE TABLE、DROP TABLE及ALTER TABLE來添加/刪除
- DML支持:用于逐行插入的UPSERT VALUES,用于相同或不同表之間大量數(shù)據(jù)傳輸?shù)腢PSERT SELECT,用于刪除行的DELETE
- 事務(wù)支持:通過客戶端的批處理實現(xiàn)的有限的事務(wù)支持(beta測試中)
- 二級索引支持:
- 遵循ANSI SQL標準
當前使用Phoenix的公司有很多,如下圖所示:
![2]
圖2.phoenix使用公司
對于我們公司來說,雖然HBase用得多,但用Phoenix的比較少。從自己測試來看,Phoenix確實還存在各種不穩(wěn)定,如下面描述的幾點問題:
- 最新版本對HBase、Hadoop等有嚴格版本控制,對于已經(jīng)用上HBase的業(yè)務(wù)來說要升級HBase版本適配Phoenix代價太大
- 與HBase強相關(guān),作為HBase中的一個組件啟動,HBase元數(shù)據(jù)容易遭到破壞
- 官方提供的創(chuàng)建索引方法,容易導(dǎo)致插入失敗,查詢失敗,程序崩潰等問題
我覺得Phoenix總體思路還是很不錯的,但本身太冒進,急于集成新功能,但現(xiàn)有的功能所存在的問題卻并未有很好的解決方案,導(dǎo)致版本很多,但沒有一個版本能放心在生產(chǎn)環(huán)境使用。下面關(guān)注一下Phoenix的整體設(shè)計思路。
二、Phoenix架構(gòu)
上面說到,Phoenix是以JDBC驅(qū)動方式嵌入到HBase中的,在部署時只有一個包,直接放HBase的lib目錄,邏輯構(gòu)架如下:
![3]
圖3.phoenix_structure
從圖中可看出,每個RS結(jié)點上,都會有一個Phoenix協(xié)處理器來處理每個表、每個region的數(shù)據(jù),應(yīng)用端通過Phoneix客戶端與HBase客戶端打交道,從而實現(xiàn)Sql化訪問HBase數(shù)據(jù)。下面先來說下Coprocessor。
2.1 Coprocessor
HBase的協(xié)處理器主要受Google BigTable的影響,具體可參考Dean-Keynote-Ladis2009-page 66-67。 對于HBase來說,引入Coprocessor也是為了提供更好的并行計算能力,而無需依賴于Hadoop的MapReduce。同時,基于Coprocessor,可以更好的實現(xiàn)二級索引、復(fù)雜過濾規(guī)則、權(quán)限訪問控制等更接地氣的特性。Coprocessor有兩種類型,Observer和EndPoint。
前者Observer,類似于RDBMS的觸發(fā)器,主要作用于RegionServer服務(wù)端,通過重載Coprocessor框架的Upcall函數(shù)插入用戶自己的邏輯,這些邏輯只有在固定的事件發(fā)生時才會被觸發(fā)調(diào)用執(zhí)行,主要有三類hook接口:RegionObserver、WALObserver和MasterObserver。RegionObserver提供了一些數(shù)據(jù)層操作事件的hook,如Put、Get、Delete和Scan等,在每個操作發(fā)生或結(jié)束時,會觸發(fā)調(diào)用一些前置的Hook(pre+操作,如preGet)或后置的Hook(post+操作,如postGet);WALObserver提供了WAL相關(guān)的Hook;MasterObserver提供了HMaster相關(guān)的Hook。
后者EndPoint類似于RDBMS的存儲過程,主要作用于客戶端,客戶端可以調(diào)用這些EndPoint執(zhí)行一段Server端代碼,并將Server端代碼結(jié)果返回給客戶端進一步處理,如常見聚合操作,找一張大表某個字段的最大值,如果不用Coprocesser則只能全表掃描,在客戶端遍歷所有結(jié)果找出最大值,且只能利用有限的客戶端資源進行迭代計算,無法利用上HBase的并發(fā)計算能力;如果用了Coprocessor,則client端可在RegionServer端執(zhí)行統(tǒng)計每個Region最大值的邏輯,并將Server端結(jié)果返回客戶端,再找出所有Server端所返回的最大值中的最大值得到最終結(jié)果,很明顯,這種方式盡量將統(tǒng)計執(zhí)行下放到Server端,Client端只執(zhí)行一些最后的聚合,大幅提高了統(tǒng)計效率;還有一個很常見的需求可能就是統(tǒng)計表的行數(shù),其邏輯和上面一樣,具體可參考Coprocessor Introduction,在這里就不展開了,后面有機會針對Coprocessor單獨展開介紹。
2.2 Phoenix 實現(xiàn)原理
Phoenix的SQL實現(xiàn)原理主要也是基于一系列的Scan操作來完成,Scan是HBase的批量掃描過程。這一系列的Scan操作也是分散到各臺RegionServer上通過Coprocessor來完成。主要用到的是RegionObserver,通過RegionObserver在postScannerOpen Hook中將RegionScanner替換成支持聚合操作的定制化Scanner,在真正執(zhí)行聚合時,會通過自定的Scan屬性傳遞給RegionScanner,在這個Scan中也可加入一些過濾規(guī)則,盡量減少返回Client的結(jié)果。
2.3 Phoenix 數(shù)據(jù)模型
Phoenix在數(shù)據(jù)模型上是將HBase非關(guān)系型形式轉(zhuǎn)換成關(guān)系型數(shù)據(jù)模型 ,如下圖所示
?
圖4.Phoenix Data Model
?
對于Phoenix來說,HBase的rowkey會被轉(zhuǎn)換成primary key,column family如果不指定則為0否則字段名會帶上,qualifier轉(zhuǎn)換成表的字段名,如下是創(chuàng)建一個Phoenix表的例子,以創(chuàng)建表test為例,主鍵為id即為HBase的rowkey, column family為i, qualifier為name和age。
create table "test" ("id" varchar(20) primary key,"i"."name" varchar(20) ,"i"."age" varchar(20));Phoenix還支持組合primary key,即由多個字段聯(lián)合組成主鍵,對于組合主鍵來說,在HBase底層會把主鍵的多個字段組合成rowkey顯示,其它字段為HBase的qualifier顯示。如上面test表,假設(shè)id和name為主鍵,創(chuàng)建表語句又變成:
create table "test" ("id" varchar(20), "name" varchar(20) ,"i"."age" varchar(20),constraint pk PRIMARY KEY("id","name"));這樣,假設(shè)插入一條數(shù)據(jù):如下所示
upsert into "test" values ('1','a','23');在HBase中,rowkey即為"1a", i:age 為 23。這里,可能大家對雙引號有點疑問,對于Phoenix來說,加了引號的話,不管是表還是字段名,會變成大小寫敏感,不加的話,會統(tǒng)一轉(zhuǎn)換成大寫字母。
2.4 Phoenix所支持的語法
目前Phoenix已經(jīng)支持關(guān)系型數(shù)據(jù)庫的大部分語法,如下圖所示:
?
圖4.Phoenix 語法
?
具體語法用法可參考Phoenix官網(wǎng),寫得比較詳細。
三、 Phoenix二級索引
我相信,二級索引這個特性應(yīng)該是大部分用戶引入Phoenix主要考慮的因素之一。HBase因其歷史原因只支持rowkey索引,當使用rowkey來查詢數(shù)據(jù)時可以很快定位到數(shù)據(jù)位置。現(xiàn)實中,業(yè)務(wù)查詢需求條件往往比較復(fù)雜,帶有多個查詢字段組合,如果用HBase查的話,只能全表掃描進行過濾,效率很低。而Phoenix支持除rowkey外的其它字段的索引創(chuàng)建,即二級索引,查詢效率可大幅提升。
3.1 索引類別
3.1.1 Covered Indexes
從字面上可理解為覆蓋索引,什么意思呢,即索引表中就包含你想要的全部字段數(shù)據(jù),這樣就只需要通過訪問索引表而無需訪問主表就能得到數(shù)據(jù)。創(chuàng)建方式如下:
create index my_index on test (v1) include(v2);當執(zhí)行select v2 from test where v1='...'時,就只會查找索引表數(shù)據(jù),不會去主表掃描。
3.1.2 Global Indexes
全局索引適用于讀多寫少的場景。全局索引在寫數(shù)據(jù)時會消耗大量資源,所有對數(shù)據(jù)的增刪改操作都會更新索引表,而索引表是分布在各個結(jié)點上的,性能會受到影響。好處就是,在讀多的場景下如果查詢的字段用到索引,效率會很快,因為可以很快定位到數(shù)據(jù)所在具體結(jié)點region上,對于寫性能就很慢了,因為每寫一次,需要更新所有結(jié)點上的索引表數(shù)據(jù)。創(chuàng)建方式如下:
create index my_index on test (v1);如果執(zhí)行`select v2 from test where v1='...', 實際是用不上索引的,因為v2不在索引字段中,對于全局索引來說,如果查詢的字段不包含在索引表中,則還是會去全表掃描主表。
3.1.3 Local Indexes
局部索引適用于寫多讀少場景,和全局索引類似,Phoenix會在查詢時自動選擇是否使用索引。如果定義為局部索引,索引表數(shù)據(jù)和主表數(shù)據(jù)會放在同一regionserver上,避免寫操作時跨節(jié)點寫索引表帶來的額外開銷(如Global Indexes)。當使用局部索引查詢時,即使查詢字段不是索引字段,索引表也會正常使用,這和Global Indexes是有區(qū)別的。在4.8版本之前,所有局部索引數(shù)據(jù)存放在一個單獨的共享表中,4.8之后是存儲在主表的一個獨立的列族中。因為是局部索引,所以在client端查詢使用索引時,需要掃描每個結(jié)點上的索引表以得到數(shù)據(jù)所在具體region位置,當region多時,查詢時耗會很高,所以查詢性能比較低,適合讀少寫多場景。創(chuàng)建局部索引方式:
create local index my_index on test (v1);3.2 Mutable Indexing 和Immutable Indexing
3.2.1 IMMutable Indexing
不可變索引主要創(chuàng)建在不可變表上,適用于數(shù)據(jù)只寫一次不會有Update等操作,在什么場景下會用到不可變索引呢,很經(jīng)典的時序數(shù)據(jù):write once read many times。在這種場景下,所有索引數(shù)據(jù)(primary和index)要么全部寫成功,要么一個失敗全都失敗返回錯誤給客戶端。不可變索引用到場景比較少,下面是創(chuàng)建不可變索引的方式:
create table test (pk VARCHAR primary key,v1 VARCHAR, v2 VARCHAR) IMMUTABLE_ROWS=true;即在創(chuàng)建表時指定IMMUTABLE_ROWS參數(shù)為true,默認這個參數(shù)為false。如果想把不可變索引改為可變索引,可用alter修改:
alter table test set IMMUTABLE_ROWS=false;3.2.2 Mutable Indexing
可變索引意思是在修改數(shù)據(jù)如Insert、Update或Delete數(shù)據(jù)時會同時更新索引。這里的索引更新涉及WAL,即主表數(shù)據(jù)更新時,會把索引數(shù)據(jù)也同步更新到WAL,只有當WAL同步到磁盤時才會去更新實際的primary/index數(shù)據(jù),以保證當中間任何一個環(huán)節(jié)異常時可通過WAL來恢復(fù)主表和索引表數(shù)據(jù)。
四、性能
在官網(wǎng),有作一個性能測試,主要是將Phoenix和Hive、Impala作一個對比。
先來看下和Hive的性能對比,測試基準如下:
測試結(jié)果:
?
圖6.Phoenix性能對比
?
從圖中可看出,帶有Key過濾的Phoenix耗時最少,不帶Key過濾的Phoenix和基于HDFS的Hive性能差不多,直接基于HBase的Hive性能最差。
再來看下和Impala的對比,測試基準如下:
select count(1) from table over 1M and 5M rows. Data is 3 narrow columns. Number of Region Server: 1 (Virtual Machine, HBase heap: 2GB, Processor: 2 cores @ 3.3GHz Xeon)測試結(jié)果:
?
圖7.Phoenix性能對比Impala
?
從圖中可看出,Impala執(zhí)行時間比Phoenix長很多,原因大概有幾點:Impala基于內(nèi)存進行并行計算,容易內(nèi)存吃緊,對HBase和HDFS的支持也還遠遠不夠,性能比較差。
我在自己的HBase測試集群也作了下測試,主要測試數(shù)據(jù)插入和一些SQL操作的查詢時耗。測試集群如下:
![11]
圖8.測試集群
先來測試下插入100萬記錄的測試基準,如下所示:
- 1.創(chuàng)建基本表,表主鍵由4個字段組成,HOST字段稱為First PK,DOMAIN為Second PK, 依此類推,SPLIT ON指定8個分區(qū)。
- 2.插入100萬行記錄
- 3.執(zhí)行如下查詢條件測試
測試結(jié)果如下:
- 插入100萬條記錄耗時70s
- Query #1 耗時1.032s
- Query #2 耗時0.025s
- Query #3 耗時0.615s
- Query #4 耗時0.608s
- Query #5 耗時1.026s
具體結(jié)果如下:
csv columns from database. CSV Upsert complete. 1000000 rows upserted Time: 69.672 sec(s)COUNT(1) ---------------------------------------- 1000000 Time: 1.032 sec(s)HO -- CS EU NA Time: 0.025 sec(s)DOMAIN ---------------------------------------- Apple.com Google.com Salesforce.com Time: 0.615 sec(s)DAY ----------------------- 2018-01-28 00:00:00.000 2018-01-29 00:00:00.000 2018-01-30 00:00:00.000 2018-01-31 00:00:00.000 2018-02-01 00:00:00.000 2018-02-02 00:00:00.000 2018-02-03 00:00:00.000 2018-02-04 00:00:00.000 2018-02-05 00:00:00.000 2018-02-06 00:00:00.000 2018-02-07 00:00:00.000 2018-02-08 00:00:00.000 2018-02-09 00:00:00.000 Time: 0.608 sec(s)COUNT(1) ---------------------------------------- 20209 Time: 1.026 sec(s)還作了下三種不同數(shù)量級下的性能對比,作了5種SQL查詢操作對比,如上測試基準第3條所描述的查詢條件,結(jié)果如下:
?
圖9.Phoenix不同數(shù)據(jù)量級測試對比
?
從結(jié)果看,隨著數(shù)量級的增加,查詢時耗也隨之增加,有一個例外,就是當用First PK索引字段作聚合查詢時,用時相差不大。總的來說,Phoenix在用到索引時查詢性能會比較好。那對于Count來說,如果不用Phoenix,用HBase自帶的Count耗時是怎樣的呢,測了一下,HBase Count 100萬需要33s, 500萬需要139s,1000萬需要284s,性能還是很差的。對于大表來說基本不能用Count來統(tǒng)計行數(shù),還得依賴于基于Coprocessor機制來統(tǒng)計。
從上面測試來看下,Phoenix的性能不能說最好,也存在各種問題,就如開篇說的,版本不穩(wěn)定,BUG過多,容易影響集群穩(wěn)定性。
五、總結(jié)
總的來說,目前并沒有一種很完美的方案來解決SQL查詢、二級索引問題,都或多或少存在各種問題。不過HBase的Coprocessor是個好東西,很多功能可以基于此特性進行二次開發(fā),后續(xù)可以深入研究一下。
六、參考
[1] https://community.hortonworks.com/articles/61705/art-of-phoenix-secondary-indexes.html
[2] https://github.com/forcedotcom/phoenix/wiki/Secondary-Indexing
[3] http://phoenix.apache.org/secondary_indexing.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的Phoenix 原理 以及 Phoenix在HBase中的应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CDH Yarn资源动态分配 - 指定资
- 下一篇: 视觉算法算法