基于HBase的 海量数据查询与检索解析

HBase回顾

(一)HBase的历史

基于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级的数据存储,亿次/每秒的读写请求。 


(二)HBase应用场景

基于HBase的 海量数据查询与检索解析

HBase应用的场景与行业非常的广泛,主要侧重于大数据量场景。

基于HBase的 海量数据查询与检索解析

HBase与大数据量场景如此契合的原因有许多,首先,HBase存储成本低,海量数据存储的成本相对较低,所需机器也非常少。


其次,HBase扩展性非常好,随着数据量的增加,只要简单地扩机器即可,HBase单个表的访问可以横向扩展到多个机器上进行访问。


此外,HBase是Schema Free,它不像关系数据库一样事先定义好表的结构,它只需要创建表的时候,指定表和列名字就可以,列是动态生成的。


HBase有很好的容错恢复能力,比方这么多的分布式节点,单个节点宕机之后,它可以快速地将计算的资源迁移到其他节点上继续提供服务,做到用户无感知的自动恢复。


同时它还支持TTL与多版本特性,比如淘汰海量数据下的一些历史数据,可以直接使用TTL操作。当遇到一个业务场景中单个列有多个版本,可以使用多版本的特性存储多个版本的数据。


HBase查询原理


(一)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.范例

基于HBase的 海量数据查询与检索解析

上方为一个普通的结构化表,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原生支持的语言以外,还支持多种语言访问。


(二)HBase数据查询


1. HBase Shell


下面介绍如何通过HBase的Shell创建一个表并写入数据,以及通过Shell把数据检索出来。 表的名字为“myTable”,列族为“f”,执行建表命令create 'myTable','f’即可成功创建。

基于HBase的 海量数据查询与检索解析

建表时还需注意以下几点:
1)建表时必需的参数:表名和列族名

2)表预分区:建表时设置分区个数、分区范围,预分区是防止数据出现热点的最佳实践。

3)列族属性:TTL、多版本、压缩、编码属性等。


建表完成后可以开始写数据。

·写数据: put 'myTable','1001','f:name','alice’ 

·表名:myTable
·RowKey:1001
·列族+列名:f:name

·值:alice


这条命令相当于把数据alice写入Rowkey等于1001,列族等于f,列名等于name的地方。

基于HBase的 海量数据查询与检索解析

这里需要注意的地方是,HBase在写入数据时,无法通过单独的列名确定写入的地方,需要列族+列名。这是由于表中可能存在不同的列族中有相同的列名,因此无法单独通过列名来确定列。


2.查询


在写入数据之后,需要做数据查询,主要有以下三种方法。

主键查询:get 'myTable','1002’

范围查询:scan 'myTable',{STARTROW => '1002', STOPROW => '1004’}

条件过滤:scan 'myTable',{STARTROW => '1002', STOPROW => '1004', FILTER=>"SingleColumnValueFilter('f', 'name',=,'binary:bob')"}

基于HBase的 海量数据查询与检索解析

这里需要注意的一点是,范围查询里的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某些数据。

基于HBase的 海量数据查询与检索解析

上图为一个简单的Demo。


首先指定一个表名,然后new Put一个对象,相当于要写一行数据,这一行数据在new Put的时候会指定Rowkey是1001。接着指定列族、列的名字,以及列的值,然后就可以完成数据写入。


接下来可以直接执行get方法,比如指定Rowkey就可以拿到相应数据。如果想范围查询,就通过Scan指定一个范围,也可以拿到相应数据。


Phoenix入门


SQL是大部分数据库通用的语言,HBase通过Phoenix组件支持SQL操作。接下来阐述除了通过Shell与Java API之外, 如何通过SQL操作HBase。


(一)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实现计算下推。

基于HBase的 海量数据查询与检索解析

(二)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');

基于HBase的 海量数据查询与检索解析

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;

基于HBase的 海量数据查询与检索解析

可以看到,通过SQL语句操作HBase会更加地简单,对于开发人员而言也是更加简单易用。


3. 丰富的语法支持


Phoenix的语法非常丰富,在官网可以看到它语法的列表,它基本涵盖类似于SQL92的所有语法,可以看到详尽的语法使用方法。

基于HBase的 海量数据查询与检索解析

丰富的语法

基于HBase的 海量数据查询与检索解析

基于HBase的 海量数据查询与检索解析

上方为线上的一个查询场景,它也可以做到两个不同表的查询,这也是非常常见的一种语法。


查询加速


(一)多样化的查询


在HBase的使用过程中,除了上文讲到的HBase支持的查询之外,随着数据量的增加,业务的查询场景会更加多样化,下面简单介绍了几个来源于业务的真实需求。


多维查询:即席查询,一般是不固定的列随机组合。 

count计数:获取数据表的总行数,或者返回一次查询命中的数据条数。 

指定列排序:按照指定列降序或升序,比方说按照订单时间降序输出结果。 

分词检索:支持文本字段的分词检索,返回相关性较高的结果数据。 

统计聚合:按照某个字段进行聚类统计,求取sum/max/min/avg等,或者返回去重后的结果集。 

模糊查询:查询以“中国”开头的数据,可以匹配出“中国人民”的结果集,类似MySQL的like语法。 


通用解决方案

1. 协处理器:计算下推,服务端执行逻辑。
2. 二级索引:变换数据存储格式,加速非主键查询。

3. 全文索引:引入搜索引擎解决查询难题。


(二)协处理器


HBase原生协处理器Coprocessor,逻辑在服务端运行,避免移动数据,加速处理。


协处理器Coprocessor有两种模式:


1. Observer

与数据库的触发器类似,在一些特定事件发生时执行回调函数。HBase服务端的内核逻辑已经在固定的流程中埋点,例如在put写数据前执行一段函数prePut,put写数据后执行一段函数postPut。

2. Endpoint

与数据库的存储过程类似,客户端远程调用服务端的代码,例如HBase原生支持的聚合Aggregate,求max/min/avg。


(三)二级索引 - 非主键索引


前文主要阐述了主键Rowkey的查询,如果检索条件是指定一个列去查询,其实就没有指定主键了,需要通过二级索引的非主键索引解决,下面举例说明。

基于HBase的 海量数据查询与检索解析

如上方所示,扫描表myTable,检索条件是'name',=,'binary:bob'。


如果表的数据非常大,需要把所有的数据都扫描出来,这种查询非常消耗资源,并且由于逐步扫描,可能会超时。


面对这种场景,最通用的解决方案就是用HBase的二级索引,下图为HBase二级索引的查询模型。

基于HBase的 海量数据查询与检索解析

如上图所示,右边是主表的查询,包含按顺序存储的Rowkey与几个列。 如果检索条件只有Col2,就可以建一个二级索引。


左边是一个二级索引表,它是一个单独的表,表的主键由Col2和Rowkey组成,唯一确定了索引表的一行数据,可以快速检测出符合条件的数据。


(四)二级索引的实现


Phoenix基于协处理器实现二级索引。

基于HBase的 海量数据查询与检索解析

上方为是基于Observer实现二级索引的一个例子。


在Put/Delete流程中解析写入的数据,构造索引数据,写入到索引表中。在Scan流程中解析查询语法,命中索引,则查询索引表,没有命中索引,则查询原表。


(五)全文索引(HBase+Elasticsearch)


还有一种通用的解决方案是全文索引(HBase+Elasticsearch),通过HBase的高效查询与Elasticsearch的全文索引, 可以满足多样化的查询场景。


全文索引(HBase+Elasticsearch)有许多方案,如业务双写、数据自动同步、Observer触发器等。

1.业务双写

基于HBase的 海量数据查询与检索解析

·简单,业务快速落地。 

·开发成本高:应用同时与HBase和 Elasticsearch交互。 

·维护复杂:熟悉HBase和Elasticsearch 技术栈。 

·数据不一致。


2.数据自动同步

基于HBase的 海量数据查询与检索解析

·无需双写,只需双读,开发成本降低。
·数据最终一致。
·维护复杂:熟悉HBase和Elasticsearch 技术栈、数据同步服务。


3. Observer触发器

基于HBase的 海量数据查询与检索解析

·仅与HBase交互,应用开发成本进一步 降低,但要额外开发Observer程序。 

·维护复杂:熟悉HBase和Elasticsearch 技术栈,Observer容易引起系统不稳定。 

·写入延迟:Elasticsearch写入阻塞全局。

上一篇:Linux Shell脚本之通过json判断应用程序内部运行状态


下一篇:python进阶--queue队列