天天看点

hbase源码系列(十)HLog与日志恢复

hbase在写入数据之前会先写入memstore,成功了再写入hlog,当memstore的数据丢失的时候,还可以用hlog的数据来进行恢复,下面先看看hlog的图。

hbase源码系列(十)HLog与日志恢复

旧版的hlog是实际上是一个sequcenefile,0.96的已经使用protobuf来进行序列化了。从writer和reader上来看hlog的都是entry的,换句话说就是,它的每一条记录就是一个entry。

所以上面那个图已经不准确了,hlogkey没变,但是value缺不是keyvalue,而是waledit。

下面我们看看hlogkey的五要素,region、tablename、log的顺序、写入时间戳、集群id。

下面看看waledit的属性, 这里只列出来一个重要的,它是内部持有的一群keyvalue。。

hlog的具体实现类是fshlog,一个region server有两个fshlog,一个负责rs上面所有的用户region的日志,一个负责rs上面的meta表的region的日志。

对于日志来说,我们关心的是它如何保证一致性和准确性,在需要它的时候可以发挥救命作用。

对于meta region的hlog写入之后,它会立即同步到硬盘,非meta表的region,它会先把entry添加到一个队列里面等待同步。

它这里是有一个判断条件的,如果判断条件不成立就立即同步,等待this.optionalflushinterval时间,默认的同步间隔是1000,它是通过参数hbase.regionserver.optionallogflushinterval设置。unflushedentries是一个atomiclong在写入entry的时候递增,syncedtillhere是一个volatile long,同步完成之后也是变大,因为可能被多个线程调用同步操作,所以它是volatile的,从条件上来看,如果没有日志需要同步就等待一秒再进行判断,如果有日志需要同步,也是立马就写入硬盘的,如果发生错误,就是调用requestlogroll方法,进行回滚,这个回滚比较有意思,它是跑过去flush掉memstore中的数据,把他们写入硬盘。

下面是回滚的方法。中间我忽略了几步,然后找到logroller中的这段代码。

找出来需要flush的region,然后计划flush。

逐个对比,找出来未flush memstore的比输出的文件的hlog流水号还小的region,当它准备flush memstore之前会调用startcacheflush方法来把region从oldestunflushedseqnums这个map当中去除,添加到已经flush的map当中。

那啥时候会用到这个呢,在region打开的时候,我们从hregionserver的openregion方法一路跟踪,中间历经openmetahandler,再到hregion.openhregion方法,终于在initializeregionstores方法里面找到了那么一句话。

高潮来了!!!

呵呵,读取recovered.edits下面的日志,符合条件的就加到memstore里面去,完成之后,就把这些文件删掉。大家也看到了,这里通篇讲到一个logseqnum,哪里都有它的身影,它实际上是fshlog当中的一个递增的atomiclong,每当往fslog里面写入一条日志的时候,它都会加一,然后memstore请求flush的时候,会调用fslog的startcacheflush方法,获取(logseqnum+1)回来,然后写入到storefile的sequenceid字段,再次拿出来的时候,就遍历这个hstore下面的storefile的logseqnum,取出来最大的跟它比较,小于它的都已经写过了,没必要再写了。

好了,hlog结束了,累死我了,要睡了。<b></b>

继续阅读