2019/3/28 星期四
hbase数据写入流程深度解析
在看此链接之前,可以写查看 hbase读写请求详细解释 中的写请求流程 https://blog.51cto.com/12445535/2356085
简介:
hbase设置之初就是为了应对大量的写多读少的应用,他出色的写性能,在一个100台RS的集群可以轻松地支撑每天10T的写入量。
hbase的写数据流程大体分为3部分
1、客户端的写入流程
2、服务端的写入流程
3、wal的工作原理
我们先回顾一下hbase写数据流程
写请求处理过程小结
1 client 向region server 提交写请求
2 region server 找到目标region
3 region 检查数据是否与schema 一致
4 如果客户端没有指定版本,则获取当前系统时间作为数据版本
5 将更新写入WAL log
6 将更新写入Memstore
7 判断Memstore 的是否需要flush 为Store 文件。
第一部分:客户端的写入流程
客户端流程解析:
1、用户提交put请求后,HBase客户端会将put请求添加到本地buffer中,符合一定条件就会通过AsyncProcess异步批量提交。
HBase默认设置autoflush=true,表示put请求直接会提交给服务器进行处理;
2、用户可以设置autoflush=false,这样的话put请求会首先放到本地buffer,等到本地buffer大小超过一定阈值(默认为2M,可以通过配置文件配置)之后才会提交。很显然,后者采用group commit机制提交请求,可以极大地提升写入性能,但是因为没有保护机制,如果客户端崩溃的话会导致提交的请求丢失。
//提示:
cdh集群中hbase默认是使用autoflush=false 也就是首先会把数据放在本地的buffer中
HBase 客户端写入缓冲
hbase.client.write.buffer = 2M //写入缓冲区大小(以字节为单位)。较大缓冲区需要客户端和服务器中有较大内存,因为服务器将实例化已通过的写入缓冲区并进行处理,这会降低远程过程调用 (RPC) 的数量。为了估计服务器已使用内存的数量,请用值“hbase.client.write.buffer”乘以“hbase.regionserver.handler.count”。
HBase Region Server 处理程序计数
hbase.regionserver.handler.count = 30 //RegionServer 中启动的 RPC 服务器实例数量
3、在提交给服务端之前,HBase会在元数据表.meta.中根据rowkey找到它们归属的region server,这个定位的过程是通过HConnection的locateRegion方法获得的。如果是批量请求的话还会把这些rowkey按照HRegionLocation分组,每个分组可以对应一次RPC请求。
4、HBase会为每个HRegionLocation构造一个远程RPC请求MultiServerCallable<Row>,然后通过rpcCallerFactory.<MultiResponse> newCaller()执行调用,忽略掉失败重新提交和错误处理,客户端的提交操作到此结束。
第二部分:服务端写入流程
服务端流程解析
(1)获取行锁、Region更新共享锁 -》(2)开始写事务 -》(3)写缓存memstore -》(4)构造waledit并append hlog - 》 (5)
释放行锁,共享锁 - 》 (6)sync hlog -》(7)结束写事务 - 》(8) flush memstore
//解释
(1)获取行锁、Region更新共享锁: HBase中使用行锁保证对同一行数据的更新都是互斥操作,用以保证更新的原子性,要么更新成功,要么失败。
(2)开始写事务:获取write number,用于实现MVCC,实现数据的非锁定读,在保证读写一致性的前提下提高读取性能。
(3)写缓存memstore:HBase中每列族都会对应一个store,用来存储该列数据。每个store都会有个写缓存memstore,用于缓存写入数据。HBase并不会直接将数据落盘,而是先写入缓存,等缓存满足一定大小之后再一起落盘。
(4)Append HLog:HBase使用WAL机制保证数据可靠性,即首先写日志再写缓存,即使发生宕机,也可以通过恢复HLog还原出原始数据。该步骤就是将数据构造为WALEdit对象,然后顺序写入HLog中,此时不需要执行sync操作。0.98版本采用了新的写线程模式实现HLog日志的写入,可以使得整个数据更新性能得到极大提升,具体原理见下一个章节。
(5)释放行锁以及共享锁
(6)Sync HLog:HLog真正sync到HDFS,在释放行锁之后执行sync操作是为了尽量减少持锁时间,提升写性能。如果Sync失败,执行回滚操作将memstore中已经写入的数据移除。
(7)结束写事务:此时该线程的更新操作才会对其他读请求可见,更新才实际生效。具体分析见文章《数据库事务系列-HBase行级事务模型》
(8)flush memstore:当写缓存满128M之后,会启动flush线程将数据刷新到硬盘。刷新操作涉及到HFile相关结构,后面会详细对此进行介绍。
//HBase Memstore 刷新大小
hbase.hregion.memstore.flush.size = 128M //如 memstore 大小超过此值(字节数),Memstore 将刷新到磁盘。通过运行由 hbase.server.thread.wakefrequency 指定的频率的线程检查此值。
//提示:
我们需要注意,在服务器端写数据的时候,有很多资料是先写到memstore中,再写到wal log中,但是,这样理解不是很准确,因为这好像,违背了wal log的容灾机制,所有,我们可以理解为
先写入到wal log中再写入到memstore中的 //这一步源码中并没有完全的体现出来,可以理解为同步进行。
理论上应该是先写wal log中,HBase这块实现是先写mem,后写WAL,hbase能够保证只有这两个都写完了用户才会可见(mvcc机制),而且如果mem写成功,wal写失败,mem会被回滚。
这样做之所以it’s ok,是由于MVCC来保证的,在每个写线程开启事务的开头就会创建全局递增的write num,但是在HLog更新完毕之后才会去向前推进(roll forward)全局读取点。
所以在此期间内,任何读取线程采用MVCC机制根据读取点读取数据,任何写入/更新操作在HLog未更新完毕之前是不会向前推进读取点的,因此即使数据已经写入memstore,对读线程也是不可见的。
第三部分:WAL机制解析
1、WAL(Write-Ahead Logging)是一种高效的日志算法,几乎是所有非内存数据库提升写性能的不二法门,
2、基本原理是在数据写入之前首先顺序写入日志,然后再写入缓存,等到缓存写满之后统一落盘。
3、之所以能够提升写性能,是因为WAL将一次随机写转化为了一次顺序写加一次内存写。
4、提升写性能的同时,WAL可以保证数据的可靠性,即在任何情况下数据不丢失。
5、假如一次写入完成之后发生了宕机,即使所有缓存中的数据丢失,也可以通过恢复日志还原出丢失的数据。
WAL持久化等级
HBase中可以通过设置WAL的持久化等级决定是否开启WAL机制、以及HLog的落盘方式。
WAL的持久化等级分为如下四个等级:
SKIP_WAL:只写缓存,不写HLog日志。这种方式因为只写内存,因此可以极大的提升写入性能,但是数据有丢失的风险。在实际应用过程中并不建议设置此等级,除非确认不要求数据的可靠性。
ASYNC_WAL:异步将数据写入HLog日志中。
SYNC_WAL:同步将数据写入日志文件中,需要注意的是数据只是被写入文件系统中,并没有真正落盘。
FSYNC_WAL:同步将数据写入日志文件并强制落盘。最严格的日志写入等级,可以保证数据不会丢失,但是性能相对比较差。
用户可以通过客户端设置WAL持久化等级,代码:put.setDurability(Durability. SYNC_WAL );
//cdh中
WAL 提供程序
hbase.wal.provider = //可选项为: //RegionServer 应用于提前写入日志的实施。
RegionServer Default Group
多个 HDFS WAL
单个 HDFS WAL
HBase 默认设置(Single HDFS WAL)
WAL HSM 存储策略
hbase.wal.storage.policy
RegionServer Default Group
所有副本都在 SSD 上
一个副本在 SSD 上,其他副本均在 HDD 上
无(全部在 HDD 上)
关于wal 和 hlog概念的的升入研究 见参考链接
//HLog的写入模型。HLog的写入可以分为三个阶段,首先将数据对<HLogKey,WALEdit>写入本地缓存,然后再将本地缓存写入文件系统,最后执行sync操作同步到磁盘。
参考链接:
http://hbasefly.com/2016/03/23/hbase_writer/
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。