前言

phoenix这个项目我一直接触不多,在去年接触的一家公司使用phoenix分析数百亿的记录并且在秒级别返回的延迟时,笔者才慢慢探究一些phoenix的内幕。上个星期跟一位phoenix的PMC&Committer聊了聊phoenix的定位及未来的发展,发现phoenix还是比较竞争力的,从最近phoenix不断的发布版本来看,phoenix也在迅速的发展。在phoenix社区也组织了phoenixCon来宣传phoenix:PhoenixCon 2017。本文的目的是想梳理下phoenix的,phoenix怎么支持海量数据的实时分析,一些细节点不多。

架构

phoenix是专门为HBase增强的,具体说就是HBase有几个方面的问题:

  • HBase比较底层,没有SQL接口,对于希望使用SQL的同学转换成本高
  • HBase不支持二级索引(HBase自身也有一些方案,不过还是以phoenix支持最佳)
  • HBase不支持事务

最近几年,从SQL到NO-SQL,再到NewSQL的兴起。其实NewSQL本身并没有什么大技术的创新点(持久内存等硬件本身除外),只是架构的创新或者说是一种混合架构。Phoenix是不是NewSQL,其实并不重要,重要的是他解决了什么问题。

大致的phoenix嵌入进HBase的图如下所示:

hbase数据如何打破HDFS不能随机更新的限制 hbase实时数据更新_SQL

phoenix最主要给HBase添加了二级索引、SQL的支持。至于事物及一些其它的支持,算是锦上添花,让phoenix越看越是NewSQL。phoenix的官方文档比较全,笔者就不搬了。

  • secondary indexing:http://phoenix.apache.org/secondary_indexing.html
  • standard SQL:https://phoenix.apache.org/language/index.html

特别地:

  • 支持join(hash joinSort-Merge Join)
  • 相关SQL的优化(现在正在对接Calcite:http://calcite.apache.org/ )
  • 支持jdbc直接访问

性能

phoenix适合海量数据的实时分析需求:

  • phoenix基本通过建立索引在海量数据上查询少量数据,并且基本实时返回。
  • phoenix也支持做一些复杂SQL操作,包括join,sub-query等。
  • phoenix不适合于ETL,比如10T数据变为10T数据。

如下有一张跟Hadoop体系hive的对比:

hbase数据如何打破HDFS不能随机更新的限制 hbase实时数据更新_大数据_02

出自:https://phoenix.apache.org/performance.html

在四个场景中,Hive On HBase最差,phoenix(key filter)最快,究其原因就是phoenix(key filter)走了index,查询时间基本在1s以内。另外,Hive on HDFS跟phoenix on HDFS对比,在5000w条数据量左右是分界线,时间在20s左右,其实hive启动时间都在5s左右,再跑一个MR/TEZ作业都在10s左右(后续有一定的优化)。

测试数据:http://phoenix-bin.github.io/client/performance/phoenix-20160718043634.htm 其中包括了主要的一些场景,比如:Aggregation、 Count Distinct、 IN/LIKE Clause、LIMIT,测试数据集合基本是百万级别,时间在数秒左右。其实,分析的性能就在于index是否命中,另外,index也会消耗更多的空间,较多的index也会降低写的QPS

演示

目前云HBase也已经支持phoenix4.6版本,用户可以直接下载 http://hbase-cloud2.oss-cn-hangzhou.aliyuncs.com/phoenix-4.6.0-HBase-1.1.tar.gz 我们简单演示下join的功能,参考:https://phoenix.apache.org/joins.html#joining-tables-with-indices-eg1

CREATE TABLE IF NOT EXISTS Customers(
CustomerID  VARCHAR NOT NULL,
CustomerName  VARCHAR,
Country VARCHAR
CONSTRAINT pk PRIMARY KEY(CustomerID)
);


CREATE TABLE IF NOT EXISTS Items(
ItemID  VARCHAR NOT NULL,
ItemName  VARCHAR,
Price Decimal
CONSTRAINT pk PRIMARY KEY(ItemID)
);

SELECT O.OrderID, C.CustomerName
FROM ORDERS AS O
INNER JOIN CUSTOMERS AS C
ON O.CustomerID = C.CustomerID;

0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> CREATE INDEX iOrders ON Orders (ItemID) INCLUDE (CustomerID, Quantity);
5 rows affected (1.519 seconds)
0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> CREATE INDEX i2Orders ON Orders (CustomerID) INCLUDE (ItemID, Quantity);
5 rows affected (1.502 seconds)
0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> CREATE INDEX iItems ON Items (ItemName) INCLUDE (Price);
6 rows affected (1.427 seconds)


0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> SELECT O.OrderID, C.CustomerName, C.Country, O.Date
. . . . . . . . . . . . . . . . . . . . . . .> FROM Orders AS O
. . . . . . . . . . . . . . . . . . . . . . .> INNER JOIN Customers AS C
. . . . . . . . . . . . . . . . . . . . . . .> ON O.CustomerID = C.CustomerID;
+------------------------------------------+------------------------------------------+------------------------------------------+-------------------------+
|                O.ORDERID                 |              C.CUSTOMERNAME              |                C.COUNTRY                 |         O.DATE          |
+------------------------------------------+------------------------------------------+------------------------------------------+-------------------------+
| 1630781                                  | Alps Nordic AB                           | Sweden                                   | 0009-01-22 13:00:00.000 |
| 1630782                                  | Salora Oy                                | Finland                                  | 0009-02-22 13:00:00.000 |
| 1630783                                  | Logica                                   | Belgium                                  | 0009-03-22 13:00:00.000 |
| 1630784                                  | Alps Nordic AB                           | Sweden                                   | 0009-04-22 13:00:00.000 |
| 1630785                                  | Deister Electronics                      | Germany                                  | 0009-05-22 13:00:00.000 |
+------------------------------------------+------------------------------------------+------------------------------------------+-------------------------+
5 rows selected (0.136 seconds)


0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> SELECT ItemName, sum(Price * Quantity) AS OrderValue
. . . . . . . . . . . . . . . . . . . . . . .> FROM Items
. . . . . . . . . . . . . . . . . . . . . . .> JOIN Orders
. . . . . . . . . . . . . . . . . . . . . . .> ON Items.ItemID = Orders.ItemID
. . . . . . . . . . . . . . . . . . . . . . .> WHERE Orders.CustomerID > 'C002'
. . . . . . . . . . . . . . . . . . . . . . .> GROUP BY ItemName;
+------------------------------------------+------------------------------------------+
|                 ITEMNAME                 |                ORDERVALUE                |
+------------------------------------------+------------------------------------------+
| BX016                                    | 10374                                    |
| MU3508                                   | 1.44E+4                                  |
| XT2217                                   | 46436                                    |
+------------------------------------------+------------------------------------------+
3 rows selected (0.184 seconds)

较大的数据量:

0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> select count(*) from "usertable";
+------------------------------------------+
|                 COUNT(1)                 |
+------------------------------------------+
| 29643363                                 |
+------------------------------------------+
1 row selected (38.704 seconds)
0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> select count(*) from "usertable" where "cf"."field0" like  '9%';
+------------------------------------------+
|                 COUNT(1)                 |
+------------------------------------------+
| 925932                                   |
+------------------------------------------+
1 row selected (1.071 seconds)
0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> select count(*) from "usertable" where "cf"."field0" like  '9C%';
+------------------------------------------+
|                 COUNT(1)                 |
+------------------------------------------+
| 14248                                    |
+------------------------------------------+
1 row selected (0.043 seconds)
0: jdbc:phoenix:hb-bp18zlo0b209p7g23-001.hbas> select "cf"."field0","field1" from "usertable" where "field0" like  '9Cy/9>%';
+------------------------------------------+------------------------------------------+
|                  field0                  |                  field1                  |
+------------------------------------------+------------------------------------------+
| 9Cy/9>2Go.]a'Iy;>.44&09~<Z/=Ye2L3(Cg.Ni&Gc1Ue&@1).n"+8%'f+,.+".%Kc!-.4%b)249(z/3z;6~0N5,( 70h?<t6X}+ | &5j;O!.,& Uw3Qy":"/<*-No>M51Y}<]-18<5 $(Gw5Ig.8p.R7-$<0[5$?&<-f;Yg6$89_c+Ha'9`6Mc2'8 |
+------------------------------------------+------------------------------------------+
1 row selected (0.046 seconds)