1. HBase回顾
1.1. HBase的历史
HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于Bigtable的能力。HBase是 Apache 的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。
Google三驾马车 :分布式文件系统 GFS 、分布式计算框架 MapReduce 、分布式列式 NoSQL 数据库BigTable; (2003~2006)
开源Hadoop三件套 :分布式文件系统 HDFS 、分布式计算框架MapReduce、分布式列式NoSQL数据库HBase; (2006~2009)
HBase :高可靠、高性能、高扩展性的 分布式存储 系统。可承载PB级的数据存储,亿次/每秒的读写请求。
1.2. HBase应用场景
HBase应用的场景与行业非常的广泛,主要侧重于大数据量场景。
HBase与大数据量场景如此契合的原因有许多,首先,HBase存储成本低,海量数据存储的成本相对较低,所需机器也非常少。
其次,HBase扩展性非常好,随着数据量的增加,只要简单地扩机器即可,HBase单个表的访问可以横向扩展到多个机器上进行访问。
此外,HBase是 Schema Free,它不像关系数据库一样事先定义好表的结构,它只需要创建表的时候,指定表和列名字就可以,列是动态生成的。
HBase有很好的容错恢复能力,比方这么多的分布式节点,单个节点宕机之后,它可以快速地将计算的资源迁移到其他节点上继续提供服务,做到用户无感知的自动恢复。
同时它还支持TTL与多版本特性,比如淘汰海量数据下的一些历史数据,可以直接使用TTL操作。当遇到一个业务场景中单个列有多个版本,可以使用多版本的特性存储多个版本的数据。
2. HBase查询原理
2.1 HBase数据模型
1> 基本概念
- Table:表名。
- Rowkey:行唯一键,也叫主键Primary Key,字典序排序存储。
- Column Family:列族,同一列族的数据集中存储,单个表可包含多列族,TTL、高效压缩。
- Column:列名。动态列,Schema Free,底层统一 byte [ ]存储。
- Timestamp :每个列的时间戳。多版本,按照时间戳最新原则排序。
2> 常见查询
- 主键查询:Rowkey Get
- 范围查询:Rowkey Scan
- 条件过滤:Rowkey Get/Scan+ Filter
- 多语言访问: Java / Python /C++/ Go /PHP/ node.js 等。
3> 范例
上方为一个普通的结构化表,ID也就是主键Rowkey,用数字表示,按顺序存储的,即使1001在1002和1003之后写入,写入后仍会按照数字顺序排在最前面。
Info和Date是两个不同列族(Cloumn Family)的名字,两个列族里包含许多列。Value表示每个列对应的值,比如小王是姓名列的值。在列族里,列的个数不是固定的,假如想在Info列组里面再加一个列,直接在列族里添加即可,这就是动态列的特点。
还有一个特性是时间戳,例子中定义了城市列和三个时间戳,杭州时间戳2019,北京时间戳2016, 厦门 时间戳2012,用户可以在写入值的时候填入时间戳,否则系统会自动按照当前时间设置时间戳。这三个版本的值会同时存在列里,如果检索1001的城市值,默认返回最新的版本。如果想把多版本都返回,则需要在检索的时候告诉系统需要几个版本,则系统会根据要求返回相应版本的数据,这就是HBase基本的数据模型。
通过这个数据模型可以看到,首先是按字典序排序存储,就可以很方便地进行范围查询,比如检索ID 1001~1003的数据,用一个Scan语句就可以把这几条数据全部返回。同时,数据是按行存储,比如指定ID 1001,可以快速地把这整行数据都取出。
HBase中有几个常见的查询场景,第一个是主键查询,基于Rowkey值,可以快速拿到某一行数据。 第二个是范围查询,可以指定Rowkey的范围,把符合条件的数据全部取出来。
第三个是条件过滤,在Get/Scan数据的时候,还想指定某个列值等于某个条件的,比方说检索范围是1001~1003,年龄等于20的数据,则系统只会把1001的数据给检测出来。
Filter相当于是过滤条件。除了指定 Rowkey的范围之外,可以指定一个单独的条件,把满足条件的数据检索出来。 HBase支持使用多语言查询,除了HBase原生支持的语言以外,还支持多种语言访问。
2.2. HBase数据查询
1> HBase Shell
下面介绍如何通过HBase的 Shell 创建一个表并写入数据,以及通过Shell把数据检索出来。 表的名字为“myTable”,列族为“f”,执行建表命令create ‘myTable’,’f’即可成功创建。
建表时还需注意以下几点:
1)建表时必需的参数:表名和列族名
2)表预分区:建表时设置分区个数、分区范围,预分区是防止数据出现热点的最佳实践。
3)列族属性:TTL、多版本、压缩、编码属性等。
建表完成后可以开始写数据。
- 写数据: put ‘myTable’,’1001′,’f:name’,’alice’
- 表名:myTable
- RowKey:1001
- 列族+列名:f:name
- 值:alice
这条命令相当于把数据alice写入Rowkey等于1001,列族等于f,列名等于name的地方。
这里需要注意的地方是,HBase在写入数据时,无法通过单独的列名确定写入的地方,需要列族+列名。这是由于表中可能存在不同的列族中有相同的列名,因此无法单独通过列名来确定列。
2> 查询
在写入数据之后,需要做数据查询,主要有以下三种方法。
主键查询 :get ‘myTable’,’1002’
范围查询 :scan ‘myTable’,{STARTROW => ‘1002’, STOPROW => ‘1004’}
条件过滤 :scan ‘myTable’,{STARTROW => ‘1002’, STOPROW => ‘1004’, FILTER=>”SingleColumnValueFilter(‘f’, ‘name’,=,’binary:bob’)”}
这里需要注意的一点是,范围查询里的STARTROW => ‘1002’是个闭区间,STOPROW => ‘1004’是个开区间,相当于取出的数据是1002和1003的数据。假设表中有1004的数据,这个数据是不会被检测出来的。
条件过滤相当于指定了一个范围外加一个条件,例如1002和1004,范围内的数据有很多,但是符合条件的数据非常少,后面跟一个过滤条件Filter,过滤的条件是’name’,=,’binary:bob’的一行数据。
以上是HBase Shell的用法,用户可以通过输入 List Filters得到当前支持的所有filter。
3> Java API 访问
除了HBase Shell这种查询的语法之外, HBase原生支持的就是 Java API访问。通过Java API我们可以快速取到某一行数据或者Scan某些数据。
上图为一个简单的Demo。
首先指定一个表名,然后new Put一个对象,相当于要写一行数据,这一行数据在new Put的时候会指定Rowkey是1001。接着指定列族、列的名字,以及列的值,然后就可以完成数据写入。
接下来可以直接执行get方法,比如指定Rowkey就可以拿到相应数据。如果想范围查询,就通过Scan指定一个范围,也可以拿到相应数据。
3. Phoenix入门
SQL 是大部分数据库通用的语言,HBase通过Phoenix组件支持SQL操作。接下来阐述除了通过Shell与Java API之外, 如何通过SQL操作HBase。
3.1. Phoenix介绍
Phoenix:OLTP and operational analytics for Apache Hadoop.
Phoenix是Salesforce公司主导的Apache开源项目,致力于“put the SQL back in NoSQL”,提升HBase的使用体验,赋予HBase OLTP和轻量级OLAP的能力。
Phoenix遵循 ANSI SQL-92标准,支持 JDBC API、Transactions、UDF、Secondary Indexes、Salt Tables等。 Phoenix语法丰富,支持group by/order by/join/subquery/function等(Phoenix Grammar)。
Phoenix具备毫秒级交互式体验,MPP并行执行,充分利用HBase Coprocessor实现计算下推。
3.2. Phoenix SQL基本使用
1> Phoenix Sqlline
下面介绍Phoenix的SQL如何操作HBase。
Phoenix有专门的Sqlline,下载之后也是一个客户端的程序,通过Sqlline连接到Phoenix集群,就可以在上面直接创建表,然后读写数据。
下面举例说明。
建表 : create table myTable(id VARCHAR primary key, name CHAR(20), age INTEGER, sex CHAR(10));’
表名 :myTable
列名和列类型 :id 主键,name 字符串类型,age 整数类型,sex 字符串类型
写数据 :upsert into myTable values(‘1001′,’alice’,18,’male’);
2> Phoenix Sqlline查询
前面介绍了HBase通过Shell检索某行数据或范围查询,Phoenix Sqlline也可以获取某行数据与简单的范围查询,如下所示。
- 主键查询:select * from myTable where id=’1002′;
- 范围查询:select * from myTable where id>=’1002′ and id<=’1004′ limit 10;
- 过滤查询:select * from myTable where id>=’1002′ and id<=’1004′ and name=’bob’ limit 10;
可以看到,通过 SQL语句 操作HBase会更加地简单,对于开发人员而言也是更加简单易用。
3> 丰富的语法支持
Phoenix的语法非常丰富,在官网可以看到它语法的列表,它基本涵盖类似于SQL92的所有语法,可以看到详尽的语法使用方法。
丰富的语法
上方为线上的一个查询场景,它也可以做到两个不同表的查询,这也是非常常见的一种语法。
3. 查询加速
3.1. 多样化的查询
在HBase的使用过程中,除了上文讲到的HBase支持的查询之外,随着数据量的增加,业务的查询场景会更加多样化,下面简单介绍了几个来源于业务的真实需求。
多维查询:即席查询,一般是不固定的列随机组合。
count计数:获取数据表的总行数,或者返回一次查询命中的数据条数。
指定列排序:按照指定列降序或升序,比方说按照订单时间降序输出结果。
分词检索:支持文本字段的分词检索,返回相关性较高的结果数据。
统计聚合:按照某个字段进行聚类统计,求取sum/max/min/avg等,或者返回去重后的结果集。
模糊查询:查询以“中国”开头的数据,可以匹配出“中国人民”的结果集,类似 MySQL 的like语法。
通用解决方案
1. 协处理器:计算下推,服务端执行逻辑。
2. 二级索引:变换数据存储格式,加速非主键查询。
3. 全文索引 :引入搜索引擎解决查询难题。
3.2. 协处理器
HBase原生协处理器Coprocessor,逻辑在服务端运行,避免移动数据,加速处理。
协处理器Coprocessor有两种模式:
1. Observer
与数据库的触发器类似,在一些特定事件发生时执行 回调函数 。HBase服务端的内核逻辑已经在固定的流程中埋点,例如在put写数据前执行一段函数prePut,put写数据后执行一段函数postPut。
2. Endpoint
与数据库的存储过程类似,客户端远程调用服务端的代码,例如HBase原生支持的聚合Aggregate,求max/min/avg。
3.3. 二级索引 – 非主键索引
前文主要阐述了主键Rowkey的查询,如果检索条件是指定一个列去查询,其实就没有指定主键了,需要通过二级索引的非主键索引解决,下面举例说明。
如上方所示,扫描表myTable,检索条件是’name’,=,’binary:bob’。
如果表的数据非常大,需要把所有的数据都扫描出来,这种查询非常消耗资源,并且由于逐步扫描,可能会超时。
面对这种场景,最通用的解决方案就是用HBase的二级索引,下图为HBase二级索引的查询模型。
如上图所示,右边是主表的查询,包含按顺序存储的Rowkey与几个列。 如果检索条件只有Col2,就可以建一个二级索引。
左边是一个二级索引表,它是一个单独的表,表的主键由Col2和Rowkey组成,唯一确定了索引表的一行数据,可以快速检测出符合条件的数据。
3.4. 二级索引的实现
Phoenix基于协处理器实现二级索引。
上方为是基于Observer实现二级索引的一个例子。
在Put/Delete流程中解析写入的数据,构造索引数据,写入到 索引 表中。在Scan流程中解析查询语法,命中索引,则查询索引表,没有命中索引,则查询原表。
3.5. 全文索引(HBase+Elasticsearch)
还有一种通用的解决方案是全文索引(HBase+Elasticsearch),通过HBase的高效查询与Elasticsearch的全文索引, 可以满足多样化的查询场景。
全文索引(HBase+Elasticsearch)有许多方案,如业务双写、数据自动同步、Observer触发器等。
1.业务双写
- 简单,业务快速落地。
- 开发成本高:应用同时与HBase和 Elasticsearch交互。
- 维护复杂:熟悉HBase和Elasticsearch 技术栈。
- 数据不一致。
2.数据自动同步
- 无需双写,只需双读,开发成本降低。
- 数据最终一致。
- 维护复杂:熟悉HBase和Elasticsearch 技术栈、数据同步服务。
3. Observer触发器
- 仅与HBase交互,应用开发成本进一步 降低,但要额外开发Observer程序。
- 维护复杂:熟悉HBase和Elasticsearch 技术栈,Observer容易引起系统不稳定。
- 写入延迟:Elasticsearch写入阻塞全局。
4. 总结
如下图所示,整个HBase的数据生态十分丰富,可以看到有很多开源产品,首先上游APP、日志、数据库等高并发写入 到HBase之后, Spark 、Flink等可以直接读取HBase数据做分析。同时它们的结果也可以批量写入/Bulkload到HBase。
然后通过同步工具,如LTS、 Kettle 等,可以把HBase的数据全量同步到离线分析系统。 也可以通过增量订阅工具,如LTS、Replication,订阅到消息队列,下游再对接实时计算的产品,如Flink、Spark。 以上就是HBase的大致生态环境。
HBase数据生态