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%的热点数据上,因此将这部分数据缓存起就可以极大地提升系 ...
随机推荐
- talend工具通过关键字来取得text文本中的数据
问题描述: 在文件夹中有多个text文本,通过关键字来取得text文本里面我所需要的数据,并出力到Excel里面.取得的数据,在text文本里面可能是多行的存在,并且在Excel里面是一行的存在. 解 ...
- U盘防病毒
1.待查 http://jingyan.baidu.com/article/a3f121e4ced14ffc9052bbca.html
- linux shell中的EOF
关键词:EOF 在平时的运维工作中,我们经常会碰到这样一个场景:执行脚本的时候,需要往一个文件里自动输入N行内容.如果是少数的几行内容,还可以用echo追加方式,但如果是很多行,那么单纯用echo追加 ...
- linux下使用Oracle常用命令
进入Oracle用户 su - oracle 以dba身份进入sql语句 sqlplus / as sysdba 启动数据库相关命令启动数据库 startup 启动监听(关闭监听的命令lsnrctl ...
- SQLite之rowid与sqlite3_last_insert_rowid()
//返回最后一次insert的rowid,如果没有插入就返回0 (DB session断开后也返回0, 是保存在进程的内存中) SELECT LAST_INSERT_ROWID(); //找到最大的r ...
- mysql-系统表的使用
https://blog.csdn.net/wind520/article/details/38728655
- spring-cloud项目搭建
springCloud项目搭建手册 springcloud应用场景及微服务框架发展趋势 Spring Cloud为开发人员提供了工具,以快速构建分布式系统中的某些常见模式(例如,配置管理,服务发现,断 ...
- Java 语言 ArrayList 和 JSONArray 相互转换
Java 语言 ArrayList 和 JSONArray 相互转换 本篇主要讲解 ArrayList 和 fastjson 中的 JSONArray相互转换的几种常用方式,以实体类 Student. ...
- 关于c++模板非类型参数中指针和引用类型必须为全局或者静态变量的问题
之前在学习c++模板的时候,一直没留意到在非类型参数中对指针和引用有着一些限制,今早在复学模板的时候才注意到书上标明,指针和引用作为模板的非类型参数传递时必须要求是全局或者静态变量.其实不难想到,模板 ...
- react封装通用tab组件
import React, { Component } from 'react' import PropTypes from 'prop-types' import _ from 'lodash' i ...