Phoenix 在 HBase 生态系统中占据了很是重要的地位,本文主要包括如下几方面内容:html
Phoenix 介绍sql
CDH HBase 集成 Phoenixapache
使用 Phoenix 建立 HBase 二级索引json
Phoenix 索引类型介绍安全
底层存储基于 HBase,并提供一套标准的 JDBC API 做为 HBase SQL 层;网络
支持标准 SQL,以及完整 ACID 事务特性;架构
为 HBase 提供了二级索引解决方案;并发
此外,Phoenix 还和不少其余组件作了集成,好比 Spark、Hive、Flume 等。Phoenix 与 HBase 集成,其最大的特色就是为 HBase 提供了二级索引,后文会重点介绍。下图是 Phoenix 的基本架构:
[root@hadoop-01 /var/www/html/phoenix/4.14.0]$ ll total 300524 -rw-r--r-- 1 root root 307722240 Feb 3 19:30 APACHE_PHOENIX-4.14.0-cdh5.11.2.p0.3-el7.parcel -rw-r--r-- 1 root root 178 Feb 3 19:28 APACHE_PHOENIX-4.14.0-cdh5.11.2.p0.3-el7.parcel.sha512 -rw-r--r-- 1 root root 5081 Feb 3 19:30 manifest.json
(可左右滑动)app
安装完 Phoenix 后,须要作一些必要配置才能使用 Phoenix,CDH HBase 配置界面配置以下两处:ide
1. hbase-site.xml 的 HBase 服务高级配置代码段(安全阀)
2. hbase-site.xml 的 HBase 客户端高级配置代码段(安全阀)
添加以下参数配置:
<!-- 二级索引支持 --> <property> <name>hbase.regionserver.wal.codec</name> <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value> </property> <!-- 命名空间映射开启,Phoenix4.8.0开始支持 --> <property> <name>phoenix.schema.isNamespaceMappingEnabled</name> <value>true</value> </property> <property> <name>phoenix.schema.mapSystemTablesToNamespace</name> <value>true</value> </property>
(可左右滑动)
而后,按照提示重启HBase服务并从新部署客户端配置便可。
CDH 安装后环境变量都已经配置好了,能够直接使用 phoenix-sqlline.py,以下:
[root@hadoop-01 ~]$ phoenix- phoenix-performance.py phoenix-psql.py phoenix-sqlline.py phoenix-utils.py
(可左右滑动)
执行 phoenix-sqlline.py 初始化使用 Phoenix:
而后咱们查看下 HBase 中 Phoenix 的系统表:
hbase(main):003:0> list SYSTEM:CATALOG SYSTEM:FUNCTION SYSTEM:LOG SYSTEM:MUTEX SYSTEM:SEQUENCE SYSTEM:STATS
(可左右滑动)
接下来看一下如何在 Phoenix 中建立 HBase 表的二级索引。
hbase(main):017:0> count 'ns1000:operate_log', INTERVAL => 100000 ... 2799827 row(s) in 173.4200 seconds => 2799827 hbase(main):018:0> scan 'ns1000:operate_log', LIMIT => 1 ROW COLUMN+CELL \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:appVersion, timestamp=1538216707892, value=2.22.0 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:area, timestamp=1538216707892, value=\xE6\xB1\x9F\xE5\x8C\x97\xE5\x8C\xBA \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:authId, timestamp=1538216707892, value= \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:city, timestamp=1538216707892, value=\xE9\x87\x8D\xE5\xBA\x86\xE5\xB8\x82 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:imei, timestamp=1538216707892, value=AF36147F-8106-47F0-B58F-A3FB75DBE325 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:lat, timestamp=1538216707892, value=29.577587127685547 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:lon, timestamp=1538216707892, value=106.50493621826172 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:memberType, timestamp=1538216707892, value=0 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:mobileManufacturer, timestamp=1538216707892, value=iPhone \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:mobileModel, timestamp=1538216707892, value=iPhone 6 Plus \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:province, timestamp=1538216707892, value=\xE9\x87\x8D\xE5\xBA\x86\xE5\xB8\x82 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:systemType, timestamp=1538216707892, value=1 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:systemVersion, timestamp=1538216707892, value=12.0 \x00\x00\x12\x12\x00\x00\x00\x0D1538216707720 column=f:time, timestamp=1538216707892, value=1538216707720 1 row(s) in 0.0460 seconds
(可左右滑动)
0: jdbc:phoenix:> create schema if not exists "ns1000"; No rows affected (0.012 seconds)
(可左右滑动)
3. Phoenix 中建立视图,并查询数据及条数
0: jdbc:phoenix:> use "ns1000"; No rows affected (0.021 seconds) 0: jdbc:phoenix:> create view "operate_log"( . . . . . . . . > "pk" varchar primary key, . . . . . . . . > "f"."appVersion" varchar, . . . . . . . . > "f"."city" varchar, . . . . . . . . > "f"."lat" varchar, . . . . . . . . > "f"."lon" varchar, . . . . . . . . > "f"."memberType" varchar, . . . . . . . . > "f"."time" varchar); No rows affected (6.555 seconds) 0: jdbc:phoenix:> !tables +------------+--------------+--------------+---------------+----------+------------+----------------------------+-----------------+--------------+-----------------+---------------+---------------+-----------------+------------+--------+ | TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_NAME | SELF_REFERENCING_COL_NAME | REF_GENERATION | INDEX_STATE | IMMUTABLE_ROWS | SALT_BUCKETS | MULTI_TENANT | VIEW_STATEMENT | VIEW_TYPE | INDEX_ | +------------+--------------+--------------+---------------+----------+------------+----------------------------+-----------------+--------------+-----------------+---------------+---------------+-----------------+------------+--------+ | | SYSTEM | CATALOG | SYSTEM TABLE | | | | | | false | null | false | | | | | | SYSTEM | FUNCTION | SYSTEM TABLE | | | | | | false | null | false | | | | | | SYSTEM | LOG | SYSTEM TABLE | | | | | | true | 32 | false | | | | | | SYSTEM | SEQUENCE | SYSTEM TABLE | | | | | | false | null | false | | | | | | SYSTEM | STATS | SYSTEM TABLE | | | | | | false | null | false | | | | | | ns1000 | operate_log | VIEW | | | | | | false | null | false | | MAPPED | | +------------+--------------+--------------+---------------+----------+------------+----------------------------+-----------------+--------------+-----------------+---------------+---------------+-----------------+------------+--------+ 0: jdbc:phoenix:> !columns "operate_log"; +------------+--------------+--------------+--------------+------------+------------+--------------+----------------+-----------------+-----------------+-----------+----------+-------------+----------------+-------------------+--------+ | TABLE_CAT | TABLE_SCHEM | TABLE_NAME | COLUMN_NAME | DATA_TYPE | TYPE_NAME | COLUMN_SIZE | BUFFER_LENGTH | DECIMAL_DIGITS | NUM_PREC_RADIX | NULLABLE | REMARKS | COLUMN_DEF | SQL_DATA_TYPE | SQL_DATETIME_SUB | CHAR_O | +------------+--------------+--------------+--------------+------------+------------+--------------+----------------+-----------------+-----------------+-----------+----------+-------------+----------------+-------------------+--------+ | | ns1000 | operate_log | pk | 12 | VARCHAR | null | null | null | null | 0 | | | null | null | null | | | ns1000 | operate_log | appVersion | 12 | VARCHAR | null | null | null | null | 1 | | | null | null | null | | | ns1000 | operate_log | city | 12 | VARCHAR | null | null | null | null | 1 | | | null | null | null | | | ns1000 | operate_log | lat | 12 | VARCHAR | null | null | null | null | 1 | | | null | null | null | | | ns1000 | operate_log | lon | 12 | VARCHAR | null | null | null | null | 1 | | | null | null | null | | | ns1000 | operate_log | memberType | 12 | VARCHAR | null | null | null | null | 1 | | | null | null | null | | | ns1000 | operate_log | time | 12 | VARCHAR | null | null | null | null | 1 | | | null | null | null | +------------+--------------+--------------+--------------+------------+------------+--------------+----------------+-----------------+-----------------+-----------+----------+-------------+----------------+-------------------+--------+ 0: jdbc:phoenix:> select * from "operate_log" limit 1; +------------------------+-------------+-------+---------------------+---------------------+-------------+----------------+ | pk | appVersion | city | lat | lon | memberType | time | +------------------------+-------------+-------+---------------------+---------------------+-------------+----------------+ 1538216707720 | 2.22.0 | 重庆市 | 29.577587127685547 | 106.50493621826172 | 0 | 1538216707720 | +------------------------+-------------+-------+---------------------+---------------------+-------------+----------------+ 1 row selected (0.115 seconds) 0: jdbc:phoenix:> select count(*) from "operate_log"; +-----------+ | COUNT(1) | +-----------+ | 2799827 | +-----------+ 1 row selected (3.848 seconds)
(可左右滑动)
0: jdbc:phoenix:> select count(*) from "operate_log" where "f"."time" between '1538216707720' and '1538223834000'; +-----------+ | COUNT(1) | +-----------+ | 5883 | +-----------+ 1 row selected (5.241 seconds)
(可左右滑动)
这里还要有两点说明:
Phoenix 会自动将表名、字段名都转成大写,若是要区分大小写使用双引号括起来便可。
这里咱们建立的是视图,至关于外部表,也能够 create table 建立表,视图的特色是删除时不会删除 HBase 表,可是视图建立的二级索引不会自动更新,若是要实时更新的话,只能使用 create table,而后经过 Phoenix jdbc 的方式写入数据,只有经过 Phoenix 写,而后用 Phoenix 实现的协处理器才能实现实时更新的索引。
0: jdbc:phoenix:> create index index_operate_log_time on "operate_log" ("f"."time"); 2,799,827 rows affected (95.814 seconds)
(可左右滑动)
2. 再次根据 time 字段作范围查询
00: jdbc:phoenix:> select count(*) from "operate_log" where "f"."time" between '1538216707720' and '1538223834000'; +-----------+ | COUNT(1) | +-----------+ | 5883 | +-----------+ 1 row selected (0.049 seconds)
(可左右滑动)
Phoenix 提供了多种索引类型,包括覆盖索引、函数索引,以及全局索引与本地索引等,具体介绍以下。
覆盖索引是在索引表中直接存储某些经常使用字段,当查询时全部字段仅涉及索引表中包含的字段时,则无需再在基于 rowkey 索引的数据表中查询,提升了查询的效率。
好比,咱们在operate_log 表 "f"."time" 列上建立一个索引,并在索引中包含 "f"."lat", "f"."lon" 列:
0: jdbc:phoenix:> create index index_operate_log_time2 on "operate_log" ("f"."time") INCLUDE("f"."lat", "f"."lon"); 2,799,827 rows affected (133.367 seconds)
(可左右滑动)
这样咱们作相似以下查询时就能够直接走索引表,以提升查询性能:
0: jdbc:phoenix:> select "f"."lat", "f"."lon" from "operate_log" where "f"."time" between '1538216707720' and '1538223834000' limit 10;
(可左右滑动)
函数索引是在 Phoeinx 4.3 版本以后新增的,它使得索引的创建不只仅只限于基于列,而可使用任意的表达式来建立索引,在查询时,如出现相同的表达式查询条件,则会自动优先检索索引表。
好比,咱们在operate_log 表上基于 substr ( "f"."time", 1, 10) 建立一个索引:
0: jdbc:phoenix:> create index index_operate_log_time3 on "operate_log" (substr("f"."time", 1, 10)); 2,799,827 rows affected (94.74 seconds)
(可左右滑动)
这样建立索引后,咱们就可使用相同表达式走索引表进行查询优化了,好比:
0: jdbc:phoenix:> select count(*) from "operate_log" where substr("f"."time", 1, 10) between '1538216707' and '1538223834'; +-----------+ | COUNT(1) | +-----------+ | 5886 | +-----------+ 1 row selected (0.059 seconds)
(可左右滑动)
上面的覆盖索引和函数索引都属于全局索引,也是 Phoenix 默认的索引建立模式。
全局索引将索引表和数据表分开存储,如以上例子中都会建立一张新的索引表,所以每条数据和其索引数据可能会分布在不一样的数据节点上,数据表的添加、删除和修改都会更新相关的索引表,因此写入数据时因为额外的网络开销会带来较大的性能消耗。而查询数据的时候,Phoenix 会经过索引表来快速低损耗的获取数据。所以全局索引更适合读多写少的使用场景。
本地索引与全局索引相反,在 4.8.0 版本以后会将索引数据以特定的列簇存储在同一张数据表中,并经过特定的 rowkey 设置,将每条数据及其索引数据存储在同一 region 中,所以在数据写入时防止了额外的网络开销,而在读取数据时因没法提早判断索引数据的准确位置,则会在全部的 region 中检索索引数据,而很是影响读取性能。因此本地索引更适合于写多读少的使用场景。
本地索引只要在原来索引建立时增长 local 关键字便可,好比:
0: jdbc:phoenix:> create local index index_operate_log_time on "operate_log" ("f"."time");
(可左右滑动)
Phoenix 是构建在 HBase 之上的 SQL 层,不只可以提供标准的 SQL 查询,还可以为 HBase 提供二级索引能力,在 HBase 使用场景中应用很是普遍。Phoenix 二级索引主要分为全局索引和本地索引,全局索引适合那些读多写少的场景,本地索引更适合那些写多读少的场景。判断是否走索引能够 explain SQL 查看具体执行计划。