Phoenix是构建在HBase上的一个SQL层,能让我们用标准的JDBC APIs对HBase数据进行增删改查,构建二级索引。当然,开源产品嘛,自然需要注意“避坑”啦,阿丸会把使用方式和最佳实践都告诉你。

1.什么是Phoenix

Phoenix完全使用Java编写,将SQL查询转换为一个或多个HBase扫描,并编排执行以生成标准的JDBC结果集。Phoenix主要能做以下这些事情:

  • 将SQL查询编译为HBase扫描scan
  • 确定scan的开始和停止位置
  • 将scan并行执行
  • 将where子句中的谓词推送到服务器端进行过滤
  • 通过服务器端挂钩(称为协处理器co-processors)执行聚合查询

除了这些之外,phoenix还进行了一些有趣的增强,以进一步优化性能:

  • 二级索引,以提高非行键查询的性能(这也是我们引入phoenix的主要原因)
  • 跳过扫描过滤器来优化IN,LIKE和OR查询
  • 可选的对行键进行加盐以实现负载均衡,避免热点

2.Phoniex架构

Phoenix结构上划分为客户端和服务端两部分:

  • 客户端包括应用程序开发,将SQL进行解析优化生成QueryPlan,进而转化为HBase Scans,调用HBase API下发查询计算请求,并接收返回结果;
  • 服务端主要是利用HBase的协处理器,处理二级索引、聚合及JOIN计算等。

Phoiex的旧版架构采用重客户端的模式,在客户端执行一系列的parser、query plan的过程,如下图所示。

这种架构存在使用上的缺陷:

  • 应用程序与Phoenix core绑定使用,需要引入Phoenix内核依赖,一个单独Phoenix重客户端集成包已达120多M;
  • 运维不便,Phoenix仍在不断优化和发展,一旦Phoenix版本更新,那么应用程序也需要对应升级版本并重新发布;
  • 仅支持Java API,其他语言开发者不能使用Phoenix。

因此,社区进行改造,引入了新的“轻客户端”模式。

轻客户端架构将Phoenix分为两部分:

  • 客户端是用户最小依赖的JDBC驱动程序,与Phoenix依赖进行解耦,支持Java、Python、Go等多种语言客户端;
  • 将QueryServer部署为一个独立的的HTTP服务,接收轻客户端的请求,对SQL进行解析、优化、产生执行计划;

3.基本使用

传送门:https://phoenix.apache.org/language/index.html(平时多参考官方的语法)

3.1 建表

在phoenix shell上建的表默认只有一个region,建表时要注意预分区

// step1: 【phoenix shell】如果没有创建过namespace的话,需要这一步
create schema "MDW_NS";
或者
create schema mdw_ns; // step2: 【hbase shell】在原生HBase上创建一个表,为什么需要这一步(可以使用预分区的功能,phoenix的建表语句在分区上的支持比较弱)
create 'MDW_NS:TABLE_DEMO', 'F1', {NUMREGIONS => 16, SPLITALGO => 'HexStringSplit'} // step3: 【phoenix shell】创建一个同步的phoenix表
craete table if not exists mdw_ns.table_demo (
id varchar not null primary key,
f1.a varchar,
f1.b varchar,
f1.c varchar,
f1.d varchar,
f1.e varchar,
f1.f varchar,
f1.g varchar,
f1.h varchar
)
TTL=86400,
UPDATE_CACHE_FREQUENCY=900000;

  

3.2 建索引

需要关注索引表的散列问题

// 方式1: split分区(适用于索引列满足散列条件)
create index table_demo_a on mdw_ns.table_demo(f1.a) split on ('10000000','20000000','30000000','40000000','50000000','60000000','70000000','80000000','90000000','a0000000','b0000000','c0000000','d0000000','e0000000','f0000000'); // 方式2: salt分区(适用于索引列不满足散列条件)
create index table_demo_a on mdw_ns.table_demo(f1.a) salt_buckets = 16; // 注意: 索引列DESC的使用是不支持的,但对原表的主键是支持desc的
[x] create index table_demo_a on mdw_ns.table_demo(f1.a desc)
[√] craete table if not exists mdw_ns.table_demo (
f1.a varchar,
f1.b varchar,
f1.c varchar,
f1.d varchar,
f1.e varchar,
f1.f varchar,
f1.g varchar,
f1.h varchar,
constraint pk primary key(a, b desc)
);

  

3.3 select查询

[√] select * from mdw_ns.table_demo limit 10;
// 主键查询
[√] select * from mdw_ns.table_demo where id = '0000000000';
// 二级索引查询必须指定列名
[x] select * from mdw_ns.table_demo where a = '0000000000';
[√] select id, a, b, c, d, e from mdw_ns.table_demo where a = '0000000000'

  

4.最佳实践

4.1 大小写问题

注意点:phoenix对于(表名,列名,namespace,cf)是区分大小写,默认都会转为成大写。如果要屏蔽转换,需要在对应的字符上用双引号(")。数据类型是字符串的话,要用单引号(')包含。

// case1: 查询「mdw_ns」(namespace)下「table_demo」(table),其中「f1」(列簇)+ 「A」(列名)为字符串「'0000000000'」 的记录
select id, a, b, c from "mdw_ns"."table_demo" where "f1".a = '0000000000' // case2: 查询PS_NS(namespace)下「MODULE_REVISION」(table)的记录
select * from ps_ns.module_revision;

  

 

4.2 加盐注意事项

加盐通常用来解决数据热点和范围查询同时存在的场景,原理介绍可以参考Phoenix社区文档。

一般我们只在同时满足以下需求的时候,才使用加盐:

  • 写热点或写不均衡
  • 需要范围查询

有热点就要打散,但打散就难以做范围查询。因此,要同时满足这对相互矛盾的需求,必须有一种折中的方案:既能在一定程度上打散,又能保证一定程度的有序。这个解决方案就是加盐,其实叫分桶(salt buckets)更准确。数据在桶内保序,桶之间随机。写入时按桶个数取模,数据随机落在某个桶里,保证写请求在桶之间是均衡的。查询时读取所有的桶来保证结果集的有序和完备。

副作用:

写瓶颈:由于桶内保序,所以即使region不断split变多,全表实际上还是只有数量为buckets的region用于承担写入。当业务体量不断增长时,因为无法调整bucket数量,不能有更多的region帮助分担写,会导致写入吞吐无法随集群扩容而线性增加。导致写瓶颈,从而限制业务发展。

读扩散:select会按buckets数量进行拆分和并发,每个并发都会在执行时占用一个线程。select本身一旦并发过多会导致线程池迅速耗尽或导致QueryServer因过高的并发而FGC。同时,本应一个RPC完成的简单查询,现在也会拆分成多个,使得查询RT大大增加。

这两个副作用会制约业务的发展,尤其对于大体量的、发展快速的业务。因为桶个数不能修改,写瓶颈会影响业务的扩张。读扩散带来的RT增加也大大降低了资源使用效率。

一定不要为了预分区而使用加盐特性,要结合业务的读写模式来进行表设计。

Buckets个数跟机型配置和数据量有关系,可以参考下列方式计算,其中 N 为 Core/RS 节点数量:

单节点内存 8G: 2*N

单节点内存 16G: 3*N

单节点内存 32G: 4*N

单节点内存 64G: 5*N

单节点内存 128G: 6*N

注意:索引表默认会继承主表的盐值;bucket的数目不能超过256;一个空的Region在内存中的数据结构大概2MB,用户可以评估下单个RegionServer承载的总Region数目,有用户发生过在低配置节点上,建大量加盐表直接把集群内存耗光的问题。

4.3 慎用扫全表、OR、Join和子查询

虽然Phoenix支持各种Join操作,但是Phoenix主要还是定位为在线数据库,复杂Join,比如子查询返回数据量特别大或者大表Join大表,在实际计算过程中十分消耗系统资源,会严重影响在线业务,甚至导致OutOfMemory异常。对在线稳定性和实时性要求高的用户,建议只使用Phoenix的简单查询,且查询都命中主表或者索引表的主键。另外,建议用户在运行SQL前都执行下explain,确认是否命中索引,或者主键。

4.4 Phoenix不支持复杂查询

Phoenix的二级索引本质还是前缀匹配,用户可以建多个二级索引来增加对数据的查询模式,二级索引的一致性是通过协处理器实现的,索引数据可以实时可见,但也会影响写性能,特别是建多个索引的情况下。对于复杂查询,比如任意条件的and/or组合,模糊查找,分词检索等Phoenix不支持,建议使用搜索引擎(如solr、es等)。当然,搜索引擎采用后台异步索引,必然会影响实时性,需要仔细权衡。

4.5 Phoenix不支持复杂分析

Phoenix定位为操作型分析(operational analytics),对于复杂分析,比如前面提到的复杂join则不适合,这种建议用Spark这种专门的大数据计算引擎来实现。

4.6 Phoenix支持映射已经存在的HBase表

参考社区相关文档。用户可以通过Phoenix创建视图或者表映射已经存在的HBase表,注意如果使用表的方式映射HBase表,在Phoenix中执行DROP TABLE语句同样也会删除HBase表。另外,由于column family和列名是大小写敏感的,必须一一对应才能映射成功。另外,Phoenix的字段编码方式大部分跟HBase的Bytes工具类不一样,一般建议如果只有varchar类型,才进行映射,包含其他类型字段时不要使用映射。

5.使用规范

  • 大小写约定:由于phoenix对大小写敏感,默认又会转换成大写,我们建表的时候都以大写作为规范,避免不必要的麻烦
  • 索引名命名:每个索引都会在hbase集群建一张索引表,便于识别索引的归属,建议索引名按 {表名}_{索引标识} 的规范命名(如表名TABLE_DEMO,索引名可以为TABLE_DEMO_C)
  • 原表分区原则:建议使用原生HBase的预分区方式
  • 索引表分区原则:建议使用salt_buckets的分区方式
  • select使用原则:建议不要使用select * 方式
  • 建表注意点:不要使用默认的UPDATE_CACHE_FREQUENCY策略(ALWAYS),改成UPDATE_CACHE_FREQUENCY = 60000

看到这里了,原创不易,点个关注、点个赞吧,你最好看了~

知识碎片重新梳理,构建Java知识图谱:https://github.com/saigu/JavaKnowledgeGraph(历史文章查阅非常方便)

最新文章

  1. AngularJS快速入门指南17:Includes
  2. Log4net在类库中的用法
  3. BochsDebug
  4. 导入Android工程源码出现乱码问题的解决方法
  5. Eclipse、MyEclipse使用git插件(egit)
  6. 设置MyEclipse的右击新建后面的选项
  7. 影响MySQL性能的五大配置参数
  8. 上一篇下一篇 排序 (非ID字段排序)
  9. Matlab命令行编译运行HelloWorld
  10. static和final修饰方法
  11. git cannot lock ref
  12. Python——字符串、文件操作,英文词频统计预处理
  13. 逆向工程vgenerator(三)
  14. 第五节《Git基本操作》
  15. 使用caffe模型测试图片(python接口)
  16. Video Frame Synthesis using Deep Voxel Flow 论文笔记
  17. Pre标签 自动换行
  18. 分享一段ios数据库代码,包括对表的创建、升级、增删查改
  19. JAVA知识积累 JSP第一篇【JSP介绍、工作原理、生命周期、语法、指令、行为】
  20. java基础(四) java运算顺序的深入解析

热门文章

  1. react: nextJs koa project basic structure
  2. BMP图片解析
  3. 学习web前端的免费12个学习网站,等你来撩
  4. 8个超好用的Python内置函数,提升效率必备(小白必看)
  5. [C语言] 获得 pwd 的几种函数
  6. React Native 在 Airbnb 的起起落落
  7. HDU 5416 CBR and tree
  8. JAVA进程CPU高的解决方法
  9. iOS逆向之一 工具的安装和使用
  10. 酷狗音乐快速转换MP3格式的方法