HBase读链路分析
简介: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会触发不同的操作,见下表。

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读链路分析的更多相关文章
- HBase读延迟的12种优化套路
任何系统都会有各种各样的问题,有些是系统本身设计问题,有些却是使用姿势问题.HBase也一样,在真实生产线上大家或多或少都会遇到很多问题,有些是HBase还需要完善的,有些是我们确实对它了解太少.总结 ...
- hbase读的性能优化
任何系统都会有各种各样的问题,有些是系统本身设计问题,有些却是使用姿势问题.HBase也一样,在真实生产线上大家或多或少都会遇到很多问题,有些是HBase还需要完善的,有些是我们确实对它了解太少.总结 ...
- HBase Scan流程分析
HBase Scan流程分析 HBase的读流程目前看来比较复杂,主要由于: HBase的表数据分为多个层次,HRegion->HStore->[HFile,HFile,...,MemSt ...
- 分布式存储系统Kudu与HBase的简要分析与对比
本文来自网易云社区 作者:闽涛 背景 Cloudera在2016年发布了新型的分布式存储系统——kudu,kudu目前也是apache下面的开源项目.Hadoop生态圈中的技术繁多,HDFS作为底层数 ...
- HBase读延迟的12种优化套
任何系统都会有各种各样的问题,有些是系统本身设计问题,有些却是使用姿势问题.HBase也一样,在真实生产线上大家或多或少都会遇到很多问题,有些是HBase还需要完善的,有些是我们确实对它了解太少. 总 ...
- HBase工程师线上工作经验总结----HBase常见问题及分析
阅读本文可以带着下面问题:1.HBase遇到问题,可以从几方面解决问题?2.HBase个别请求为什么很慢?你认为是什么原因?3.客户端读写请求为什么大量出错?该从哪方面来分析?4.大量服务端excep ...
- (转)HBase工程师线上工作经验总结----HBase常见问题及分析
阅读本文可以带着下面问题:1.HBase遇到问题,可以从几方面解决问题?2.HBase个别请求为什么很慢?你认为是什么原因?3.客户端读写请求为什么大量出错?该从哪方面来分析?4.大量服务端excep ...
- Hbase源码分析:Hbase UI中Requests Per Second的具体含义
Hbase源码分析:Hbase UI中Requests Per Second的具体含义 让运维加监控,被问到Requests Per Second(见下图)的具体含义是什么?我一时竟回答不上来,虽然大 ...
- HBase写请求分析
HBase作为分布式NoSQL数据库系统,不单支持宽列表.而且对于随机读写来说也具有较高的性能.在高性能的随机读写事务的同一时候.HBase也能保持事务的一致性. 眼下HBase仅仅支持行级别的事务一 ...
- 读APUE分析散列表的使用
最近学习APUE读到避免线程死锁的部分,看到部分源码涉及到避免死锁部分,源码使用了散列表来实现对结构(struct)的存储与查找. 本文不讨论代码中的互斥量部分. #include <stdli ...
随机推荐
- day01-1-需求分析和项目设计
满汉楼01 1.需求分析 满汉楼项目说明 因为javaGUI不是学习的重点,这里将继续使用控制台界面来代替界面和事件处理 完成的功能: 登录 订座 点餐 结账 查看账单等功能 在实际项目中,独立完成项 ...
- java -jar xxx.jar命令执行jar包时出现Error: Invalid or corrupt jarfile xxx.jar解决方案
MANIFEST.MF清单文件内容: Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.2 Created-By: 1.8.0_60-b27 (Ora ...
- GDB调试之多线程
1.set scheduler-locking off/on/step 调试时除了当前线程在运行,要想规定其他线程的运行情况用这个命令,有三个选择: set scheduler-locking off ...
- 使用Wireshark在RTP流中提取中264数据(针对udp)(转)
调试rtsp收发流时,经常会需要抓包以确认是网络问题还是程序问题还是其它问题.通过tcpdump或者wireshark抓到的包通常是rtp流,保存为.pcap格式文件后中,可通过wireshark进行 ...
- 记录--uniapp 应用APP跳转微信小程序
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 最近APP项目开发完成,在评审会上老板提了一个需求,想在开发的APP上添加一个链接,可以跳转公司的小程序商城. 原以为会很复杂,结果只有短 ...
- WPF MVVM 集合内容更改时如何添加操作,触发通知
用过mvvm设计WFP程序的人都知道,在我们mvvm中有一个非常重要的接口叫做 INotifyPropertyChanged 这个接口的主要作用是用于触发属性更改时向我们xaml中绑定此属性值的控件发 ...
- modelsim常用操作之波形仿真
modelsim波形仿真的新手问题 1.实验目的 在刚接触modelsim时,被其繁复的操作流程所困,一度只能依靠在quartus中修改代码编译后再重启modelsim,自动导入才能得到波形.这样的操 ...
- Docker技术全景:推动云原生架构的关键力量
本文深入探讨了Docker的发展历程.核心技术.在云服务中的应用以及其庞大生态系统.通过分析Docker如何革新容器化技术.加速云服务的发展,并构建一个多元化的生态系统,本文揭示了Docker在当代云 ...
- java使用ftp连接linux处理文件
1.Maven依赖 <!-- FTP使用包 --> <dependency> <groupId>commons-net</groupId> <ar ...
- Unit 1 Computer hardware【石家庄铁道大学-专业英语课程复习资料】
Unit 1 Computer hardware 1.Introduction of computer A computer is a machine that can be instructed t ...