前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >HBase 架构原理-数据读取流程解析

HBase 架构原理-数据读取流程解析

作者头像
一个会写诗的程序员
发布于 2022-12-02 07:30:26
发布于 2022-12-02 07:30:26
9120
举报

和写流程相比,HBase读数据是一个更加复杂的操作流程,这主要基于两个方面的原因:

  • 其一是因为整个HBase存储引擎基于LSM-Like树实现,因此一次范围查询可能会涉及多个分片、多块缓存甚至多个数据存储文件;
  • 其二是因为HBase中更新操作以及删除操作实现都很简单,更新操作并没有更新原有数据,而是使用时间戳属性实现了多版本。删除操作也并没有真正删除原有数据,只是插入了一条打上”deleted”标签的数据,而真正的数据删除发生在系统异步执行Major_Compact的时候。

很显然,这种实现套路大大简化了数据更新、删除流程,但是对于数据读取来说却意味着套上了层层枷锁,读取过程需要根据版本进行过滤,同时对已经标记删除的数据也要进行过滤。

总之,把这么复杂的事情讲明白并不是一件简单的事情,为了更加条理化地分析整个查询过程,接下来笔者会用两篇文章来讲解整个过程,首篇文章主要会从框架的角度粗粒度地分析scan的整体流程,并不会涉及太多的细节实现。大多数看客通过首篇文章基本就可以初步了解scan的工作思路;为了能够从细节理清楚整个scan流程,接着第二篇文章将会在第一篇的基础上引入更多的实现细节以及HBase对于scan所做的基础优化。因为理解问题可能会有纰漏,希望可以一起探讨交流,欢迎拍砖~

Client-Server交互逻辑

运维开发了很长一段时间HBase,经常有业务同学咨询为什么客户端配置文件中没有配置RegionServer的地址信息,这里针对这种疑问简单的做下解释,客户端与HBase系统的交互阶段主要有如下几个步骤:

  1. 客户端首先会根据配置文件中zookeeper地址连接zookeeper,并读取/<hbase-rootdir>/meta-region-server节点信息,该节点信息存储HBase元数据(hbase:meta)表所在的RegionServer地址以及访问端口等信息。用户可以通过zookeeper命令(get /<hbase-rootdir>/meta-region-server)查看该节点信息。
  2. 根据hbase:meta所在RegionServer的访问信息,客户端会将该元数据表加载到本地并进行缓存。然后在表中确定待检索rowkey所在的RegionServer信息。
  3. 根据数据所在RegionServer的访问信息,客户端会向该RegionServer发送真正的数据读取请求。服务器端接收到该请求之后需要进行复杂的处理,具体的处理流程将会是这个专题的重点。

通过上述对客户端以及HBase系统的交互分析,可以基本明确两点:

  1. 客户端只需要配置zookeeper的访问地址以及根目录,就可以进行正常的读写请求。不需要配置集群的RegionServer地址列表。
  2. 客户端会将hbase:meta元数据表缓存在本地,因此上述步骤中前两步只会在客户端第一次请求的时候发生,之后所有请求都直接从缓存中加载元数据。如果集群发生某些变化导致hbase:meta元数据更改,客户端再根据本地元数据表请求的时候就会发生异常,此时客户端需要重新加载一份最新的元数据表到本地。

-----------------此处应有华丽丽的分隔线----------------

RegionServer接收到客户端的get/scan请求之后,先后做了两件事情:构建scanner体系(实际上就是做一些scan前的准备工作),在此体系基础上一行一行检索。举个不太合适但易于理解的例子,scan数据就和开发商盖房一样,也是分成两步:组建施工队体系,明确每个工人的职责;一层一层盖楼。

构建scanner体系-组建施工队

scanner体系的核心在于三层scanner: RegionScanner、StoreScanner以及StoreFileScanner。

三者是层级的关系,

一个RegionScanner由多个StoreScanner构成,一张表由多个列族组成,就有多少个StoreScanner负责该列族的数据扫描。

一个StoreScanner又是由多个StoreFileScanner组成。

每个Store的数据由内存中的MemStore和磁盘上的StoreFile文件组成。 相对应的,StoreScanner对象会雇佣一个MemStoreScanner和N个StoreFileScanner来进行实际的数据读取,每个StoreFile文件对应一个StoreFileScanner。

注意:StoreFileScanner和MemstoreScanner是整个scan的最终执行者。

对应于建楼项目,一栋楼通常由好几个单元楼构成(每个单元楼对应于一个Store),每个单元楼会请一个监工(StoreScanner)负责该单元楼的建造。而监工一般不做具体的事情,他负责招募很多工人(StoreFileScanner),这些工人才是建楼的主体。下图是整个构建流程图:

818160

  1. RegionScanner会根据列族构建StoreScanner,有多少列族就构建多少StoreScanner,用于负责该列族的数据检索 1.1 构建StoreFileScanner:每个StoreScanner会为当前该Store中每个HFile构造一个StoreFileScanner,用于实际执行对应文件的检索。同时会为对应Memstore构造一个MemstoreScanner,用于执行该Store中Memstore的数据检索。该步骤对应于监工在人才市场招募建楼所需的各种类型工匠。 1.2 过滤淘汰StoreFileScanner:根据Time Range以及RowKey Range对StoreFileScanner以及MemstoreScanner进行过滤,淘汰肯定不存在待检索结果的Scanner。上图中StoreFile3因为检查RowKeyRange不存在待检索Rowkey所以被淘汰。该步骤针对具体的建楼方案,裁撤掉部分不需要的工匠,比如这栋楼不需要地暖安装,对应的工匠就可以撤掉。 1.3 Seek rowkey:所有StoreFileScanner开始做准备工作,在负责的HFile中定位到满足条件的起始Row。工匠也开始准备自己的建造工具,建造材料,找到自己的工作地点,等待一声命下。就像所有重要项目的准备工作都很核心一样,Seek过程(此处略过Lazy Seek优化)也是一个很核心的步骤,它主要包含下面三步:
  • 定位Block Offset:在Blockcache中读取该HFile的索引树结构,根据索引树检索对应RowKey所在的Block Offset和Block Size
  • Load Block:根据BlockOffset首先在BlockCache中查找Data Block,如果不在缓存,再在HFile中加载
  • Seek Key:在Data Block内部通过二分查找的方式定位具体的RowKey

整体流程细节参见《HBase原理-探索HFile索引机制》,文中详细说明了HFile索引结构以及如何通过索引结构定位具体的Block以及RowKey

1.4 StoreFileScanner合并构建最小堆:将该Store中所有StoreFileScanner和MemstoreScanner合并形成一个heap(最小堆),所谓heap是一个优先级队列,队列中元素是所有scanner,排序规则按照scanner seek到的keyvalue大小由小到大进行排序。这里需要重点关注三个问题,首先为什么这些Scanner需要由小到大排序,其次keyvalue是什么样的结构,最后,keyvalue谁大谁小是如何确定的:

  • 为什么这些Scanner需要由小到大排序?

最直接的解释是scan的结果需要由小到大输出给用户,当然,这并不全面,最合理的解释是只有由小到大排序才能使得scan效率最高。举个简单的例子,HBase支持数据多版本,假设用户只想获取最新版本,那只需要将这些数据由最新到最旧进行排序,然后取队首元素返回就可以。那么,如果不排序,就只能遍历所有元素,查看符不符合用户查询条件。这就是排队的意义。

工匠们也需要排序,先做地板的排前面,做墙体的次之,最后是做门窗户的。做墙体的内部还需要再排序,做内墙的排前面,做外墙的排后面,这样,假如设计师临时决定不做外墙的话,就可以直接跳过外墙部分工作。很显然,如果不排序的话,是没办法临时做决定的,因为这部分工作已经可能做掉了。

  • HBase中KeyValue是什么样的结构?

HBase中KeyValue并不是简单的KV数据对,而是一个具有复杂元素的结构体,其中Key由RowKey,ColumnFamily,Qualifier ,TimeStamp,KeyType等多部分组成,Value是一个简单的二进制数据。Key中元素KeyType表示该KeyValue的类型,取值分别为Put/Delete/Delete Column/Delete Family等。KeyValue可以表示为如下图所示:

了解了KeyValue的逻辑结构后,我们不妨再进一步从原理的角度想想HBase的开发者们为什么如此对其设计。这个就得从HBase所支持的数据操作说起了,HBase支持四种主要的数据操作,分别是Get/Scan/Put/Delete,其中Get和Scan代表数据查询,Put操作代表数据插入或更新(如果Put的RowKey不存在则为插入操作、否则为更新操作),特别需要注意的是HBase中更新操作并不是直接覆盖修改原数据,而是生成新的数据,新数据和原数据具有不同的版本(时间戳);Delete操作执行数据删除,和数据更新操作相同,HBase执行数据删除并不会马上将数据从数据库中永久删除,而只是生成一条删除记录,最后在系统执行文件合并的时候再统一删除。

HBase中更新删除操作并不直接操作原数据,而是生成一个新纪录,那问题来了,如何知道一条记录到底是插入操作还是更新操作亦或是删除操作呢?这正是KeyType和Timestamp的用武之地。上文中提到KeyType取值为分别为Put/Delete/Delete Column/Delete Family四种,如果KeyType取值为Put,表示该条记录为插入或者更新操作,而无论是插入或者更新,都可以使用版本号(Timestamp)对记录进行选择;如果KeyType为Delete,表示该条记录为整行删除操作;相应的KeyType为Delete Column和Delete Family分别表示删除某行某列以及某行某列族操作;

  • 不同KeyValue之间如何进行大小比较?

上文提到KeyValue中Key由RowKey,ColumnFamily,Qualifier ,TimeStamp,KeyType等5部分组成,HBase设定Key大小首先比较RowKey,RowKey越小Key就越小;RowKey如果相同就看CF,CF越小Key越小;CF如果相同看Qualifier,Qualifier越小Key越小;Qualifier如果相同再看Timestamp,Timestamp越大表示时间越新,对应的Key越小。如果Timestamp还相同,就看KeyType,KeyType按照DeleteFamily -> DeleteColumn -> Delete -> Put 顺序依次对应的Key越来越大。

2. StoreScanner合并构建最小堆:上文讨论的是一个监工如何构建自己的工匠师团队以及工匠师如何做准备工作、排序工作。实际上,监工也需要进行排序,比如一单元的监工排前面,二单元的监工排之后… StoreScanner一样,列族小的StoreScanner排前面,列族大的StoreScanner排后面。

scan查询-层层建楼

构建Scanner体系是为了更好地执行scan查询,就像组建工匠师团队就是为了盖房子一样。scan查询总是一行一行查询的,先查第一行的所有数据,再查第二行的所有数据,但每一行的查询流程却没有什么本质区别。盖房子也一样,无论是盖8层还是盖18层,都需要一层一层往上盖,而且每一层的盖法并没有什么区别。所以实际上我们只需要关注其中一行数据是如何查询的就可以。

对于一行数据的查询,又可以分解为多个列族的查询,比如RowKey=row1的一行数据查询,首先查询列族1上该行的数据集合,再查询列族2里该行的数据集合。同样是盖第一层房子,先盖一单元的一层,再改二单元的一层,盖完之后才算一层盖完,接着开始盖第二层。所以我们也只需要关注某一行某个列族的数据是如何查询的就可以。

还记得Scanner体系构建的最终结果是一个由StoreFileScanner和MemstoreScanner组成的heap(最小堆)么,这里就派上用场了。下图是一张表的逻辑视图,该表有两个列族cf1和cf2(我们只关注cf1),cf1只有一个列name,表中有5行数据,其中每个cell基本都有多个版本。cf1的数据假如实际存储在三个区域,memstore中有r2和r4的最新数据,hfile1中是最早的数据。现在需要查询RowKey=r2的数据,按照上文的理论对应的Scanner指向就如图所示:

这三个Scanner组成的heap为<MemstoreScanner,StoreFileScanner2, StoreFileScanner1>,Scanner由小到大排列。查询的时候首先pop出heap的堆顶元素,即MemstoreScanner,得到keyvalue = r2:cf1:name:v3:name23的数据,拿到这个keyvalue之后,需要进行如下判定:

  1. 检查该KeyValue的KeyType是否是Deleted/DeletedCol等,如果是就直接忽略该列所有其他版本,跳到下列(列族)
  2. 检查该KeyValue的Timestamp是否在用户设定的Timestamp Range范围,如果不在该范围,忽略
  3. 检查该KeyValue是否满足用户设置的各种filter过滤器,如果不满足,忽略
  4. 检查该KeyValue是否满足用户查询中设定的版本数,比如用户只查询最新版本,则忽略该cell的其他版本;反正如果用户查询所有版本,则还需要查询该cell的其他版本。

现在假设用户查询所有版本而且该keyvalue检查通过,此时当前的堆顶元素需要执行next方法去检索下一个值,并重新组织最小堆。即图中MemstoreScanner将会指向r4,重新组织最小堆之后最小堆将会变为<StoreFileScanner2, StoreFileScanner1, MemstoreScanner>,堆顶元素变为StoreFileScanner2,得到keyvalue=r2:cf1:name:v2:name22,进行一系列判定,再next,再重新组织最小堆…

不断重复这个过程,直至一行数据全部被检索得到。继续下一行…

----------------此处应有华丽丽的分隔符----------------

本文从框架层面对HBase读取流程进行了详细的解析,文中并没有针对细节进行深入分析,一方面是担心个人能力有限,引入太多细节会让文章难于理解,另一方面是大多数看官可能对细节并不关心,下篇文章笔者会揪出来一些比较重要的细节和大家一起交流~

文章最后,贴出来一个一些朋友咨询的问题:Memstore在flush的时候会不会将Blockcache中的数据update?如果不update的话不就会产生脏读,读到以前的老数据?

这个问题大家可以思考思考,我们下一篇文章再见~

范欣欣,网易杭州研究院技术专家。负责网易内部Hadoop&HBase等组件内核开发运维工作,擅长大数据领域架构设计,性能优化以及问题诊断。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
HBase 读流程解析与优化的最佳实践
本文首先对 HBase 做简单的介绍,包括其整体架构、依赖组件、核心服务类的相关解析。再重点介绍 HBase 读取数据的流程分析,并根据此流程介绍如何在客户端以及服务端优化性能,同时结合有赞线上 HBase 集群的实际应用情况,将理论和实践结合,希望能给读者带来启发。如文章有纰漏请在下面留言,我们共同探讨共同学习。
Fayson
2019/04/29
1.4K0
HBase 读流程解析与优化的最佳实践
深入理解HBase架构:从理论到实践
HBase 是一个分布式的、面向列存储的 NoSQL 数据库,基于 Google 的 Bigtable 设计,用于处理海量的结构化数据。HBase 架构的独特性使其在大数据领域得到了广泛应用。本文将详细介绍 HBase 的架构设计,从理论概念到实践部署,并结合具体实例进行分析。
数字扫地僧
2024/08/27
4930
大白话彻底讲透 HBase Rowkey 设计和实现!
大家都知道 HBase 由于它存储和读写的高性能,在 OLAP 即时分析中发挥着非常重要的作用,而 RowKey 作为 HBase 的核心知识点,其设计势必会影响到数据在 HBase 中的分布,甚至会影响我们查询的效率,可以说 RowKey 的设计质量关乎了 HBase 的质量。
玄姐谈AGI
2021/02/08
1.8K0
HBase架构详解及读写流程
Master是所有Region Server的管理者,其实现为HRegionServer,主要作用有:
一个会写诗的程序员
2022/12/02
7.6K0
一篇文章完成Hbase入门
逻辑上,HBase的数据模型同关系型数据库很类似,数据存储在一张表中,有行有列。但从HBase的底层物理存储结构(K-V)来看,HBase更像是一个multi-dimensional map(多维地图)
ha_lydms
2023/11/26
1.4K0
一篇文章完成Hbase入门
hbase源码系列(十二)Get、Scan在服务端是如何处理?
继上一篇讲了Put和Delete之后,这一篇我们讲Get和Scan, 因为我发现这两个操作几乎是一样的过程,就像之前的Put和Delete一样,上一篇我本来只打算写Put的,结果发现Delete也可以走这个过程,所以就一起写了。 Get 我们打开HRegionServer找到get方法。Get的方法处理分两种,设置了ClosestRowBefore和没有设置的,一般来讲,我们都是知道了明确的rowkey,不太会设置这个参数,它默认是false的。 if (get.hasClosestRowBefore()
岑玉海
2018/03/01
2.1K0
hbase源码系列(十二)Get、Scan在服务端是如何处理?
HBase 底层原理详解(深度好文,建议收藏)
HBase 是一个分布式的、面向列的开源数据库。建立在 HDFS 之上。Hbase的名字的来源是 Hadoop database,即 Hadoop 数据库。HBase 的计算和存储能力取决于 Hadoop 集群。
五分钟学大数据
2021/03/04
1.6K0
HBase 底层原理详解(深度好文,建议收藏)
Hbase面试题(面经)整理
Hbase 中的每张表都通过行键 (rowkey) 按照一定的范围被分割成多个子表(HRegion),默认一个 HRegion 超过 256M 就要被分割成两个,由 HRegionServer 管理,管理哪些 HRegion 由 Hmaster 分配。 HRegion 存取一个子表时,会创建一个 HRegion 对象,然后对表的每个列族 (Column Family) 创建一个 store 实例, 每个 store 都会有 0个或多个 StoreFile 与之对应,每个 StoreFile 都会对应一个 HFile , HFile 就是实际的存储文件,因此,一个 HRegion 还拥有一个 MemStore 实例。
全栈程序员站长
2022/09/04
1.8K0
Hbase面试题(面经)整理
HBase入门与基本使用
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
用户1212940
2019/11/03
6470
Hbase 基础 Rowkey CF 架构 概述 预分区及Rowkey设计 学习笔记
HBase类似于数据库的存储层,HBase适用于结构化存储,并且为列式分布式数据库。
大鹅
2020/10/29
1.3K0
基于docker快速搭建hbase集群
HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。
py3study
2020/08/03
2.7K0
HBase常见面试题[通俗易懂]
读: 找到要读数据的region所在的RegionServer,然后按照以下顺序进行读取:先去BlockCache读取,若 BlockCache没有,则到Memstore读取,若Memstore中没有,则到HFile中去读。 写: 找到要写数据的region所在的RegionServer,然后先将数据写到WAL(Write-Ahead Logging,预写日志系统)中,然后再将数据写到Memstore等待刷新,回复客户端写入完成。
全栈程序员站长
2022/09/03
9920
Hbase(一)了解Hbase与Phoenix
  HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。
大道七哥
2019/09/10
2.6K0
Hbase(一)了解Hbase与Phoenix
史上最全 | HBase 知识体系吐血总结
HBase 是 BigTable 的开源 Java 版本。是建立在 HDFS 之上,提供高可靠性、高性能、列存储、可伸缩、实时读写 NoSql 的数据库系统。
五分钟学大数据
2021/11/23
5.2K0
史上最全 | HBase 知识体系吐血总结
Hbase面试题总结(大数据面试)
hbase是建立的hdfs之上,提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统。
全栈程序员站长
2022/08/23
5410
Hbase面试题总结(大数据面试)
HBase原理 | HBase读写流程和MemStore Flush(图形化通俗易懂)
Zookeeper:HBase 通过 Zookeeper 来做 Master 的高可用、 RegionServer 的监控、存储Hbase元数据(如哪个表存储在哪个RegionServer上)以及集群配置的维护等工作。
lovelife110
2022/06/08
8480
HBase原理 | HBase读写流程和MemStore Flush(图形化通俗易懂)
HBase底层原理及读写流程
1 包含访问hbase的接口,client维护着一些cache来加快对hbase的访问,比如regione的位置信息。
硅谷子
2020/12/23
8650
HBase底层原理及读写流程
深入理解HBase架构
在这篇博客文章中,我们主要深入看一下H Base 的体系结构以及在 NoSQL 数据存储解决方案主要优势。
smartsi
2019/11/28
1.8K0
深入理解HBase架构
HBase 底层原理详解(深度好文,建议收藏)
HBase 是一个分布式的、面向列的开源数据库。建立在 HDFS 之上。Hbase的名字的来源是 Hadoop database,即 Hadoop 数据库。HBase 的计算和存储能力取决于 Hadoop 集群。
五分钟学大数据
2021/01/13
4K0
HBase 底层原理详解(深度好文,建议收藏)
实战大数据,HBase 性能调优指南
在 HBase 中,row key 可以是任意字符串,最大长度 64KB,实际应用中一般为 10~100bytes,存为 byte[]字节数组,一般设计成定长的。
程序狗
2021/12/29
9300
相关推荐
HBase 读流程解析与优化的最佳实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档