这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
请结合我的这篇博客来理解本文: 一篇文章搞懂 HBase 的内部原理
写操作
HBase 采用 LSM 树架构,天生适用于写多读少的应用场景。
在真实生产线环境中,也正是因为 HBase 集群出色的写入能力,オ能支持当下很多数据激增的业务。
需要说明的是, HBase 服务端并没有提供 update 、 delete 接口, HBase 中对数据的更新、删除操作在服务器端也认为是写入操作,不同的是,更新操作会写入一个最新版本数据,删除操作会写入一条标记为 deleted 的 KV 数据。
所以 HBase 中更新、刪除操作的流程与写入流程完全一致。
当然, HBase 数据写入的整个流程随着版本的迭代在不断优化,但总体流程变化不大。
3 个阶段
从整体架构的视角来看,写入流程可以概括为三个阶段。
- 客户端处理阶段:客户端将用户的写入请求进行预处理,并根据集群元数据定位写入数据所在的 RegionServer ,将请求发送给对应的 RegionServer .
- Region 写入阶段: RegionServer 接收到写入请求之后将数据解析出来,首先写入 WAL ,再写入对应 Region 列簇的 MemStore 。
- MemStore Flush 阶段:当 Region 中 MemStore 容量超过一定阈值,系统会异步执行 flush 操作,将内存中的数据写入文件,形成 HFile 。
6 个步骤
- 首先从 ZooKeeper 找到 hbase:meta 表的 Region 位置,然后读取 hbase:meta 表中的数据, hbase:meta 表中存储了用户表的 Region 信息
- 根据 namespace 、表名和 rowkey 信息找到写入数据对应的 Region 信息
- 找到这个 Region 对应的 RegionServer ,然后发送请求
- 把数据分别写到 HLog ( WriteAheadLog )和 MemStore 各一份
- MemStore 达到阈值后把数据刷到磁盘,生成 StoreFile 文件
- 删除 HLog 中的历史数据。
读操作
和写流程相比, HBase 读数据的流程更加复杂。
主要基于两个方面的原因:
一是因为 HBase 一次范围査询可能会涉及多个 Region 、多块缓存甚至多个数据存储文件; 二是因为 HBase 中更新操作以及删除操作的实现都很简单,更新操作并没有更新原有数据,而是使用时间戳属性实现了多版本;删除操作也并没有真正删除原有数据,只是插入了一条标记为" deleted "标签的数据,而真正的数据删除发生在系统异步执行 Major Compact 的时候。
很显然,这种实现思路大大简化了数据更新、删除流程,但是对于数据读取来说却意味着套上了层层枷锁: 读取过程需要根据版本进行过滤,对已经标记删除的数据也要进行过滤。
4 个阶段
读流程从头到尾可以分为如下 4 个阶段:
- Client - Server 读取交互逻辑
- Server 端 Scan 框架体系
- 过滤淘汰不符合查询条件的 HFile
- 从 HFile 中读取待查找 Key
其中 Client - Server 交互逻辑主要介绍 HBase 客户端在整个 scan 请求的过程中是如何与服务器端进行交互的,理解这点对于使用 Hbase Scan API 进行数据读取非常重要。
了解 Server 端 Scan 框架体系,从宏观上介绍 HbaseRegionServer 如何逐步处理一次 scan 请求。
6 个步骤
- 首先从 ZooKeeper 找到 meta 表的 region 位置,然后读取 hbase:meta 表中的数据, hbase:meta 表中存储了用户表的 region 信息
- 根据要查询的 namespace 、表名和 rowkey 信息,找到写入数据对应的 Region 信息
- 找到这个 Region 对应的 RegionServer ,然后发送请求
- 查找对应的 Region
- 先从 MemStore 查找数据,如果没有,再从 BlockCache 上读取
HBase 上 RegionServer 的内存分为两个部分一部分作为 MemStore ,主要用来写;。 另外一部分作为 BlockCache ,主要用于读数据;
- 如果 BlockCache 中也没有找到,再到 StoreFile(HFile) 上进行读取
从 StoreFile 中读取到数据之后,不是直接把结果数据返回给客户端,而是把数据先写入到 BlockCache 中,目的是为了加快后续的查询;然后在返回结果给客户端。