注意: 這裏以ambari 集羣進行整合說明
1. 前提條件
一. ambari 集羣上已經安裝好了phoenix 插件以及hbase 組件
二. 保證ambari 集羣的hdfs系統,zookeeper 系統,hbase 集羣,phoenix 組件server ,ranger 管理權限系統 已經正常運行.
2. 配置hbase的namespace映射爲phoenix數據庫; (到hbase 服務的cofig 配置選項卡下選擇"自定義 hbase-site.xml" 配置中添加一下內容)
2.1 修改hbase-site.xml,增加下面配置項並重啓bhase服務,修改後hbase namespace會映射爲數據庫的schema .
property> <name>phoenix.schema.isNamespaceMappingEnabled</name> <value>true</value> </property> <property> <name>phoenix.schema.mapSystemTablesToNamespace</name> <value>true</value> </property> |
以上是大部分博客或者簡書都說到的,都需要配置的內容,但是在實際操作過程中發現此時hbase 和phoenix 只是針對系統namespace 是起到作用的,但是自定義的namespace 在phoenix 中是怎麼也找不着(我這裏是這樣的),經過兩天的查找資料以及查看phoenix 的官網(http://phoenix.apache.org/views.html)關於hbase 與phoenix 進行整合的講解方法,最終得到了答案 .
需要進行下面至關重要的一步:
3.進行hbase 與phoenix 的映射 表關係
先在phoenix shell 命令行,使用命令查看:
命令: select DISTINCT TABLE_SCHEM from SYSTEM.CATALOG; 1). 若發現 只有一個schem 那說明只是系統的 ; 2). 若發現不知一個schem 的話,說明上面的配置已經完全找到hbase 的namespace ,其下面的操作都不需要在進行操作了,直接就進行關於phoenix 與hbase 的表進行映射吧.
|
若你出現方框中的第一個情況,在phoenix shell 命令行直接進行下面這條sql 語句:
CREATE SCHEMA IF NOT EXISTS "test"; 注意: 1. 這裏"test" 是我集羣中hbase 的namespace 中一個測試庫,請換成自己的hbase 集羣 的namespace; 2. phoenix shell 的sql 語句中有大小寫區分,默認是使用字母大寫,使用雙引號就不會轉換成大寫; |
當添加schema 成功之後,然後再執行第一條sql 命令查看 schema ,會發現我們已經成功添加了一個schema .然後按照 常規操作建立phoenix 與 hbase 建立映射表 關係
以上就是hbase與phoenix 組件進行整合細節操作 .
4. phoenix 一些擴展內容
下面的內容是參考網址( https://www.jianshu.com/p/91decdd7fc5d ) 的內容
我覺得寫的是非常好的,但是沒有進行實踐過,希望大家可以學習一下.
加鹽表
1. 什麼是加鹽?
在密碼學中,加鹽是指在散列之前將散列內容(例如:密碼)的任意固定位置插入特定的字符串。這個在散列中加入字符串的方式稱爲“加鹽”。其作用是讓加鹽後的散列結果和沒有加鹽的結果不相同,在不同的應用情景中,這個處理可以增加額外的安全性。而Phoenix中加鹽是指對pk對應的byte數組插入特定的byte數據。
2. 加鹽能解決什麼問題?
加鹽能解決HBASE讀寫熱點問題,例如:單調遞增rowkey數據的持續寫入,使得負載集中在某一個RegionServer上引起的熱點問題。
3. 怎麼對錶加鹽?
在創建表的時候指定屬性值:SALT_BUCKETS,其值表示所分buckets(region)數量, 範圍是1~256。
CREATE TABLE table (key VARCHAR PRIMARY KEY, col VARCHAR) SALT_BUCKETS = 8;
4. 加鹽的原理是什麼?
加鹽的過程就是在原來key的基礎上增加一個byte作爲前綴,計算公式如下:
new_row_key = (++index % BUCKETS_NUMBER) + original_key
下圖展示了自增rowkey通過加鹽被打散寫入到各個region中的過程
5. 一個表“加多少鹽合適”?
當可用block cache的大小小於表數據大小時,較優的slated bucket是和region server數量相同,這樣可以得到更好的讀寫性能。
當表的數量很大時,基本上會忽略blcok cache的優化收益,大部分數據仍然需要走磁盤IO。比如對於10個region server集羣的大表,可以考慮設計64~128個slat buckets。
6. 加鹽時需要注意
創建加鹽表時不能再指定split key。
太大的slated buckets會減小range查詢的靈活性,甚至降低查詢性能。
References
https://phoenix.apache.org/salted.html
https://zh.wikipedia.org/wiki/%E7%9B%90_(%E5%AF%86%E7%A0%81%E5%AD%A6)
https://community.hortonworks.com/questions/26269/how-many-salt-buckets-should-i-use-for-my-phoenix.html
二級索引
一.概要
目前HBASE只有基於字典序的主鍵索引,對於非主鍵過濾條件的查詢都會變成掃全表操作,爲了解決這個問題Phoenix引入了二級索引功能。然而此二級索引又有別於傳統關係型數據庫的二級索引,本文將詳細描述Phoenix中二級索引功能、用法和原理,希望能夠對大家在業務技術選型時起到一些幫助作用。
二.二級索引
示例表如下(爲了能夠容易通過HBASE SHELL對照表內容,我們對屬性值COLUMN_ENCODED_BYTES設置爲0,不對column family進行編碼):
CREATE TABLE TEST ( ID VARCHAR NOT NULL PRIMARY KEY, COL1 VARCHAR, COL2 VARCHAR ) COLUMN_ENCODED_BYTES=0;
upsert into TEST values('1', '2', '3');
1. 全局索引
全局索引更多的應用在讀較多的場景。它對應一張獨立的HBASE表。對於全局索引,在查詢中檢索的列如果不在索引表中,默認的索引表將不會被使用,除非使用hint。
創建全局索引:
CREATE INDEX IDX_COL1 ON TEST(COL1)
通過HBASE SHELL觀察生成的索引表IDX_COL1。我們發現全局索引表的RowKey存儲了索引列的值和原表RowKey的值,這樣編碼更有利於提高查詢的性能。
hbase(main):001:0> scan 'IDX_COL1'ROW COLUMN+CELL 2\x001 column=0:_0, timestamp=1520935113031, value=x1 row(s) in 0.1650 seconds
實際上全局索引的RowKey將會按照如下格式進行編碼
SALT BYTE: 全局索引表和普通phoenix表一樣,可以在創建索引時指定SALT_BUCKETS或者split key。此byte正是存儲着salt。TENANT_ID: 當前數據對應的多租戶ID。INDEX VALUE: 索引數據。PK VALUE: 原表的RowKey。
2. 本地索引
因爲本地索引和原數據是存儲在同一個表中的,所以更適合寫多的場景。對於本地索引,查詢中無論是否指定hint或者是查詢的列是否都在索引表中,都會使用索引表。
創建本地索引:
create local index LOCAL_IDX_COL1 ON TEST(COL1);
通過HBASE SHELL觀察表'TEST', 我們可以看到表中多了一行column爲L#0:_0的索引數據。
hbase(main):001:0> scan 'TEST'ROW COLUMN+CELL \x00\x002\x001 column=L#0:_0, timestamp=1520935997600, value=_0 1 column=0:COL1, timestamp=1520935997600, value=2 1 column=0:COL2, timestamp=1520935997600, value=3 1 column=0:_0, timestamp=1520935997600, value=x2 row(s) in 0.1680 seconds
本地索引的RowKey將會按照如下格式進行編碼
REGION START KEY : 當前row所在region的start key。加上這個start key的好處是,可以讓索引數據和原數據儘量在同一個region, 減小IO,提升性能。INDEX ID : 每個ID對應不同的索引表。TENANT ID :當前數據對應的多租戶ID。INDEX VALUE: 索引數據。PK VALUE: 原表的RowKey。
3. 覆蓋索引
覆蓋索引的特點是把原數據存儲在索引數據表中,這樣在查詢到索引數據時就不需要再次返回到原表查詢,可以直接拿到查詢結果。
創建覆蓋索引:
create index IDX_COL1_COVER_COL2 on TEST(COL1) include(COL2);
通過HBASE SHELL 查詢表IDX_COL1_COVER_COL2, 我們發現include的列的值被寫入到了value中。
hbase(main):003:0> scan 'IDX_COL1_COVER_COL2'ROW COLUMN+CELL 2\x001 column=0:0:COL2, timestamp=1520943893821, value=3 2\x001 column=0:_0, timestamp=1520943893821, value=x1 row(s) in 0.0180 seconds
對於類似select col2 from TEST where COL1='2'的查詢,查詢一次索引表就能獲得結果。其查詢計劃如下:
+--------------------------------------------------------------------------------------+-----------------+----------------+---+| PLAN | EST_BYTES_READ | EST_ROWS_READ | E |+--------------------------------------------------------------------------------------+-----------------+----------------+---+| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER IDX_COL1_COVER_COL2 ['2'] | null | null | n |+--------------------------------------------------------------------------------------+-----------------+----------------+---+
4. 函數索引
函數索引的特點是能根據表達式創建索引,適用於對查詢表,過濾條件是表達式的表創建索引。例如:
//創建函數索引CREATE INDEX CONCATE_IDX ON TEST (UPPER(COL1||COL2))//查詢函數索引SELECT * FROM TEST WHERE UPPER(COL1||COL2)='23'
三.什麼是Phoenix的二級索引?
Phoenix的二級索引我們基本上已經介紹過了,我們回過頭來繼續看Phoenix二級索引的官方定義:Secondary indexes are an orthogonal way to access data from its primary access path。簡單理解爲,在主訪問路徑(通過row key訪問)上發生正交的一種方法,更清楚的應該描述爲:索引列訪問和row key訪問產生交集時的一種索引方法。我們來通過一個例子說明:
1. 對錶TEST的COL1創建全局索引
CREATEINDEXIDX_COL1ONTEST(COL1);
2. 對於如下查詢必將發生FULL SCAN
select*fromTESTwhereCOL1='2';
以上查詢的查詢計劃如下:
+----------------------------------------------------------------+-----------------+----------------+--------------+| PLAN | EST_BYTES_READ | EST_ROWS_READ | EST_INFO_TS |+----------------------------------------------------------------+-----------------+----------------+--------------+| CLIENT1-CHUNK PARALLEL1-WAY ROUND ROBIN FULL SCAN OVER TEST |null|null|null|| SERVER FILTER BY COL1 ='2'|null|null|null|+----------------------------------------------------------------+-----------------+----------------+--------------+
3. 對於以下查詢將會形成點查。因爲二級索引是RowKey的交集。
select * from TEST where id='1' and COL1='2'
查詢計劃如下
+---------------------------------------------------------------------------------------------+-----------------+-------------+| PLAN | EST_BYTES_READ | EST_ROWS_RE |+---------------------------------------------------------------------------------------------+-----------------+-------------+| CLIENT 1-CHUNK 1 ROWS 203 BYTES PARALLEL 1-WAY ROUND ROBIN POINT LOOKUP ON 1 KEY OVER TEST | 203 | 1 || SERVER FILTER BY COL1 = '2' | 203 | 1 |+---------------------------------------------------------------------------------------------+-----------------+-------------+
對於2中所描述的查詢爲什麼會發生FULL SCAN? 正如Phoenix二級索引官方定義的一樣,因爲“沒有和RowKey列的查詢發生正交關係”,除非使用Hint強制指定索引表。
四.索引Building
Phoenix的二級索引創建有同步和異步兩種方式。
在執行CREATE INDEX IDX_COL1 ON TEST(COL1)時會進行索引數據的同步。此方法適用於數據量較小的情況。
異步build索引需要藉助MR,創建異步索引語法和同步索引相差一個關鍵字:ASYNC。
//創建異步索引CREATE INDEX ASYNC_IDX ON DB.TEST (COL1) ASYNC//build 索引數據${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool --schema DB --data-table TEST --index-table ASYNC_IDX --output-path ASYNC_IDX_HFILES
五.索引問題彙總
1. 創建同步索引超時怎麼辦?
在客戶端配置文件hbase-site.xml中,把超時參數設置大一些,足夠build索引數據的時間。
2. 索引表最多可以創建多少個?
建議不超過10個
3. 爲什麼索引表多了,單條寫入會變慢?
索引表越多寫放大越嚴重。寫放大情況可以參考下圖。
References
https://phoenix.apache.org/secondary_indexing.html
https://community.hortonworks.com/articles/61705/art-of-phoenix-secondary-indexes.html
MR在Ali-Phoenix上的使用
一.MR在Phoenix上的用途
利用MR對Phoenix表(可帶有二級索引表)進行Bulkload入庫, 其原理是直接生成主表(二級索引表)的HFILE寫入HDFS。相對於走API的數據導入方式,不僅速度更快,而且對HBASE集羣的負載也會小很多。目前雲HBASE上的Phoenix支持以下數據源的Bulkload工具:
CsvBulkLoadTool
JsonBulkLoadTool
RegexBulkLoadTool
ODPSBulkLoadTool(待上線)
利用MR Building二級索引。當主表數據量較大時,可以通過創建異步索引,使用MR快速同步索引數據。
二.如何訪問雲HBASE的HDFS?
由於雲HBASE上沒有MR,需要藉助外部的計算引擎(自建的HADOOP集羣或者EMR),而使用外部的計算引擎的首先面臨的問題是,如何跨集羣訪問HDFS。
由於雲HBASE的HDFS端口默認是不開的,需要聯繫工作人員開通。
端口開通以後,要想順利的訪問HDFS是HA配置的雲HBASE集羣,需要向工作人員獲取雲HBASE的主備(emr-header-1,emr-header-2)namenode host/IP。參考如下配置模板,設置hadoop客戶端配置文件:
core-site.xml
hdfs-site.xml
驗證訪問雲HBASE HDFS
hadoop dfs -ls hdfs://emr-cluster/
三.BULKLOAD PHOENIX表
1. 由於要和雲HBASE通信,所以客戶端的依賴的hbase-protocol.jar需要是1.1.x版本。可以使用鏈接:http://central.maven.org/maven2/org/apache/hbase/hbase-protocol/1.1.1/hbase-protocol-1.1.1.jar 下載。
2. 以EMR訪問雲HBASE爲例。EMR集羣需要把雲HBASE HDFS的emr-cluster 相關配置和當前EMR的HDFS配置合在一起形成新的配置文件,單獨存放在一個目錄(${conf-dir})下。通過yarn命令的--config參數指定新的配置目錄,使這些配置文件放在CLASSPATH最前面覆蓋掉當前EMR集羣hadoop_conf_dir下的配置,以便bulkload程序能識別到雲HBASE HA的HDFS URL。
3. 執行BULKLOAD命令
yarn --config ${CONF_DIR} jar ${PHOENIX_HOME}/phoenix-${version}-client.jar org.apache.phoenix.mapreduce.CsvBulkLoadTool --table "TABLENAME" --input "hdfs://emr-header-1.cluster-55090:9000/tmp/test_data" --zookeeper "zk1,zk2,zk3" --output "hdfs://emr-cluster/tmp/tmp_data"
注意: --output 配置的是雲HBASE的臨時文件,這樣直接把生成的HFILE存儲在雲HBASE的HDFS上,後續的只有簡單的move操作。否則,如果生成在EMR集羣還需要走網絡發送到雲HBASE HDFS上。