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%的热点数据上,因此将这部分数据缓存起就可以极大地提升系 ...
随机推荐
- Win10下 jdk的安装
jdk 的下载地址 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 在 D 盘 ...
- 【leetcode算法-简单】66. 加一
[题目描述] 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示 ...
- todo---jaxen
- PO,VO,DAO,BO,POJO之间的区别与解释
VO value object:值对象 通常用于业务层之间的数据传递,由new创建,由GC回收. PO persistant object:持久层对象 对应数据库中表的字段. VO和PO,都是属性加上 ...
- Netty中两种Keepalive的区别
在Server端开启TCP keepalive: 两种方式 serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); serverB ...
- 堆学习笔记(未完待续)(洛谷p1090合并果子)
上次讲了堆,别人都说极其简单,我却没学过,今天又听dalao们讲图论,最短路又用堆优化,问懂了没,底下全说懂了,我???,感觉全世界都会了堆,就我不会,于是我决定补一补: ——————来自百度百科 所 ...
- Linux (x86) Exploit 开发系列教程之一(典型的基于堆栈的缓冲区溢出)
(1)漏洞代码 //vuln.c #include <stdio.h> #include <string.h> int main(int argc, char* argv[]) ...
- SAS学习笔记7 合并语句(set、merge函数)
set函数:纵向合并数据集 set语句进行纵向合并.set语句的作用是将若干个数据集依次纵向连接,并存放到data语句建立的数据集中.若set后面只有一个数据集,此时相当于复制的作用 注:data语句 ...
- c++学习-----引用
引用相当于给一个对象起个别名 必须初始化 引用只是与一个对象bind,所以引用无法改变 引用不是一个对象,所以没有引用的引用 引用的初始化值必须是一个对象,而不能是字面量或表达式 引用不是地址,所以引 ...
- [Python爬虫] 使用 Beautiful Soup 4 快速爬取所需的网页信息
[Python爬虫] 使用 Beautiful Soup 4 快速爬取所需的网页信息 2018-07-21 23:53:02 larger5 阅读数 4123更多 分类专栏: 网络爬虫 版权声明: ...