apache phoenix 入门_实现Phoenix入门
快速入門
Phoenix是一個開源的HBASE SQL層。Phoeinx可以用標準的JDBC API替代HBASE client API來創建表,插入和查詢查詢HBASE中的數據。
Phoenix作為應用層和HBASE之間的中間件,以下特性使它在大數據量的簡單查詢場景有著獨有的優勢
1. 二級索引支持(global index + local index)
2. 編譯SQL成為原生HBASE的可并行執行的scan
3. 在數據層完成計算,server端的coprocessor執行聚合
4. 下推where過濾條件到server端的scan filter上
5. 利用統計信息優化、選擇查詢計劃(5.x版本將支持CBO)
6. skip scan功能提高掃描速度
一般可以使用以下三種方式訪問Phoenix
1. JDBC API
2. 使用Python編寫的命令行工具(sqlline, sqlline-thin和psql等)
3. SQuirrel
一.命令行工具psql使用示例
1.創建一個建表的sql腳本文件us_population.sql:
CREATE TABLE IF NOT EXISTS us_population (
state CHAR(2) NOT NULL,
city VARCHAR NOT NULL,
population BIGINT ? ?CONSTRAINT my_pk PRIMARY KEY (state, city)
);
2. 創建csv格式的數據文件us_population.csv:
NY,New York,8143197
CA,Los Angeles,3844829
IL,Chicago,2842518
TX,Houston,2016582
PA,Philadelphia,1463281
AZ,Phoenix,1461575
TX,San Antonio,1256509
CA,San Diego,1255540
TX,Dallas,1213825
CA,San Jose,912332
3. 創建一個查詢sql腳本文件us_population_queries.sql:
SELECT state as "State",count(city) as "City Count",sum(population) as "Population Sum"FROM us_populationGROUP BY stateORDER BY sum(population) DESC;
4. 執行psql.py工具運行sql腳本:
./psql.py ?us_population.sql us_population.csv us_population_queries.sql
二.JDBC API使用示例
1. 使用Maven構建工程時,需要添加以下依賴
com.aliyun.phoenix
ali-phoenix-core
${version}
2. 創建名為test.java的文件
importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.PreparedStatement;importjava.sql.Statement;publicclasstest{publicstaticvoidmain(String[] args)throwsSQLException{ ? ? ? ?Statement stmt =null; ? ? ? ?ResultSet rset =null; ? ? ? ? ? ? ? ?Connection con = DriverManager.getConnection("jdbc:phoenix:[zookeeper]"); ? ? ? ?stmt = con.createStatement(); ? ? ? ? ? ? ? ?stmt.executeUpdate("create table test (mykey integer not null primary key, mycolumn varchar)"); ? ? ? ?stmt.executeUpdate("upsert into test values (1,'Hello')"); ? ? ? ?stmt.executeUpdate("upsert into test values (2,'World!')"); ? ? ? ?con.commit(); ? ? ? ? ? ? ? ?PreparedStatement statement = con.prepareStatement("select * from test"); ? ? ? ?rset = statement.executeQuery();while(rset.next()) { ? ? ? ? ? ?System.out.println(rset.getString("mycolumn")); ? ? ? ?} ? ? ? ?statement.close(); ? ? ? ?con.close(); ? ?}}
3.執行test.java
javac test.javajava -cp"../phoenix-[version]-client.jar:."test
三.SQuirrel使用示例
數據類型
目前Phoenix支持24種簡單數據類型和1個一維Array的復雜類型。以下是對支持數據類型的說明:
DML語法
云HBASE上Phoenix支持的DML
1. SELECT
從一個或者多個表中查詢數據。
LIMIT(或者FETCH FIRST) 在ORDER BY子句后將轉換為top-N查詢。
OFFSET子句指定返回查詢結果前跳過的行數。
示例
SELECT * FROM TEST LIMIT 1000;SELECT * FROM TEST LIMIT 1000 OFFSET 100;SELECT full_name FROM SALES_PERSON WHERE ranking >= 5.0 ? ?UNION ALL SELECT reviewer_name FROM ? ?CUSTOMER_REVIEW WHERE score >= 8.0
2. UPSERT VALUES
此處upsert語義有異于標準SQL中的Insert,當寫入值不存在時,表示寫入數據,否則更新數據。其中列的聲明是可以省略的,當省略時,values指定值的順序和目標表中schema聲明列的順序需要一致。
ON DUPLICATE KEY是4.9版本中的功能,表示upsert原子寫入的語義,在寫入性能上弱于非原子語義。相同的row在同一batch中按照執行順序寫入。
示例
UPSERT INTO TEST VALUES('foo','bar',3);UPSERT INTO TEST(NAME,ID) VALUES('foo',123);UPSERT INTO TEST(ID, COUNTER) VALUES(123, 0) ON DUPLICATE KEYUPDATECOUNTER = COUNTER +1;UPSERT INTO TEST(ID, MY_COL) VALUES(123, 0) ON DUPLICATE KEY IGNORE;
3. UPSERT SELECT
從另外一張表中讀取數據寫入到目標表中,如果數據存在則更新,否則插入數據。插入目標表的值順序和查詢表指定查詢字段一致。當auto commit被打開并且select子句沒有聚合時,寫入目標表這個過程是在server端完成的,否則查詢的數據會先緩存在客戶端再寫入目標表中(phoenix.mutate.upsertBatchSize表示從客戶端一次commit的行數,默認10000行)。
示例
UPSERT INTO test.targetTable(col1, col2) SELECT col3, col4 FROM test.sourceTable WHERE col5 < 100UPSERT INTO foo SELECT * FROM bar;
4. DELETE
刪除選定的列。如果auto commit打開,刪除操作將在server端執行。
示例
DELETEFROMTABLENAME;DELETEFROMTABLENAMEWHEREPK=123;DELETEFROMTABLENAMEWHERENAMELIKE'%';
References
https://phoenix.apache.org/language/index.html
加鹽表
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上。
四.參考
http://www.syscrest.com/2016/02/access-remote-ha-enabled-hdfs-oozie-distcp-action/
更多技術交流,請關注:
總結
以上是生活随笔為你收集整理的apache phoenix 入门_实现Phoenix入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《软件体系结构》第三章 软件体系结构风格
- 下一篇: headroom.js插件使用方法