WAL(Write-Ahead Logging)是数据库系统中保障原子性和持久性的技术,经过使用WAL能够将数据的随机写入变为顺序写入,能够提升数据写入的性能。在hbase中写入数据时,会将数据写入内存同时写wal日志,为防止日志丢失,日志是写在hdfs上的。
默认是每一个RegionServer有1个WAL,在HBase1.0开始支持多个WALHBASE-5699,这样能够提升写入的吞吐量。配置参数为hbase.wal.provider=multiwal,支持的值还有defaultProvider和filesystem(这2个是一样的实现)。
WAL的持久化的级别有以下几种:数据库
先看看wal写入中的几个主要的类
1. WALKey:wal日志的key,包括regionName:日志所属的region
tablename:日志所属的表,writeTime:日志写入时间,clusterIds:cluster的id,在数据复制的时候会用到。
2.WALEdit:在hbase的事务日志中记录一系列的修改的一条事务日志。另外WALEdit实现了Writable接口,可用于序列化处理。
3. FSHLog: WAL的实现类,负责将数据写入文件系统
在每一个wal的写入这里使用的是多生产者单消费者的模式,这里使用到了disruptor框架,将WALKey和WALEdit信息封装为FSWALEntry,而后经过RingBufferTruck放入RingBuffer中。接下来看hlog的写入流程,分为如下3步:apache
下面来详细说明一下各种线程是如何配合来实现这几步操做的,数组
wal写入文件系统是经过Writer来写入的,其实际类为ProtobufLogWriter,使用的是Protobuf的格式持久化处理。使用Protobuf格式有以下优点:缓存
方便扩展以及支持其余语言,经过其余语言来解析日志。框架
写入的日志中是按WALKey和WALEdit来依次存储的(具体内容见前面WALKey和WALEdit类的说明),另外还将WALKey和WALEdit分别进行了压缩处理。异步
每一个wal中有一个RingBufferEventHandler对象,其中用数组管理着多个SyncRunner线程(由参数hbase.regionserver.hlog.syncer.count配置,默认5)来进行同步处理,每一个SyncRunner对象里面有一个LinkedBlockingQueue(syncFutures,大小为参数{hbase.regionserver.handler.count默认值200}*3
另外这里的SyncFuture是每一个rpcHandler线程拥有一个,由wal中的private final Mapide
class RingBufferEventHandler implements EventHandler<RingBufferTruck>, LifecycleAware { private final SyncRunner [] syncRunners; private final SyncFuture [] syncFutures; ... } private class SyncRunner extends HasThread { private volatile long sequence; // Keep around last exception thrown. Clear on successful sync. private final BlockingQueue<SyncFuture> syncFutures; ... }
这里在处理ringBuffer中的syncFuture时,不是每有一个就提交到syncRunner处理,而是按批来处理的,这里的批分2种状况:性能
若是达到了批大小,就从syncRunner数组中顺序选择下一个SyncRunner,将这批数据插入该SyncRunner的BlockingQueue中。最后由SyncRunner线程进行hdfs文件同步处理。为保证数据的不丢失,rpc请求须要保证wal日志写入成功后才能返回,这里HBase作了一系列的优化处理的操做。优化
经过wal日志切换,这样能够避免产生单独的过大的wal日志文件,这样能够方便后续的日志清理(能够将过时日志文件直接删除)另外若是须要使用日志进行恢复时,也能够同时解析多个小的日志文件,缩短恢复所需时间。
wal触发切换的场景有以下几种:spa
这里前面2种场景调用requestLogRoll发起日志滚动请求,最终也是经过LogRoller来执行日志滚动的操做。
当memstore中的数据刷新到hdfs后,那对应的wal日志就不须要了,FSHLog中有记录当前memstore中各region对应的最老的sequenceId,若是一个日志中的各个region的操做的最新的sequenceId均小于wal中记录的各个需刷新的region的最老sequenceId,说明该日志文件就不须要了,因而就会将该日志文件从./WALs目录移动到./oldWALs目录。这块是在前面日志滚动完成后调用cleanOldLogs来处理的。
因为wal日志还会用于跨集群的同步处理,因此wal日志失效后并不会当即删除,而是移动到oldWALs目录。由HMaster中的LogCleaner这个Chore线程来负责wal日志的删除,在LogCleaner内部经过参数{hbase.master.logcleaner.plugins}以插件的方式来筛选出能够删除的日志文件。目前配置的插件有ReplicationLogCleaner、SnapshotLogCleaner和TimeToLiveLogCleaner
在本篇中对HBase中wal日志的整个周期进行了叙述,能对wal的处理过程有了总体的了解,后续在单独说说WAL日志的恢复的内容。
参考资料:
1. http://hbasefly.com/2016/03/23/hbase_writer/
2. http://hbasefly.com/2016/10/29/hbase-regionserver-recovering/
转:https://blog.csdn.net/xiangel/article/details/54424900