hbase实践之写流程拾遗
keyvalue
KeyValue中包含了丰富的自我描述信息:

KeyValue是支撑”稀疏矩阵”设计的一个关键点:一些Key相同的任意数量的独立KeyValue就可以构成一行数据。但这种设计带来的一个显而易见的缺点:每一个KeyValue所携带的自我描述信息,会带来显著的数据膨胀。
为什么rowkey不能太长?columnfamily、qualifiter尽量短?
行级事务模型
写写并发控制
包括单行、批量多行。
- 单行:行锁
- 多行:两阶段锁协议,即:
(1) 获取所有待写入(更新)行记录的行锁
(2) 开始执行写入(更新)操作
(3) 写入完成之后再统一释放所有行记录的行锁
读写并发控制:MVCC
Mutil Version Concurrent Control。HBase中MVCC机制实现主要分为两步:
(1) 为每一个写(更新)事务分配一个Region级别自增的序列号
(2) 为每一个读请求分配一个已完成的最大写事务序列号
MVCC的精髓是写入的时候分配递增版本信息(SequenceId),读取的时候分配唯一的版本用于读取可见,比之大的版本不可见。这里需要注意版本必须递增,而且版本递增的范围一定程度上决定了事务是什么事务,比如HBase是Region级别的递增版本,那么事务就是region级别事务。
非必须情况,不要使用行锁。
sequenceId
为什么要有sequenceId?
- 先写HLog,再写memstore,两个地方的数据是一致的,两者如何一一对应?一一对应后,日志可删除(因为只能保留有限日志)。
- HLog日志如何删除?HLog只能保存一定数量的日志,如果删除日志文件,先删除谁? 先删除年龄最老的日志文件,则其sequenceId最小。如果这些数据没有落盘,就可以强制对其执行flush,之后就可以将HLog删除。
- RegionServer宕机,memsotre中数据丢失,数据从哪里开始恢复?
本质问题:mestore、Hlog中的数据是同一份,他们需要同一个标识。
- 读写并发控制
- HLog文件的基本结构

<logseq#-for-entire-txn>:<-1, 3, , , >
The -1 marker is just a special way of being backward compatible with an old HLog which would have contained a single . -1只是一个标志, 是为了对旧版本兼容.
问题一:HLog在什么时候可以过期回收?HLog在什么时候可以过期回收?
RegionServer会为每个Region维护了一个变量oldestUnflushedSequenceId(实际上是为每个Store,为了方便讲解,此处暂且认为是Region,不影响原理),表示这个Region最早的还未落盘的seqid ,即这个seqid之前的所有数据都已经落盘。
下图是flush过程中oldestUnflushedSequenceId变量变化的示意图,初始时为null,假设在某一时刻阶段二RegionA(红色方框)要执行flush,中间HLog中sequenceId为1~4对应的数据将会落盘,在执行flush之前,HBase会append一个空的Entry到HLog,仅为获取下一个sequenceId(5),并将这个sequenceId赋给OldestUnflushedSequenceId-RegionA。如图中第三阶段OldestUnflushedSequenceId-RegionA指向sequenceId为5的Entry。


场景一中右侧HLog还有未落盘的数据(sequenceid=5还未落盘),因此不能删除;而场景二中右侧HLog的所有数据都已经落盘,所以这个HLog理论上就已经可以被删除回收。
问题二:HLog数量超过阈值(maxlogs)之后删除最早HLog,应该强制刷新哪些Region?

HLog日志文件超过阈值,会删除最老的,根据OldestUnflushedSequenceId,如果该日志中有数据未写磁盘,则强制刷写磁盘,然后将该日志文件删除。
问题三:RegionServer宕机恢复replay日志时哪些WALEntry需要被回放,哪些会被skip?
理论上来说只需要回放Memstore中没有落地的数据对应的WALEntry,已经落地数据对应的WALEntry可以skip。可问题是RegionServer已经宕机了,<region, oldestUnflushedSequenceId> 对应信息肯定没有了,如何是好?想办法持久化呗,上文分析oldestUnflushedSequenceId变量是flush时产生的一个变量,这个变量完全可以以flush的时候以元数据的形式写到HFile中(代码见下图):

到目前为止,上面所有分析都基于一个事实:hbase中flush操作是region级别操作,即每次执行flush都需要整个region中的所有store全都执行flush。
Per-CF Flush
map<region, map<store, oldestUnflushedSequenceId>>
RS宕机与恢复


由HMaster来管理并切分日志==>RegionServer切分日志(小文件多)==>RegionServer切分日志后,直接在Region-Buffer中回放。
Region 切分
Region切分触发策略
- ConstantSizeRegionSplitPolicy
- IncreasingToUpperBoundRegionSplitPolicy:(#regions) * (#regions) * (#regions) * flush size * 2
在大集群条件下对于很多大表来说表现很优秀,但并不完美,这种策略下很多小表会在大集群中产生大量小region,分散在整个集群中。而且在发生region迁移时也可能会触发region分裂。
- SteppingSplitPolicy:如果region个数等于1,切分阈值为flush size * 2,否则为MaxRegionFileSize。
切分本质

虽然产生2个子Region,但还是指向原来的HFile文件。只有major compaction时,父region的数据才会迁移到子region目录。
参考文献
hbase实践之写流程拾遗的更多相关文章
- hbase实践之写流程
内容提要 一.写入流程 初始化ZooKeeper Session,建立长连接,获取META Region的地址. 获取rowkey对应的Region路由信息:来自.meta. 写入region 如何快 ...
- hbase实践之flush and compaction
本文主要涉及flush流程,探讨flush流程过程中引入的问题并阐述2种解决策略,最后简要说明Flush执行策略. 对于Compaction,本文主要探讨Compaction要解决的本质问题以及由Co ...
- Raid1源代码分析--写流程
正确写流程的总体步骤是,raid1接收上层的写bio,申请一个r1_bio结构,将其中的所有bios[]指向该bio.假设盘阵中有N块盘.然后克隆N份上层的bio结构,并分别将每个bios[]指向克隆 ...
- 如何使用 CODING 实践 DevOps 全流程
你好,欢迎使用 CODING!这份最佳实践将帮助你通过 CODING 研发管理系统来更好地实践 DevOps 流程. DevOps 的本质是打破各个部门之间的隔阂,打通企业的前中后台,推进跨部门协作. ...
- HDFS写流程
HDFS client首先会与NameNode交互元数据信息,然后NameNode制定策略,分配NameNode节点,客户端先会与离自己最近的DataNode进行socket连接,已经与DataNod ...
- HBase最佳实践-写性能优化策略
本篇文章来说道说道如何诊断HBase写数据的异常问题以及优化写性能.和读相比,HBase写数据流程倒是显得很简单:数据先顺序写入HLog,再写入对应的缓存Memstore,当Memstore中数据大小 ...
- HBase实践案例:知乎 AI 用户模型服务性能优化实践
用户模型简介 知乎 AI 用户模型服务于知乎两亿多用户,主要为首页.推荐.广告.知识服务.想法.关注页等业务场景提供数据和服务, 例如首页个性化 Feed 的召回和排序.相关回答等用到的用户长期兴趣特 ...
- hbase实践之协处理器Coprocessor
HBase客户端查询存在的问题 Scan 用Get/Scan查询数据, Filter 用Filter查询特定数据 以上情况只适合几千行数据以及不是很多的列的"小数据". 当表扩展为 ...
- hbase实践(十六) BlockCache
0 引言 和其他数据库一样,优化IO也是HBase提升性能的不二法宝,而提供缓存更是优化的重中之重. 根据二八法则,80%的业务请求都集中在20%的热点数据上,因此将这部分数据缓存起就可以极大地提升系 ...
随机推荐
- python变量 - python基础入门(6)
何为python变量,即数据类型.python变量一共六种类型:整数/浮点数/字符串/BOOL/列表/元组/字典,今天先讲解前四种,后三种留到后面的文章在讲解. 首先讲解print() 函数,prin ...
- OS填空题练习
1.操作系统的基本特征:并发性:共享性:虚拟性:异步性. 2.操作系统的设计目标:方便性:有效性:可扩充性:开放性. 3.操作系统的主要功能:处理机管理:存储器管理:设备管理:文件管理:用户接口. 4 ...
- B9 Concurrent 重入锁(ReentrantLock)
[概述] java.util.concurrent.locks.ReentrantLock 实现 java.util.concurrent.locks.Lock 接口,加锁(lock)和 解锁(unl ...
- mysql-系统表的使用
https://blog.csdn.net/wind520/article/details/38728655
- Python split()方法分割字符串
Python 中,除了可以使用一些内建函数获取字符串的相关信息外(例如 len() 函数获取字符串长度),字符串类型本身也拥有一些方法供我们使用. 注意,这里所说的方法,指的是字符串类型 str 本身 ...
- python-pillow图像处理模块
from PIL import ImageColor ImageColor.getcolor('red','RGB') #颜色 模式 ImageColor.getcolor('red','RGBA') ...
- Java中自增(++)和赋值(=)运算效率比较
前言 将一个int型数组x[]从初值0变成1.有两种做法: // 只考虑后自增 int length = x.length; for (int i = 0; i < length; i++) ...
- Luogu4770 NOI2018你的名字(后缀自动机+线段树合并)
先考虑l=1,r=n,并且不要求本质不同的情况.对原串建SAM,将询问串在上面跑,得到每个前缀的最长匹配后缀即可得到答案. 然后考虑本质不同.对询问串也建SAM,统计每个节点的贡献,得到该点right ...
- (三)Lucene之删除更新文档以及luke的基本使用
一.demo 本例中采用单元测试,故在pom.xml中引入junit jar包 1.1 前提: public class IndexTest { /** *数据准备 */ private String ...
- ASP.NET Core 3.0 入门
原文:ASP.NET Core 3.0 入门 课程简介 与2.x相比发生的一些变化,项目结构.Blazor.SignalR.gRPC等 课程预计结构 ASP.NET Core 3.0项目架构简介 AS ...