HBase读链路分析

本文涉及的产品
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,通用型 2核4GB
简介: HBase的存储引擎是基于LSM-Like树实现的,更新操作不会直接去更新数据,而是使用各种type字段(put,delete)来标记一个新的多版本数据,采用定期compaction的形式来归档合并数据。这种数据结构将写操作变得非常简单且高效,但是却给读造成了很大的困扰。读取过程需要根据列族读取不同HFile中的数据;还需要根据版本进行过滤,同时对已经标记删除的数据也要进行过滤;硬盘中的数据与MemStore中的数据重合时,还需要执行合并,最后在内存中拼接成一行完整的数据再向上返回。本文粗粒度地展示了HBase的读取链路,欢迎一起探讨交流~

正文之前

在讲HBase的读路径时,我们先来看几个简单的类图。

InternalScanner是一个Interface主要提供了两个方法,next(List<Cell> result)方法——获取下一行的数据。而next(List<Cell> result, ScannerContext scannerContext)提供功能相同,只不过允许传入一个ScannerContext用以记录当前scan任务的上下文,判断是否可以提前结束、是否要去读下一列、是否要去读下一行等。并且发生在InternalScanner中的数据比较等操作,都是基于byte[](而不用先转化为RowResults),更加接近于数据在物理上的存储形式,可以获得更高的性能。

KeyValueScanner也是一个接口,换成CellScanner可能更容易理解。对,它主要提供在一个“可读取的对象上”,获取cell的能力。这里使用“可读取的对象”这个词,主要是因为它可以是一个物理概念上的HFile,但也可以是逻辑意义上有迭代读取能力的scanner。

最后一个关键的类就是KeyValueHeap,该类实现了KeyValueScanner与InternalScanner接口,具备了获取cell及获取行的能力。KeyValueHeap中还有一个关键的属性,为heap,它是一个PriorityQueue<KeyValueScanner>对象,comparator = CellComparatorImp(即按照key的格式:rowkey:family:qualifier:timestamp)。即KeyValueHeap允许传入多个KeyValueScanner,通过PriorityQueue的形式将这些scanner管理起来,向上提供获取cell及获取行数据的能力!

有了InternalScanner,KeyValueScanner和KeyValueHeap其实已经可以做很多事情了。

我们知道,HBase的查询抽象地来看的话,是表现为下面这个流程的:

即从不同的HFile中进行数据读取,在内存中进行一个MergeSort,拼接成一行数据向上返回。

你们看KeyValueScanner、InternalScanner是不是就像其负责中HFile的读取Scanner,而KeyValueHeap负责的其实就是图中的MergeSort的任务。KeyValueHeap控制着下层KeyValueScanner、InternalScanner的数据读取,KeyValueScanner、InternalScanner是真正读取数据的Scanner。

好,大体的流程思路已经讲清楚了。其实HBase的读取流程远比这复杂,涉及的对象也更多,但有了上面的基础相信可以理解得很容易,接下来我们来仔细看看HBase的读取流程。

正文

我们从RegionScanner出发,仔细看看HBase的读取流程。

上图中的RegionScanner主要靠成员变量storeHeap,joinedHeap(KeyValueHeap)进行数据读取迭代。而StoreScanner也不是一个单纯的Scanner,而是扮演了跟RegionScanner类似的角色,它也拥有自己的heap,以此来进行数据的读取。跟【正文之前】说的一样,KeyValueHeap控制着下层KeyValueScanner、InternalScanner的数据读取,KeyValueScanner、InternalScanner是真正读取数据的Scanner。只不过RegionScanner中多嵌了一层StoreScanner(KeyValueHeap),变成了这样的调用链路:KeyValueHeap(RegionScanner)->KeyValueHeap(StoreScanner)

->KeyValueScanner,InternalScanner(StoreFileScanner及SegmentScanner)。

为什么HBase要这样封装?

其实是为了抽象不同的功能。

简单来说,

1)StoreScanner是为了联合StoreFileScanner与SegmentScanner向上提供整行的数据迭代读取功能。

2)而RegionScanner,一方面是对获取的数据做了过滤功能,另一方面是为了将全部数据分为两段获取形式(storeHeap和joinedHeap),用以优化性能。因为从storeHeap中获取的数据如果会被过滤,那么就没有必要再获取joinedHeap中的数据了。

详细内容我们见下文。

HBase的读取任务开始之前需要构建初始的Scanner体系,涉及RegionScanner与StoreScanner的对象初始化,我们详细来看:

1)RegionScanner对象的初始化:

1.建立RegionScanner对象,准备开始Scan任务涉及的所有Scanner的生成。

2.根据scan任务涉及的所有column family,在本region上分别会为其中的每个column family生成一个StoreScanner。如果开启了on-demand column family loading,那么会根据传入FilterList的isFamilyEssential方法进行判断,如果isFamilyEssential,那么会将该StoreScanner放入storeHeap中,否则放入joinedHeap中

3.storeHeap和joinedHeap中存放StoreScanner的形式为PriorityQueue,优先级为CellComparatorImp。

2)StoreScanner对象的初始化

接下来我们介绍RegionScanner对象的初始化中,我们一笔带过的StoreScanner的生成过程:

1.根据scan.isReversed()控制StoreScanner中的Scanner的优先级顺序。

2.根据传入的scan信息,生成matcher内置对象,该对象在查询过程中会对StoreScanner读取的数据进行一个筛选。

3.根据scan信息startRow,stopRow在storeEngine中查询出涉及的HStoreFile,对这些HStoreFile分别建立StoreFileScanner,组成scannerList,并且StoreFileComparators.SEQ_ID为优先级(maxSequenceId升序,FileSize降序,BulkTime升序,PathName升序)。

4.对scannerList根据timestamp range, row key range, bloomFilter做一个过滤

5.scannerList中剩余的scanner根据startRow,stopRow将指针seek到正确的位置。

6.将scanners以PriorityQueue的形式组织,优先级同样为CellComparatorImp。


PS:StoreFileComparators.SEQ_ID —— Comparator.comparingLong(HStoreFile::getMaxSequenceId)  .thenComparing(Comparator.comparingLong(new GetFileSize()).reversed())  .thenComparingLong(new GetBulkTime()).thenComparing(new GetPathName())

组建好需要Scanner体系之后,后续就是读取流程了。

读取流程如下图所示:

RegionScanner主要负责以下功能:

其包含storeHeap与joinedHeap都为KeyValueHeap的对象实例,heap底层是包含了多个StoreScanner组成的PriorityQueue,comparator = CellComparatorImp。向上提供符合条件的整行数据的迭代查询。

1.循环从storeHeap上获取cell数据,以此判断是否还存在待获取数据。如果没有,return false。如果有:

2.那么先从storeHeap上获取family essential相关的数据,使用filter进行过滤。如果被过滤,continue loop。如果没有:

3.那么从joinedHeap上获取剩余数据,返回。


StoreScanner主要负责以下功能:

StoreScanner虽然是实现了KeyValueScanner和InternalScanner的类,但主要靠其成员变量heap(KeyValueHeap)来完成必要的操作。heap由多个StoreFileScanner实例按照PriorityQueue组成,comparator = CellComparatorImp。

1.循环从heap中获取cell。

2.通过matcher匹配cell获得返回的MatchCode,不同MatchCode会触发不同的操作,见下表。

MatchCode

Operation

INCLUDE

check

fill results

heap.next()

continue Loop

INCLUDE_AND_SEEK_NEXT_ROW

check

fill results

seekOrSkipToNextRow

continue Loop

INCLUDE_AND_SEEK_NEXT_COL

check

fill results

seekOrSkipToNextColumn

continue Loop

DONE

return results

DONE_SCAN

close heap

return

SEEK_NEXT_ROW

if no data: return false;

else:

seekOrSkipToNextRow

continue;

SEEK_NEXT_COL

seekOrSkipToNextColumn

continue;

SKIP

heap.next()

continue Loop

SEEK_NEXT_USING_HINT

seekAsDirection

or heap.next()

3.不停循环,直到数据组成整行,向上返回。

StoreScanner中KeyValueHeap的next功能:

storeScanner中的heap.next()究竟做了什么?简单来说,做了以下两件事情:1)从current(当前的StoreFileScanner,不在heap中)获取cell返回2)更新当前current,把current放回heap重新排序,再获取当前最优先的StoreFileScanner作为current。

具体做法如下:

1.从当前的StoreFileScanner current中获取下一个cell(kvReturn)。再获取kvReturn往后的第一个cell(kvNext)

2.判断kvNext是否为空。为空代表当前current读取完毕,需要从heap中获取下一个scanner记为current。不为空则

3.从当前heap中获取第一个scanner,与current 进行对比。判断它们谁通过peek()获得的cell key最小,如果scanner更小,那么把current放回heap。重新heap.poll()获得最新current。

4.返回kvReturn cell。

至此整个HBase的读路径分析结束,留待补充的点:

1.Matcher的实现逻辑分析。

2.BloomFilter的过滤分析。

3.StoreFileScanner以下直到HDFS之间的链路分析,中间涉及一个BlockCache。

相关实践学习
云数据库HBase版使用教程
&nbsp; 相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情:&nbsp;https://cn.aliyun.com/product/hbase &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
分布式计算 Hadoop 关系型数据库
Hadoop任务scan Hbase 导出数据量变小分析
Hadoop任务scan Hbase 导出数据量变小分析
53 0
|
4月前
|
SQL 消息中间件 分布式数据库
基于Flume+Kafka+Hbase+Flink+FineBI的实时综合案例(三)离线分析
基于Flume+Kafka+Hbase+Flink+FineBI的实时综合案例(三)离线分析
63 0
|
6月前
|
存储 SQL 分布式数据库
记录一次 Hbase 线上问题的分析和解决,并分析总结下背后的知识点 - KeyValue size too large
记录一次 Hbase 线上问题的分析和解决,并分析总结下背后的知识点 - KeyValue size too large
|
8月前
|
存储 分布式计算 关系型数据库
|
分布式数据库 Hbase
|
分布式数据库 Hbase
《HBase 基本知识介绍及典型案例分析》电子版地址
HBase 基本知识介绍及典型案例分析
70 0
《HBase 基本知识介绍及典型案例分析》电子版地址
|
SQL 消息中间件 存储
基于 HBase 的大数据在线分析|学习笔记
快速学习基于 HBase 的大数据在线分析
338 0
基于 HBase 的大数据在线分析|学习笔记
|
SQL 存储 消息中间件
|
存储 SQL 分布式计算
HBase 与 Cassandra 架构对比分析的经验分享
HBase 与 Cassandra 架构对比分析的经验分享
|
大数据 分布式数据库 Hbase
《HBase实战:基于HBase的大数据在线分析》电子版地址
HBase实战:基于HBase的大数据在线分析
93 0
《HBase实战:基于HBase的大数据在线分析》电子版地址