Phoenix 原理 以及 Phoenix在HBase中的应用

一、前言

业务使用HBase已经有一段时间了,期间也反馈了很多问题,其中反馈最多的是HBase是否支持SQL查询和二级索引,由于HBase在这两块上目前暂不支持,导致业务在使用时无法更好的利用现有的经验来查询HBase。虽然HBase本身不支持SQL,但业界还是有现成的方案来支持,如Hive、Impala、Phoenix等。众多方案各有各的优势,本文主要对Phoenix作一个大概的介绍。

Phoenix中文翻译为凤凰, 其最早是Salesforce的一个开源项目,Salesforce背景是一个搞ERP的,ERP软件一个很大的特点就是数据库操作,所以能搞出一个数据库中间件也是很正常的。而后,Phoenix成为Apache基金的顶级项目。

Phoenix具体是什么呢,其本质是用Java写的基于JDBC API操作HBase的开源SQL引擎。它有如下几个功能特性:

1

 

图1.phoenix功能特性

 

我觉得值得关注的几个特性主要有以下几块:

  • 通过JDBC API实现了大部分的java.sql接口,包括元数据API
  • DDL支持:通过CREATE TABLE、DROP TABLE及ALTER TABLE来添加/删除
  • DML支持:用于逐行插入的UPSERT VALUES,用于相同或不同表之间大量数据传输的UPSERT SELECT,用于删除行的DELETE
  • 事务支持:通过客户端的批处理实现的有限的事务支持(beta测试中)
  • 二级索引支持:
  • 遵循ANSI SQL标准

当前使用Phoenix的公司有很多,如下图所示:

![2]

图2.phoenix使用公司

对于我们公司来说,虽然HBase用得多,但用Phoenix的比较少。从自己测试来看,Phoenix确实还存在各种不稳定,如下面描述的几点问题:

  • 最新版本对HBase、Hadoop等有严格版本控制,对于已经用上HBase的业务来说要升级HBase版本适配Phoenix代价太大
  • 与HBase强相关,作为HBase中的一个组件启动,HBase元数据容易遭到破坏
  • 官方提供的创建索引方法,容易导致插入失败,查询失败,程序崩溃等问题

我觉得Phoenix总体思路还是很不错的,但本身太冒进,急于集成新功能,但现有的功能所存在的问题却并未有很好的解决方案,导致版本很多,但没有一个版本能放心在生产环境使用。下面关注一下Phoenix的整体设计思路。

二、Phoenix架构

上面说到,Phoenix是以JDBC驱动方式嵌入到HBase中的,在部署时只有一个包,直接放HBase的lib目录,逻辑构架如下:

![3]

图3.phoenix_structure

从图中可看出,每个RS结点上,都会有一个Phoenix协处理器来处理每个表、每个region的数据,应用端通过Phoneix客户端与HBase客户端打交道,从而实现Sql化访问HBase数据。下面先来说下Coprocessor。

2.1 Coprocessor

HBase的协处理器主要受Google BigTable的影响,具体可参考Dean-Keynote-Ladis2009-page 66-67。 对于HBase来说,引入Coprocessor也是为了提供更好的并行计算能力,而无需依赖于Hadoop的MapReduce。同时,基于Coprocessor,可以更好的实现二级索引、复杂过滤规则、权限访问控制等更接地气的特性。Coprocessor有两种类型,ObserverEndPoint

前者Observer,类似于RDBMS的触发器,主要作用于RegionServer服务端,通过重载Coprocessor框架的Upcall函数插入用户自己的逻辑,这些逻辑只有在固定的事件发生时才会被触发调用执行,主要有三类hook接口:RegionObserverWALObserverMasterObserver。RegionObserver提供了一些数据层操作事件的hook,如Put、Get、Delete和Scan等,在每个操作发生或结束时,会触发调用一些前置的Hook(pre+操作,如preGet)或后置的Hook(post+操作,如postGet);WALObserver提供了WAL相关的Hook;MasterObserver提供了HMaster相关的Hook。

后者EndPoint类似于RDBMS的存储过程,主要作用于客户端,客户端可以调用这些EndPoint执行一段Server端代码,并将Server端代码结果返回给客户端进一步处理,如常见聚合操作,找一张大表某个字段的最大值,如果不用Coprocesser则只能全表扫描,在客户端遍历所有结果找出最大值,且只能利用有限的客户端资源进行迭代计算,无法利用上HBase的并发计算能力;如果用了Coprocessor,则client端可在RegionServer端执行统计每个Region最大值的逻辑,并将Server端结果返回客户端,再找出所有Server端所返回的最大值中的最大值得到最终结果,很明显,这种方式尽量将统计执行下放到Server端,Client端只执行一些最后的聚合,大幅提高了统计效率;还有一个很常见的需求可能就是统计表的行数,其逻辑和上面一样,具体可参考Coprocessor Introduction,在这里就不展开了,后面有机会针对Coprocessor单独展开介绍。

2.2 Phoenix 实现原理

Phoenix的SQL实现原理主要也是基于一系列的Scan操作来完成,Scan是HBase的批量扫描过程。这一系列的Scan操作也是分散到各台RegionServer上通过Coprocessor来完成。主要用到的是RegionObserver,通过RegionObserver在postScannerOpen Hook中将RegionScanner替换成支持聚合操作的定制化Scanner,在真正执行聚合时,会通过自定的Scan属性传递给RegionScanner,在这个Scan中也可加入一些过滤规则,尽量减少返回Client的结果。

2.3 Phoenix 数据模型

Phoenix在数据模型上是将HBase非关系型形式转换成关系型数据模型 ,如下图所示

6

 

图4.Phoenix Data Model

 

对于Phoenix来说,HBase的rowkey会被转换成primary key,column family如果不指定则为0否则字段名会带上,qualifier转换成表的字段名,如下是创建一个Phoenix表的例子,以创建表test为例,主键为id即为HBase的rowkey, column family为i, qualifier为name和age。

create table "test" ("id" varchar(20) primary key,"i"."name" varchar(20) ,"i"."age" varchar(20));

Phoenix还支持组合primary key,即由多个字段联合组成主键,对于组合主键来说,在HBase底层会把主键的多个字段组合成rowkey显示,其它字段为HBase的qualifier显示。如上面test表,假设id和name为主键,创建表语句又变成:

create table "test" ("id" varchar(20), "name" varchar(20) ,"i"."age" varchar(20),constraint pk PRIMARY KEY("id","name"));

这样,假设插入一条数据:如下所示

upsert into "test" values ('1','a','23');

在HBase中,rowkey即为"1a", i:age 为 23。这里,可能大家对双引号有点疑问,对于Phoenix来说,加了引号的话,不管是表还是字段名,会变成大小写敏感,不加的话,会统一转换成大写字母。

2.4 Phoenix所支持的语法

目前Phoenix已经支持关系型数据库的大部分语法,如下图所示:

7

 

图4.Phoenix 语法

 

具体语法用法可参考Phoenix官网,写得比较详细。

三、 Phoenix二级索引

我相信,二级索引这个特性应该是大部分用户引入Phoenix主要考虑的因素之一。HBase因其历史原因只支持rowkey索引,当使用rowkey来查询数据时可以很快定位到数据位置。现实中,业务查询需求条件往往比较复杂,带有多个查询字段组合,如果用HBase查的话,只能全表扫描进行过滤,效率很低。而Phoenix支持除rowkey外的其它字段的索引创建,即二级索引,查询效率可大幅提升。

3.1 索引类别

3.1.1 Covered Indexes

从字面上可理解为覆盖索引,什么意思呢,即索引表中就包含你想要的全部字段数据,这样就只需要通过访问索引表而无需访问主表就能得到数据。创建方式如下:

create index my_index on test (v1) include(v2);

当执行select v2 from test where v1='...'时,就只会查找索引表数据,不会去主表扫描。

3.1.2 Global Indexes

全局索引适用于读多写少的场景。全局索引在写数据时会消耗大量资源,所有对数据的增删改操作都会更新索引表,而索引表是分布在各个结点上的,性能会受到影响。好处就是,在读多的场景下如果查询的字段用到索引,效率会很快,因为可以很快定位到数据所在具体结点region上,对于写性能就很慢了,因为每写一次,需要更新所有结点上的索引表数据。创建方式如下:

create index my_index on test (v1);

如果执行`select v2 from test where v1='...', 实际是用不上索引的,因为v2不在索引字段中,对于全局索引来说,如果查询的字段不包含在索引表中,则还是会去全表扫描主表。

3.1.3 Local Indexes

局部索引适用于写多读少场景,和全局索引类似,Phoenix会在查询时自动选择是否使用索引。如果定义为局部索引,索引表数据和主表数据会放在同一regionserver上,避免写操作时跨节点写索引表带来的额外开销(如Global Indexes)。当使用局部索引查询时,即使查询字段不是索引字段,索引表也会正常使用,这和Global Indexes是有区别的。在4.8版本之前,所有局部索引数据存放在一个单独的共享表中,4.8之后是存储在主表的一个独立的列族中。因为是局部索引,所以在client端查询使用索引时,需要扫描每个结点上的索引表以得到数据所在具体region位置,当region多时,查询时耗会很高,所以查询性能比较低,适合读少写多场景。创建局部索引方式:

create local index my_index on test (v1);

3.2 Mutable Indexing 和Immutable Indexing

3.2.1 IMMutable Indexing

不可变索引主要创建在不可变表上,适用于数据只写一次不会有Update等操作,在什么场景下会用到不可变索引呢,很经典的时序数据:write once read many times。在这种场景下,所有索引数据(primary和index)要么全部写成功,要么一个失败全都失败返回错误给客户端。不可变索引用到场景比较少,下面是创建不可变索引的方式:

create table test (pk VARCHAR primary key,v1 VARCHAR, v2 VARCHAR) IMMUTABLE_ROWS=true;

即在创建表时指定IMMUTABLE_ROWS参数为true,默认这个参数为false。如果想把不可变索引改为可变索引,可用alter修改:

alter table test set IMMUTABLE_ROWS=false;

3.2.2 Mutable Indexing

可变索引意思是在修改数据如Insert、Update或Delete数据时会同时更新索引。这里的索引更新涉及WAL,即主表数据更新时,会把索引数据也同步更新到WAL,只有当WAL同步到磁盘时才会去更新实际的primary/index数据,以保证当中间任何一个环节异常时可通过WAL来恢复主表和索引表数据。

四、性能

在官网,有作一个性能测试,主要是将Phoenix和Hive、Impala作一个对比。
先来看下和Hive的性能对比,测试基准如下:

 select count(1) from table over 10M and 100M rows. Data is 5 narrow columns. Number of Region Servers: 4 (HBase heap: 10GB, Processor: 6 cores @ 3.3GHz Xeon)

测试结果:

9

 

图6.Phoenix性能对比

 

从图中可看出,带有Key过滤的Phoenix耗时最少,不带Key过滤的Phoenix和基于HDFS的Hive性能差不多,直接基于HBase的Hive性能最差。

再来看下和Impala的对比,测试基准如下:

select count(1) from table over 1M and 5M rows. Data is 3 narrow columns. Number of Region Server: 1 (Virtual Machine, HBase heap: 2GB, Processor: 2 cores @ 3.3GHz Xeon)

测试结果:

10

 

图7.Phoenix性能对比Impala

 

从图中可看出,Impala执行时间比Phoenix长很多,原因大概有几点:Impala基于内存进行并行计算,容易内存吃紧,对HBase和HDFS的支持也还远远不够,性能比较差。

我在自己的HBase测试集群也作了下测试,主要测试数据插入和一些SQL操作的查询时耗。测试集群如下:

![11]

图8.测试集群

先来测试下插入100万记录的测试基准,如下所示:

  • 1.创建基本表,表主键由4个字段组成,HOST字段称为First PK,DOMAIN为Second PK, 依此类推,SPLIT ON指定8个分区。
CREATE TABLE IF NOT EXISTS %s (HOST CHAR(2) NOT NULL,
DOMAIN VARCHAR NOT NULL, 
FEATURE VARCHAR NOT NULL,
DATE DATE NOT NULL,
USAGE.CORE BIGINT,
USAGE.DB BIGINT,
STATS.ACTIVE_VISITOR INTEGER
CONSTRAINT PK PRIMARY KEY (HOST, DOMAIN, FEATURE, DATE))  
SPLIT ON   ('CSGoogle','CSSalesforce','EUApple','EUGoogle','EUSalesforce','NAApple','NAGoogle','NASalesforce')
  • 2.插入100万行记录
  • 3.执行如下查询条件测试
Query # 1 - Count - SELECT COUNT(1) FROM PERFORMANCE_1000000;
Query # 2 - Group By First PK - SELECT HOST FROM PERFORMANCE_1000000 GROUP BY HOST;
Query # 3 - Group By Second PK - SELECT DOMAIN FROM PERFORMANCE_1000000 GROUP BY DOMAIN;
Query # 4 - Truncate + Group By - SELECT TRUNC(DATE,'DAY') DAY FROM PERFORMANCE_1000000 GROUP BY TRUNC(DATE,'DAY');
Query # 5 - Filter + Count - SELECT COUNT(1) FROM PERFORMANCE_1000000 WHERE CORE<10;

测试结果如下:

    1. 插入100万条记录耗时70s
    1. Query #1 耗时1.032s
    1. Query #2 耗时0.025s
    1. Query #3 耗时0.615s
    1. Query #4 耗时0.608s
    1. Query #5 耗时1.026s

具体结果如下:

csv columns from database.
CSV Upsert complete. 1000000 rows upserted
Time: 69.672 sec(s)COUNT(1) 
---------------------------------------- 1000000 
Time: 1.032 sec(s)HO 
-- 
CS 
EU 
NA 
Time: 0.025 sec(s)DOMAIN                                   
---------------------------------------- 
Apple.com                                
Google.com                               
Salesforce.com                           
Time: 0.615 sec(s)DAY                     
----------------------- 
2018-01-28 00:00:00.000 
2018-01-29 00:00:00.000 
2018-01-30 00:00:00.000 
2018-01-31 00:00:00.000 
2018-02-01 00:00:00.000 
2018-02-02 00:00:00.000 
2018-02-03 00:00:00.000 
2018-02-04 00:00:00.000 
2018-02-05 00:00:00.000 
2018-02-06 00:00:00.000 
2018-02-07 00:00:00.000 
2018-02-08 00:00:00.000 
2018-02-09 00:00:00.000 
Time: 0.608 sec(s)COUNT(1) 
---------------------------------------- 20209 
Time: 1.026 sec(s)

还作了下三种不同数量级下的性能对比,作了5种SQL查询操作对比,如上测试基准第3条所描述的查询条件,结果如下:

12

 

图9.Phoenix不同数据量级测试对比

 

从结果看,随着数量级的增加,查询时耗也随之增加,有一个例外,就是当用First PK索引字段作聚合查询时,用时相差不大。总的来说,Phoenix在用到索引时查询性能会比较好。那对于Count来说,如果不用Phoenix,用HBase自带的Count耗时是怎样的呢,测了一下,HBase Count 100万需要33s, 500万需要139s,1000万需要284s,性能还是很差的。对于大表来说基本不能用Count来统计行数,还得依赖于基于Coprocessor机制来统计。

从上面测试来看下,Phoenix的性能不能说最好,也存在各种问题,就如开篇说的,版本不稳定,BUG过多,容易影响集群稳定性。

五、总结

总的来说,目前并没有一种很完美的方案来解决SQL查询、二级索引问题,都或多或少存在各种问题。不过HBase的Coprocessor是个好东西,很多功能可以基于此特性进行二次开发,后续可以深入研究一下。

六、参考

[1] https://community.hortonworks.com/articles/61705/art-of-phoenix-secondary-indexes.html

[2] https://github.com/forcedotcom/phoenix/wiki/Secondary-Indexing

[3] http://phoenix.apache.org/secondary_indexing.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/509938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

node.js文件操作

介绍&#xff1a;fs模块是文件操作的封装&#xff0c;它提供了文件的读取&#xff0c;写入&#xff0c;更名&#xff0c;删除&#xff0c;遍历目录&#xff0c;链接POSIX文件系统操作。与其他模块不同的是&#xff0c;fs模块中所有的操作都提供了异步和同步两个版本&#xff0c…

phoenix 使用详细介绍 创建二级索引

phoenix 关联hbase 基本使用参考&#xff1a;https://blog.csdn.net/zhangshenghang/article/details/97491597 Phoenix 创建二级索引 hbase中有表test_article ,在表空间 test_ns ,列簇 fn 下有字段 url , text , uid ,name 连接phoenixphoenix-sqlline.py hostname:2181:/hb…

node.js详解Http服务器

概念&#xff1a;Node.js提供了http模块。其中封装了一个高效的HTTP服务器和一个建议的HTTP客户端。http.server是一个基于事件的HTTP服务器。内部有C实现。接口由JavaScript封装。http.request则是一个HTTP客户端工具。用户向服务器发送请求。一、HTTP服务器 http.Server实现的…

node.js http客户端

一、http模块提供了两个函数http.request和http.get&#xff0c;功能是作为客户端向HTTP服务器发起请求。 Ext.Ajax.request({},function(response))1.http.request(options,callback)发起HTTP请求&#xff0c;接受两个参数&#xff0c;option是一个类似关联数组的对象&#xf…

CDH kerberos 认证,安全认证

环境centos 7.4 安装KDC服务 yum -y install krb5-server krb5-libs krb5-auth-dialog krb5-workstation 修改配置文件 vi /etc/krb5.conf 默认如下 修改为 # Configuration snippets may be placed in this directory as well includedir /etc/krb5.conf.d/[logging]default…

虚拟继承和虚表

普通继承和虚拟继承类的大小变化&#xff1a; 普通继承&#xff1a; 虚拟继承&#xff1a; 类A和类B大小为&#xff1a; 由此可见&#xff1a;1、类中静态成员不会影…

Kerberos 下运行spark 报错 Requested user hdfs is not whitelisted and has id 995,which is below the minimu

异常如下 main : run as user is hdfs main : requested yarn user is hdfs Requested user hdfs is not whitelisted and has id 995,which is below the minimum allowed 1000 问题原因&#xff1a;是由于Yarn限制了用户id小于1000的用户提交作业&#xff1b; 解决方法&a…

kerberos 下运行spark 报错 Requested user hdfs is banned

启动运行报错 main : run as user is hdfs main : requested yarn user is hdfs Requested user hdfs is bannedFailing this attempt. Failing the application.ApplicationMaster host: N/AApplicationMaster RPC port: -1queue: root.defaultstart time: 1565170753121fina…

node.js路由控制

一、工作原理 当通过浏览器访问app.js建立的服务器时&#xff0c;会看到一个简单的页面&#xff0c;实际上它已经完成了许多透明的工作&#xff0c;当访问http://localhost:3000&#xff0c;浏览器会向服务器发送请求&#xff0c;包括请求的方法、路径、HTTP协议版本和请求头信…

node.js模块引擎

一、什么是模版引擎 模版引擎是一个从页面模版根据一定的规则生成HTML的工具&#xff0c;PHP首发&#xff0c;随后出现了ASP、JSP都沿用这个模式&#xff0c;即建立一个HTML页面模版&#xff0c;插入可执行的代码。运行时动态生成HTML。缺点&#xff1a; 页面功能逻辑与页面布局…

HBase ACL管理 Hbase 权限管理

场景&#xff1a;hadoop集群已经进行kerberos认证 启动Hbase相关配置Hbase权限分为以下五种&#xff1a;Read(R) : 可以读取给定范围内数据的权限 Write(W) : 可以在给定范围内写数据 Executor(X) : 可以在指定表执行Endpoints类型的协处理 Create(C) : 可以在给定范围内创建和…

MySql索引的原理

数据库索引&#xff0c;是数据库管理系统中一个排序的数据结构&#xff0c;以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B树。 在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08…

Hadoop Kerberos 认证下 Sentry 安装 + Sentry 权限设置使用

目录 一、安装Sentry &#xff11;.&#xff2d;ariaDB中创建sentry数据库 2.CDH中添加sentry 服务 3.hive配置 启动Sentry 4.Impala配置 启动Sentry 5.Hue配置 启动Sentry 6.Hdfs配置 启动Sentry 7.重启服务&#xff0c;使配置生效 二、Sentry权限测试 1.创建hive超…

mongodb最详细的安装与配置

今天晚上才装好&#xff0c;我觉得有必要写这篇文章给你们分享一下 我是看点击打开链接这位博主的文章才装好的其中我想引用里面内容从头到尾来给你们 分享一下流程 第一步&#xff1a;下载mongodb https://www.mongodb.com/download-center#community 第二步&#xff1a;m…

vue.js安装与配置

我们在前端学习中&#xff0c;学会了HTML、CSS、JS之后一般会选择学习一些框架&#xff0c;比如Jquery、AngularJs等。这个系列的博文是针对于学习Vue.js的同学展开的。 1.如何简单地使用Vue.js 如同以前我们学过的Jquery一样&#xff0c;我们在程序中使用Vue.js时也可以使用直…

Hbase WALs(HLog) 文件存储,查看

WALs(HLog) 存储 HLog 存储位置是在&#xff0c;hbase配置目录下WALs目录&#xff0c;默认为 /hbase/WALs 与 /hbase/oldWALs /hbase/WALs : 存储未过期的日志/hbase/oldWALs : 存储已过期的日志 这里先查看WALs日志目录&#xff0c;目录格式为&#xff1a;hostname1 为 …

Elasticsearch 6.x 下载安装

下载ES 下载ES安装包上传至服务器&#xff0c;地址为&#xff1a; https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.1.0.tar.gz 上传完成后解压 tar -zxvf elasticsearch-6.1.0.tar.gz 安装JDK 这里使用jdk8&#xff0c;官网下载安装即可&#xf…

抽象工厂模式-与-工厂方法模式区别

首先来看看这两者的定义区别&#xff1a; 工厂模式&#xff1a;定义一个用于创建对象的借口&#xff0c;让子类决定实例化哪一个类 抽象工厂模式&#xff1a;为创建一组相关或相互依赖的对象提供一个接口&#xff0c;而且无需指定他们的具体类 个人觉得这个区别在于产品&#x…

Centos7.x 安装 CDH 6.x

前置条件 ntp服务安装防火墙关闭 执行以下优化代码 systemctl stop firewalld.service echo "* soft nofile 128000" >>/etc/security/limits.conf echo "* hard nofile 128000" >>/etc/security/limits.conf echo "* so…

Windows IEDA 编译Hbase源码报错 - 无法执行shell脚本

windows 下编译 hbase源码&#xff0c;报错 [ERROR] Command execution failed. java.io.IOException: Cannot run program "bash" (in directory "D:\File\ideaWorkspace\hbase-1.4.10-src\hbase-1.4.10\hbase-shaded\hbase-shaded-check-invariants\target\…