springboot集成phoenix,操作hbase

文章目录

  • 前言
  • 1、版本要求
    • 1.1 对hbase版本的支持
  • 2、微服务集成
    • 2.1 创建gradle项目,添加依赖
    • 2.2 application.yml配置
    • 2.3 准备调试环境
      • 2.3.1 服务器配置
      • 2.3.2 本地配置
  • 3 Phoenix语法
    • 3.1 创建表
    • 3.2 删除表
    • 3.3 查询数据
    • 3.4 删除数据
    • 3.5 插入或更新数据
    • 3.6 Phoenix映射HBase
      • 以正确的姿势创建表映射
      • 创建表来进行表的映射
      • 创建视图来进行表的映射
  • FAQ
    • hbase插入的数据,phoenix查出来的怎么是奇怪的值
    • 1 java.net.UnknownHostException: node3
    • 2 可视化工具Squirrel安装
    • 3 使用注意事项
    • 4 关于hbase数据转换类型的问题
    • 4 优化

前言

Apache Phoenix 官方站点:https://phoenix.apache.org/
Phoenix支持的sql语句: https://phoenix.apache.org/language/index.html
Phoenix 支持的DataTypes:https://phoenix.apache.org/language/datatypes.html
Phoenix 支持的函数:https://phoenix.apache.org/language/functions.html

jar包下载地址: https://phoenix.apache.org/download.html

注:打开网址http://mirror.bit.edu.cn/apache/phoenix/,可以看到如下类似的页面。phoenix对hbase版本有严格的要求,因此在使用的时候要格外小心,如果公司的hbase升级后,使用phoenix编写的代码也需要更新jar,甚至修改代码(这个有点蛋疼,不知道会不会因为这一点导致其很难广泛被使用)

1、版本要求

1.1 对hbase版本的支持

在Phoenix说明中,已明确指出,Phoenix对hbase版本有严格的要求,官方摘录如下

Current release 4.15.0 can run on Apache HBase 1.3, 1.4 and 1.5. CDH HBase 5.11, 5.12, 5.13 and 5.14 is supported by 4.14.0. Apache HBase 2.0 is supported by 5.0.0. Please follow the appropriate link depending on your HBase version.

目前最新的版本支持如下:

Phoenix版本 hbase版本
5.0.0-HBase-2.0 2.0
4.15.0-HBase-1.5 1.3/1.4/1.5
4.15.0-HBase-1.4 1.4

注:以上只是最新的版本,其他版本可以查看如下链接

  • release版本:http://mirror.bit.edu.cn/apache/phoenix/
  • 历史版本:http://archive.apache.org/dist/phoenix/

2、微服务集成

2.1 创建gradle项目,添加依赖

依赖包加载不下来的问题,可添加aliyun的国内镜像,在阿里云仓库里可以找到,phoenix-core包存在jcenter里面

阿里云仓库地址:https://maven.aliyun.com/mvn/search

repositories {
    maven {
        url 'http://maven.aliyun.com/nexus/content/groups/public/'
    }
    maven {
        url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
    }
}

添加依赖如下:

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'
    compile('org.springframework.boot:spring-boot-starter-jdbc')
    compile('mysql:mysql-connector-java:6.0.6')
    compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2')
    compile('org.apache.hadoop:hadoop-common:2.9.2')
    compile('org.apache.phoenix:phoenix-core:5.0.0-HBase-2.0')
    compile group: 'dom4j', name: 'dom4j', version: '1.6.1'
    compile('javax.servlet:javax.servlet-api:4.0.1')
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    
}

2.2 application.yml配置

在配置数据库连接的时候,phoenix官方文档有明确说明,没有必要设置连接池。因为其基于HBase的连接的创建成本很低,并且用过的HBase连接不能共享使用,因此用过的Connection需要关闭。

Phoenix’s Connection objects are different from most other JDBC Connections due to the underlying HBase connection. The Phoenix Connection object is designed to be a thin object that is inexpensive to create. If Phoenix Connections are reused, it is possible that the underlying HBase connection is not always left in a healthy state by the previous user. It is better to create new Phoenix Connections to ensure that you avoid any potential issues.

application.yml 配置地址如下

spring:
  datasource:
    url: jdbc:phoenix:127.0.0.1:2181
    driver-class-name: org.apache.phoenix.jdbc.PhoenixDriver
mybatis:
  mapper-locations: classpath*:/mapper/**/*.xml
  configuration:
    map-underscore-to-camel-case: true   #开启驼峰命名

2.3 准备调试环境

在phoenix连接服务器时,本地和服务端均需要做相关的配置。需要提前下载

服务器环境

JDK1.8
Hbase2.0.0

2.3.1 服务器配置

这里服务器已经安装好hbase-2.0.0

  • 下载apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz

    下载地址:
    http://archive.apache.org/dist/phoenix/apache-phoenix-5.0.0-HBase-2.0/bin/apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz

  • 将下载好的apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz上传到服务器后解压

  • 把hbase-2.0.0已经配置好的hbase-site.xml复制到apache-phoenix-5.0.0-HBase-2.0-bin/bin/hbase-site.xml

  • 进入Phoenix 控制台:
    ./apache-phoenix-5.0.0-HBase-2.0-bin/bin/sqlline.py 127.0.0.1

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-86TEKFr3-1594201709798)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1584696661653.png)]

出现上图:说明已经连接成功了

2.3.2 本地配置

1、配置hosts文件

windows打开C:\Windows\System32\drivers\etc\hosts,添加集群的hosts信息,添加集群的hosts信息

127.0.0.1 activate.navicat.com
... manager
.
.. node1
.
.. node2
.
.*. node3

2、下载hadoop,解压到本地,配置到环境变量即可

下载地址:http://archive.apache.org/dist/hadoop/core/hadoop-3.0.0

接着下载hadoop.dll、winutils.exe这两个文件,根据下载地址中对应的版本下载

下载地址:https://github.com/steveloughran/winutils

(1):将hadoop.dll、winutils.exe文件复制到你解压的 hadoop-2.9.0.tar 的bin目录下
(2):将hadoop.dll复制到C:\Window\System32下(这一步最重要,找了很多文章,都没说这个,然后就还是一直不成功)

(3):添加环境变量HADOOP_HOME,指向hadoop目录
(4):将%HADOOP_HOME%\bin加入到path里面
(5):重启 IDE(我的没重启就出问题了)
(6). 再次运行你的程序就不会在看到这个异常。

按照如上配置,即可连接成功了.源码参照文档中的code文件夹

3 Phoenix语法

3.1 创建表

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)
);

3.2 删除表

DROP TABLE us_population;

3.3 查询数据

SELECT * FROM us_population WHERE state = 'NA' AND population > 10000 ORDER BY population DESC;

*****在进行查询时,支持ORDER BY、GROUP BY、LIMIT、JOIN等操作,同时Phoenix提供了一系列的函数,其中包括COUNT()、MAX()、MIN()、SUM()等,具体的函数列表可以查看:http://phoenix.apache.org/language/functions.html

*****不管条件中的列是否是联合主键中的,Phoenix一样可以支持。

3.4 删除数据

DELETE FROM us_population WHERE state = 'NA';

3.5 插入或更新数据

UPSERT INTO us_population VALUES('CA','GZ',850000);
UPSERT INTO us_population(state,city) VALUES('CA','GZ');

*****如果主键的值重复,那么进行更新操作,否则插入一条新的记录(在进行更新时,没有更新的列保持原值,在进行插入时,没有插入的列为null)

*****在使用UPSERT时,主键的列不能为空(包括联合主键)

3.6 Phoenix映射HBase

1、需要将原有 HBase 中的表做映射才能后使用 Phoenix 操作。
2、Phoenix 区分大小写,切默认情况下会将小写转成大写,所以表名、列簇、列名需要用双引号。
3、Phoenix 4.10 版本之后,在创建表映射时需要将 COLUMN_ENCODED_BYTES 置为 0。
4、删除映射表,会同时删除原有 HBase 表。所以如果只做查询炒作,建议做视图映射。

只要直接通过HBase客户端创建的表,若想用Phoenix来进行操作,那么必须要进行表的映射,因为SYSTEM.CATALOG表中并没有维护Phoenix创建表的元数据。

以正确的姿势创建表映射

​ phoenix是支持数据类型的,hbase存储的是二进制数据。对于int,string等不同类型,二进制转换规则是不一样的,一定意义上也可以说hbase每列可以接收各类型的数据,如果要想做到各数据类型支持,首先在创建表的时候就要做到类型规范。所以在映射hbase表前,首先要确定指定表中的各列数据存储的是什么类型,这是必要的规范。

所以下面几步是必须的:

先有建表的字段规范,再有表,然后存值的时候按照数据类型来存,按照各列类型规范来进行phoenix的表的映射,取的时候就不会出现问题了。

下面从源码中扣出的bytes转换规则样例,都是二进制转换,但是类型不同,规则不同。所以呢,hbase如果存入的是string类型,phoenix却用integer接收,这个过程还会有一个二进制toObject的操作,那你将会看到一个莫名其妙的数字。

org.apache.hadoop.hbase.util.Bytes中的Bytes.toBytes(value)方法;
int类型的转换

  public static byte[] toBytes(int val) {
    byte [] b = new byte[4];
    for(int i = 3; i > 0; i--) {
      b[i] = (byte) val;
      val >>>= 8;
    }
    b[0] = (byte) val;
    return b;
  }
  
  string类型的转换
  public static byte[] toBytes(String s) {
    try {
      return s.getBytes(UTF8_CSN);
    } catch (UnsupportedEncodingException e) {
      // should never happen!
      throw new IllegalArgumentException("UTF8 decoding is not supported", e);
    }
  }

创建表来进行表的映射

CREATE TABLE IF NOT EXISTS 表名(
  列名 类型 主键,
  列簇.列名,
  列簇.列名
)

*****HBase中的RowKey映射Phoenix的主键,HBase中的Column映射Phoenix的列,且使用列簇名.列名进行映射。

*****相当于在SYSTEM.CATALOG表中录入相关的元数据,使Phoenix能够进行操作它。

创建视图来进行表的映射

CREATE VIEW 视图名(
  列名 类型 主键,
  列簇.列名,
  列簇.列名
)

*****Phoenix中的视图只能进行查询,不能进行添加、更新、删除操作。

FAQ

hbase插入的数据,phoenix查出来的怎么是奇怪的值

1、hbase插入的值是什么类型,读取时就应该转为什么类型。如:hbase插入是string,phoenix不能用int类型去读取。

2、对于不同的数据类型,hbase中的Bytes.to(value)方法,给入的数据类型的不同,转换规则也不同。在读取时就要用给入的数据类型去接收。

解决方案:

方案一:提前做hbase表的规范设计,某个列簇某个字段存什么数字类型的值,存值的时候严格按这个规范导入数据。然后再做phoenix表的映射建表。后期增加类型 的话可做相应扩展

方案二:数据来源复杂,hbase设计表时某列不能确定具体类型的话,就更要规范了,确保各个途径进入hbase的该列的数据类型一致,或者统一用string,然后在phoenix也用varchar接收,需要类型转换时再做转换。不统一的话就扯了。

1 java.net.UnknownHostException: node3

Can not resolve node3, please check your network
java.net.UnknownHostException: node3

解决办法:windows打开C:\Windows\System32\drivers\etc\hosts,添加集群的hosts信息

127.0.0.1       activate.navicat.com
39.100.153.59   manager
39.98.144.222   node1
39.98.148.29    node2
39.101.222.209  node3

2 可视化工具Squirrel安装

https://blog.csdn.net/fangchao2011/article/details/103477782?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

3 使用注意事项

  • 表名区分大小写,如果小写的时候需要给字段名或表名添加双引号

  • 插入值如果是字符串要用单引号引起来,切记不能用双引号

    Error: ERROR 204 (22008): Values in UPSERT must evaluate to a constant.

  • 表名如果要体现小写效果,必须要用双引号

  • 存储中文用varchar

    因为phoenix的char类型只支持ascii字符,不支持中文等多字节字符,如果存储中文时用varchar

    Illegal data. CHAR types may only contain single byte characters (张三)

  • boolean类型

    存储boolean值时需要用boolean类型,存储的值为TRUE/FALSE.

    Error: ERROR 203 (22005): Type mismatch. BOOLEAN and TINYINT for expression: true in column 0.read

    存储 1时会报如下错

    Error: ERROR 203 (22005): Type mismatch. INTEGER cannot be coerced to BOOLEAN

  • date类型

    • java phoenix插入和查询不存在时区问题
    • phoenix工具插入时出现时区问题,可在sql语句中对时区进行处理

日期类型保存为UTC时间,在shell/squirrel查询的时候要用CONVERT_TZ做转换,CONVERT_TZ(col, ‘UTC’, ‘Asia/Shanghai’),但有个bug,如果col字段是timestamp的话,会报Type mismatch. expected: [DATE]。实在需要转换的话先转成Date类型:CONVERT_TZ(TO_DATE(TO_CHAR(col,‘yyyy-MM-dd HH:mm:ss’),‘yyyy-MM-dd HH:mm:ss’),‘UTC’,‘Asia/Shanghai’)

  • CHAR类型只能保存单字节的字符,不能保存中文字符,中文需要使用VARCHAR。
  • 非主键字段不能指定为NOT NULL,不支持指定字段默认值(4.9版本以上支持)。
  • UPDATE table SET col=val WHERE:不支持该语法,phoenix更新和插入使用同样的UPSERT INTO语法,如果主键存在则更新,不存在则插入。但可以使用UPSERT INTO table SELECT语句来实现条件更新,需要把主键按条件选出来,如:
UPSERT INTO table(id, col1) SELECT id, 'val1' FROM table WHERE col2 = val2
  • DATE/TIME字段类型:这两个字段类型对应java.sql.Date类型,其JDBC驱动不会对java.util.Date类型进行转换,所以在PreparedStatement中setObject(int, java.util.Date)会报下面的错误。如果使用jfinal ActiveRecord保存实体,当实体字段是java.util.Date类型时要注意。
java.util.Date cannot be cast to org.apache.phoenix.schema.types.PhoenixArray
  • LIMIT OFFSET分页:phoenix 4.6不支持使用OFFSET分页,在4.8以上版本才支持。
  • ALTER不支持改变表名、字段名与字段类型,只能增加与删除字段。在设计的时候要注意使用合适的字段类型。
  • 大小写:phoenix默认不区分大小写,所有表名、列名都是大写。
  • 不支持的函数:IFNULL, ISNULL等;IFNULL有对等的COALESCE()函数
  • 连接池:phoenix不推荐使用连接池,因为其基于HBase的连接的创建成本很低,并且用过的HBase连接不能共享使用,因此用过的Connection需要关闭。Should I pool Phoenix JDBC Connections:

Phoenix’s Connection objects are different from most other JDBC Connections due to the underlying HBase connection. The Phoenix Connection object is designed to be a thin object that is inexpensive to create. If Phoenix Connections are reused, it is possible that the underlying HBase connection is not always left in a healthy state by the previous user. It is better to create new Phoenix Connections to ensure that you avoid any potential issues.

  • JDBC Connection: AutoCommit默认为false,其他JDBC Driver一般默认是true,需要手动条用connnection.commit()或者在连接url后面加上";autocommit=true"
  • 索引使用:使用CREATE INDEX idx创建的是全局索引(GLOBAL INDEX),还有一种本地索引(LOCAL INDEX),相对于本地索引,全局索引可以让读的性能更佳,但写入的时候成本会高一点;而本地索引在写入的时候成本较低,但读的时候成本较高。使用全局索引的时候,如果SELECT字段含有非索引的字段,则索引不会被使用,大多数情况下我们SELECT都会有索引之外的字段,这时候需要考虑建立覆盖索引(CREATE INDEX INCLUDING …)或使用hint来让phoenix使用索引:SELECT /*+ INDEX(table idx) */ col FROM table WHERE …。
  • PreparedStatement不支持Statement.RETURN_GENERATED_KEYS,getGeneratedKeys()。
  • 日期类型保存为UTC时间,在shell/squirrel查询的时候要用CONVERT_TZ做转换,CONVERT_TZ(col, ‘UTC’, ‘Asia/Shanghai’),但有个bug,如果col字段是timestamp的话,会报Type mismatch. expected: [DATE]。实在需要转换的话先转成Date类型:CONVERT_TZ(TO_DATE(TO_CHAR(col,‘yyyy-MM-dd HH:mm:ss’),‘yyyy-MM-dd HH:mm:ss’),‘UTC’,‘Asia/Shanghai’)

4 关于hbase数据转换类型的问题

​ 4.1 使用hbase shell看不到数据?

​ Hbase中的数据类型都是Byte类型,显示都是二进制的形式,如果想在hbase中能看到数据,那么可以在导入数据到hbase中时设置为String类型,这样在hbase中就可以看见数据

​ 4.2 为什么hbase可以看到数据,phoenix查到的数据是异常

4 优化

由于phoenix本质上在HBase读写数据,所以HBase集群的性能影响是最大的,一般使用多节点(一般hadoop集群节点要大于等于5个)、SSD、更大的内存与缓存和对phoenix/hbase/hadoop配置参数进行调优能获得更大性能的提升。下面列举一些针对phoenix的优化措施:

  • 主键:主键对应HBase的row key,HBase会把相近的row key放到相同的region里,如果选择的主键是单调递增的,那么某个region就会变成热点,写入的性能会变差,这种情况需要在建表的使用SALT_BUCKETS=N来自动对数据分片。
  • 优化读:使用全局索引,这会对写入的速度有一定影响。查询时注意使用exlain来看执行计划是否使用了索引。
  • 优化写:使用本地索引,建表时预先指定好分区方案(pre-split)。
  • 数据是否可变:如果数据只是写入,以后不会变更,可以在建表的时候指定IMMUTABLE_ROWS=true,这样可以提高写入的性能。
  • 适当使用查询hint来优化执行计划:用explain查看执行计划,用hint来优化。支持的语法见hinting。

你可能感兴趣的:(springboot)