Phoenix on HBase

Bertha 。 2022-08-19 08:58 257阅读 0赞

(一)概要

Apache Phoenix是基于BSD许可开源的一个Java中间层,可以让开发者在ApacheHBase上执行SQL查询。Apache Phoenix主要特性:

  • 嵌入式的JDBC驱动,实现了大部分的java.sql接口,包括元数据API
  • 可以通过多部行键或是键/值单元对列进行建模
  • 完善的查询支持,可以使用多个谓词以及优化的扫描键
  • DDL支持:通过CREATE TABLE、DROP TABLE及ALTERTABLE来添加/删除列
  • 版本化的模式仓库:当写入数据时,快照查询会使用恰当的模式
  • DML支持:用于逐行插入的UPSERT VALUES、用于相同或不同表之间大量数据传输的UPSERTSELECT、用于删除行的DELETE
  • 通过客户端的批处理实现的有限的事务支持
  • 单表——还没有连接,同时二级索引也在开发当中
  • 紧跟ANSI SQL标准,HIVE不完全支持SQL92,而Phoenix 接近ANSI SQL-2003

(二)安装

HBase Compatibility

  • Phoenix 2.x - HBase 0.94.x
  • Phoenix 3.x - HBase 0.94.x
  • Phoenix 4.x - HBase 0.98.1+

从Apache Phoenix下载Phoenix二进制包安装,也可以从Apache或Github下载源码使用Maven编译,命令如下:
#mvn package -DskipTests -Dhadoop.profile=2

将Phoenix服务端二进制拷贝至HBase regionserver lib 目录下,这里以CDH为例:

#mv$PHOENIX_HOME/phoenix-core/target/phoenix-core-4.0.0-incubating.jar /opt/cloudera/parcels/CDH/lib/hbase/lib/
# mv$PHOENIX_HOME/phoenix-hadoop2-compat/target/phoenix-hadoop2-compat-4.0.0-incubating.jar/opt/cloudera/parcels/CDH/lib/hbase/lib/

将Phoenix客户端二进制增加至Client CLASSPATH

#CLASSPATH=$CLASSPATH:$PHOENIX_HOME/phoenix-assembly/target/phoenix-4.0.0-incubating-client.jar

(三)Quick Start

1)Shell 操作

启动HBase验证

#hbase shell
hbase(main):001:0> list

启动Phoenix

#bin/sqlline.py zk_host

  1. create table test (mykey integer not null primary key, mycolumn varchar);
  2. upsert into test values (1,'Hello');
  3. upsert into test values (2,'World!');
  4. select * from test;

注意:Phoenix使用sqlline作为连接终端,详细命令可参考 http://www.hydromatic.net/sqlline/manual.html,如可使用如下命令查看HBase数据库表和表的列属性:

0:jdbc:phoenix:zk_host> !tables
0: jdbc:phoenix:zk_host> !columns TEST

回到HBase Terminal:

hbase(main):001:0>list
hbase(main):002:0> scan ‘TEST’

2)Java Client

新建一个Java Client Source 文件,内容如下:

  1. import java.sql.Connection;
  2. import java.sql.DriverManager;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.sql.PreparedStatement;
  6. import java.sql.Statement;
  7. public class TestJava {
  8. public static void main(String[] args) throws SQLException {
  9. Statement stmt = null;
  10. ResultSet rset = null;
  11. Connection con = DriverManager.getConnection("jdbc:phoenix:[zk_host]");
  12. // 已通过Shell建立
  13. //stmt = con.createStatement();
  14. //stmt.executeUpdate("create table test (mykey integer not null primary key, mycolumn varchar)");
  15. //stmt.executeUpdate("upsert into test values (1,'Hello')");
  16. //stmt.executeUpdate("upsert into test values (2,'World!')");
  17. //con.commit();
  18. PreparedStatement statement = con.prepareStatement("select * from test");
  19. rset = statement.executeQuery();
  20. while (rset.next()) {
  21. System.out.println(rset.getString("mycolumn"));
  22. }
  23. statement.close();
  24. con.close();
  25. }
  26. }

编译并执行:

#javac TestJava.java
# java -cpphoenix-assembly/target/phoenix-4.0.0-incubating-client.jar:.TestJava

3)数据导入

3.1 Loading CSV data via PSQL

以Phoenix自带的examples为例,建表、导入数据、查询结果,命令如下:

#bin/psql.py zk_host examples/WEB_STAT.sql examples/WEB_STAT.csv examples/WEB_STAT_QUERIES.sql

详细用法参考如下:

http://phoenix.incubator.apache.org/bulk_dataload.html

3.2 Loading via MapReduce

3.2.1)建表

#bin/psql.py zk_host examples/WEB_STAT.sql

3.2.2)创建待导入HDFS数据文件

#sudo -u hdfs hadoop fs -mkdir /user/phoenix/
# sudo -u hdfs hadoop fs -put examples/WEB_STAT.csv/user/phoenix/

3.2.3)从HDFS向Phoenix HBase导入数据 (以CDH为例)

#sudo -u hdfs HADOOP_CLASSPATH=$(hbase classpath) hadoop jarphoenix-assembly/target/phoenix-4.0.0-incubating-client.jarorg.apache.phoenix.mapreduce.CsvBulkLoadTool-zookeeper zk_host --table WEB_STAT --input /user/phoenix/WEB_STAT.csv

或者

#sudo -u hdfsHADOOP_CLASSPATH=/opt/cloudera/parcels/CDH-5.0.0-1.cdh5.0.0.p0.47/lib/hbase/hbase-protocol.jar:/etc/hbase/confhadoop jarphoenix-assembly/target/phoenix-4.0.0-incubating-client.jarorg.apache.phoenix.mapreduce.CsvBulkLoadTool-zookeeper zk_host --table WEB_STAT --input /user/phoenix/WEB_STAT.csv

4)映射现有HBase表

在Phoenix中通过CREATE TABLE/CREATE VIEW DDL映射HBase表
phoenix>CREATE TABLE “t1” ( pk VARCHAR PRIMARY KEY, “cf”.aVARCHAR, “cf”.B VARCHAR, “cf”.C VARCHAR);
phoenix> select * from “t1”;

在HBase中使用Shell创建一个测试表,并插入若干数据

hbase> put’t1’, ‘row1’, ‘cf:a’, ‘value1’
hbase> put ‘t1’, ‘row1’, ‘cf:B’, ‘value2’
hbase> put ‘t1’, ‘row1’, ‘cf:c’, ‘value3’
hbase> scan ‘t1’

注意:

  • 在Phoenix中DDL/DML是忽略大小写的,而表名和列名是区分大小写的;
  • CREATEVIEW风险较小,但是readonly无法新增修改数据;
  • CREATETABLE风险较大,一旦表结构与HBase原有表不一致,原表将会被新表覆盖,造成数据丢失;
  • 映射表创建后,遗留数据无法查询,新增修改后的数据才可见

(四)高级进阶

1)Secondary Indexing

在HBase中每条记录都有一个primary rowkey,所有的查询过滤器都是基于此项进行。而Phoenix设计了二级索引,使得数据检索不再依赖于primary rowkey,而更像传统的SQL查询。Phoenix支持Mutable Index和ImmutableIndex,两种索引适合不同的场景,如Immutable Index非常适合time-seriesdata,数据一旦写入便不再修改,只能追加。
1.1)Mutable Index

  1. CREATE TABLE my_table (k VARCHAR PRIMARY KEY, v1 VARCHAR, v2 BIGINT);

为列v1查询建立索引

  1. CREATE INDEX my_index ON my_table (v1);

为列v1,v2查询建立索引

  1. CREATE INDEX my_index ON my_table (v1) INCLUDE (v2);

1.2)Immutable Index

要使用此索引形式,必须在建表时指定 IMMUTABLE_ROWS=true,如:

  1. CREATE TABLE my_table (k VARCHAR PRIMARY KEY, v VARCHAR) IMMUTABLE_ROWS=true;
  2. 注意:只有当查询cloumns完全匹配索引时,基于索引的查询才能生效。例如:
  3. create table usertable (id varchar primary key, firstname varchar, lastname varchar);
  4. create index idx_name on usertable (firstname);
  5. 查询语句:
  6. select id, firstname, lastname from usertable where firstname = 'foo';
  7. 由于索引只有firstname,而查询cloumns还包括了lastname,因此上述查询索引并未生效,可将索引调整如下:

create indexidx_name on usertable (firstname) include(lastname);

2)Paged Queries

SELECT * FROMTEST LIMIT 1000;

  1. SELECT title, author, isbn, description
  2. FROM library
  3. WHERE published_date > 2010
  4. AND (title, author, isbn) > (?, ?, ?)
  5. ORDER BY title, author, isbn
  6. LIMIT 20

3)Sequences

创建序列

CREATE SEQUENCEmy_sequence;
CREATE SEQUENCE my_sequence START WITH -1000;
CREATE SEQUENCE my_sequence INCREMENT BY 10;
CREATE SEQUENCE my_schema.my_sequence START 0 CACHE10;

插入数据

UPSERT INTOmy_schema(MYKEY, MYCOLUMN) VALUES( NEXT VALUE FORmy_schema.my_sequence, ‘foo’);

删除序列
DROP SEQUENCEmy_sequence;
DROP SEQUENCE IF EXISTS my_schema.my_sequence;

  1. 4Salted Tables
  2. 在使用连续的row key时,避免RegionServer出现HotspottingHBase使用过程中的通用问题。详细描述及解决方案参考http://blog.sematext.com/2012/04/09/hbasewd-avoid-regionserver-hotspotting-despite-writing-records-with-sequential-keys/。
  3. 其问题大致可描述为:HBase按照row key的字典序的形式存储记录,这可以非常快速的通过raw key定位数据,以及数据的startkeyendkey范围。在很多应用场景中,很多时候采用自增或自减的序列作为HBaserow key,比如001002003……或者499498,……
  4. 在这种情况下,下一个序列必须由当前序列和步长计算得出,那么如果Region由很多个RegionServer提供服务,这是没有问题的。但很显然在HBase的架构中,一个Region只有一个RegionServer提供服务。因此,当一个Region达到它预先设置的一个最大范围时,将分裂成为两个较小的Region,并由两个RegionServer接管,无论怎样分裂对Region的写入负载总是落在某一个RegionServer的主机上,若需要全局序列实现自增,显然就失去了集群负载均衡的作用,下图是一个负载情况:
  5. 找到了问题原因,那么解决方案就相对容易一下,例如可以salt row keys with a prefix,即为row key做一些添加剂,如增加前缀:
  6. new_row_key = (++index % BUCKETS_NUMBER) + original_key
  7. 这里简单的根据数据的原始自增或自减的记录或者ID作为index,对需要分片的bucket去余进行划分,得到一个新的row key
  8. 那么HBase集群相对之前的负载将会大有改善,如下图所示:
  9. Phoenix中以Salted Table的方式支持上述接近方案,可以做如下定义,其中SALT_BUCKETS1~256的自然数:
  10. CREATE TABLE table (a_key VARCHAR PRIMARY KEY, a_col VARCHAR) SALT_BUCKETS = 20;

5)Configuration andTuning

ApachePhoenix作为HBase的一个连接驱动,在客户端做了很多定制优化。因此,应用程序可以对Client端的hbase-site.xml进行参数调优。详细属性说明参考:http://phoenix.incubator.apache.org/tuning.html
这里以bin/psql.py客户端脚本执行调优为例,修改$PHOENIX/phoenix-assembly/target目录下的phoenix-4.0.0-incubating-client.jar的hbase-default.xml文件,增加如下内容以实现将客户端默认缓存从100MB调整为1GB:

phoenix.query.maxServerCacheBytes
1024000000

发表评论

表情:
评论列表 (有 0 条评论,257人围观)

还没有评论,来说两句吧...

相关阅读