深入HBase读写

简介: 深入HBase读写

1.首次读写的基本过程


在上一篇 深入HBase架构(建议收藏)中已经做了介绍。这里再重申一下。

这里要解决的主要问题是,


client如何知道去那个region server执行自己的读写请求。


有一个特殊的HBase表,叫做META table,保存了集群中各个region的位置。


而这个表的位置信息是保存在zookeeper中的。因此,当我们第一次访问HBase集群时,会做以下操作:


1)客户端从zk中获取保存meta table的位置信息,知道meta table保存在了哪个region server,并在客户端缓存这个位置信息;

2)client会查询这个保存meta table的特定的region server,查询meta table信息,在table中获取自己想要访问的row key所在的region在哪个region server上。

3)客户端直接访问目标region server,获取对应的row


这里我们需要关注一定,在读写的过程中,客户端实际上是不需要跟HMaster有任何交互的。这也是为什么我们在客户端的配置中,连接地址是填写的zookeeper的地址。


36.jpg


meta table信息都可以在client上进行缓存(apache的原生abase-client类的Connection的实现类中)。


2.写请求


从上文我们知道了,client如何找到目标region server发起请求。


接下来,就是正式的写操作了。


当client将写请求发送到客户端后,会执行以下流程。

(1)获取行锁:HBase中使用行锁保证对同一行数据的更新都是互斥操作,用以保证更新的原子性。

(2)Append HLog:顺序写入HLog中,并执行sync。

(3)写缓存memstore

(4)释放行锁


这里需要重点关注WAL。


WAL(Write-Ahead Logging)是一种高效、高可靠的日志机制。


基本原理就是在数据写入时,通过先顺序写入日志,然后再写入缓存,等到缓存写满之后统一落盘。


为什么可以提高写入性能和可靠性呢?


众所周知,对于磁盘的写入,顺序写性能是远高于随机写的。因此,WAL将将一次随机写转化为了一次顺序写加一次内存写,提高了性能。


至于可靠性,我们可以看到,因为先写日志再写缓存,即使发生宕机,缓存数据丢失,那么我们也可以通过恢复日志还原出丢失的数据。


另一方面,我们需要关注一下HBase中的各个结构的关系。


37.jpg


每个region server上只有一个HLog,但是有多个region。


每个HRegion里面有多个HStore,每个HStore会有一个写入缓存memstore,memstore是根据columnfamily来划分。


因此,在一个写入操作中,我们对任意一行的改变是落在memstore上,然后HBase并不会直接将数据落盘,而是先写入缓存,等缓存满足一定大小之后再一起落盘,生成新的HFile。


3.读请求


HBase-client上的读请求分为 两种,Get和Scan。


Get是一种随机查询的模式,根据给定的rowkey返回一行数据,虽然Get也支持输入多个rowkey返回多个结果,但是本质上是多次随机查询。具体rpc次数,看查询list的数据分布,如果都分布在一个region server上,就是一次rpc,如果是分布在3个rs,就是3次rpc,但是是并发请求和返回的,时间取决于最慢的那个。


Scan是一种批量查询的模式,根据指定的startRow和endRow进行范围扫描,获取区间内的数据。


而对于hbase服务端来说,当一个Get请求过来后,还是会转换为一个特殊的scan请求,即startrow和endrow一致的Scan请求。所以,下文的介绍,就围绕scan展开。


首先,我们要知道,HBase的写入很快,是追加多版本的形式,删除也很快,只是插入一条打上“deteled”标签的数据。因此,hbase的读操作比较复杂的,需要处理各种状态和关系。


因为Store是按照columfamily来划分的,一张表由N个列族组成,就有N个StoreScanner负责该列族的数据扫描。


当client要查询一个region,那么就会有一个RegionScanne,这个regionscannerr会创建

N个StoreScanner。


而一个store由多个storefile和一个memstore组成,


因此,StoreScanner对象会创建一个MemStoreScanner和多个StoreFileScanner进行实际数据的读取。


这些scanner首先根据TimeRange和RowKey Range过滤掉一部分肯定无用的StoreFileScanner。


剩下的scanner组成一个最小堆KeyValueHeap。这个最小堆的实际数据结构是一个优先级队列,队列中所有元素是scanner,根据scanner指向的keyvalue进行排序(scanner类似游标,每次查询一个结果后,通过next下移找下一个kv值)。


举个简单的例子。

38.jpg


假设有4个scanner组成的优先级队列,分布标记为ScannerA\B\C\D。


1)查询的时候首先pop出heap的堆顶元素。

2)第一次pop出来的是scannerA。调用 next 请求,将会返回 ScannerA 中的 rowA:cf:colA,而后 ScannerA 的指针移动到下一个 KeyValue rowA:cf:colB;

3)重新组织堆中元素,堆中的 Scanners 排序不变;

4)第二次 pop出来的还是scannerA。调用next 请求,返回 ScannerA 中的 rowA:cf:colB,ScannerA 的 current 指针移动到下一个 KeyValue rowB:cf:ColA;

5)重新组织堆中元素,由于此时scannerA的指针指向了rowB,按照 KeyValue 排序可知 rowB 小于 rowA, 所以堆内部,scanner 顺序发生改变,改变之后如下图所示:

6)第三次pop出来的就是ScannerB了。


以此类推。


39.jpg


当某个scanner 内部数据完全检索之后会就会被 close 掉,或者 rowA 所有数据检索完毕,则查询下一条。


默认情况下返回的数据需要经过 ScanQueryMatcher 过滤返回的数据需要满足下面的条件:

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


至此,就是HBase大致上的读写流程。


我们经常听说HBase数据读取要读Memstore、HFile和Blockcache,为什么我们这里说Scanner只有StoreFileScanner和MemstoreScanner,而没有BlockcacheScanner呢?


因为HBase中数据仅独立地存在于Memstore和StoreFile中,Blockcache作为读缓存,里面有StoreFile中的部分热点数据,因此,如果有数据存在于Blockcache中,那么这些数据必然存在StoreFile中。因此使用MemstoreScanner和StoreFileScanner就可以覆盖到所有数据。


而在实际的读操作时,StoreFileScanner通过索引定位到待查找key所在的block之后,会先去查看该block是否存在于Blockcache中,如果存在,那么就会去BlockCache中取出,避免IO,如果BlockCache中不存在,才会再到对应的StoreFile中读取。


相关实践学习
云数据库HBase版使用教程
  相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情: https://cn.aliyun.com/product/hbase   ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
3月前
|
存储 分布式计算 Java
HBase的读写操作是如何进行的?
HBase的读写操作是如何进行的?
17 0
|
4月前
|
缓存 分布式计算 NoSQL
分布式NoSQL列存储数据库Hbase_MR集成Hbase:读写Hbase规则(九)
分布式NoSQL列存储数据库Hbase_MR集成Hbase:读写Hbase规则(九)
38 0
|
分布式数据库 数据库 Python
Python编程:happybase读写HBase数据库
Python编程:happybase读写HBase数据库
480 0
|
分布式计算 DataWorks Java
如何使用MaxCompute Spark读写阿里云Hbase
通过Spark on MaxCompute来访问阿里云的Hbase,需要设置网络安全组、Hbase的白名单和配置Spark的参数
2180 0
如何使用MaxCompute Spark读写阿里云Hbase
|
分布式数据库 索引 Hbase
|
分布式计算 分布式数据库 Apache
Spark读写Hbase中的数据
def main(args: Array[String]) { val sparkConf = new SparkConf().setMaster("local").setAppName("cocapp").
893 0
|
监控 分布式数据库 Hbase
HBase工具之监控Region的可用和读写延时状况
1、介绍HBase集群上region数目由于业务驱动而越来越多,由于服务器本身,网络以及hbase内部的一些不确定性bug等因素使得这些region可能面临着不可用或响应延时情况。
957 0
|
4月前
|
Java Shell 分布式数据库
【大数据技术Hadoop+Spark】HBase数据模型、Shell操作、Java API示例程序讲解(附源码 超详细)
【大数据技术Hadoop+Spark】HBase数据模型、Shell操作、Java API示例程序讲解(附源码 超详细)
84 0
|
8月前
|
SQL 分布式计算 Hadoop
Hadoop集群hbase的安装
Hadoop集群hbase的安装
143 0