日期:2014-05-16  浏览次数:20435 次

Hbase的log管理(一)

每一个Regionserver中都有一个HLog,一般情况下除非设置了SETWAL(false)否则对hbase的写操作在put到内存之前会append到log中以防止机器down 掉造成的数据丢失。

首先来看RS启动后对HLog的处理

private HLog setupWALAndReplication() throws IOException {
    final Path oldLogDir = new Path(rootDir, HConstants.HREGION_OLDLOGDIR_NAME);
    Path logdir = new Path(rootDir, HLog.getHLogDirectoryName(this.serverInfo));
     if (this.fs.exists(logdir)) {// 若hbase/.logs存在则表明在该台机器上已经有regionserver启动了
      throw new RegionServerRunningException("Region server already "
          + "running at " + this.serverInfo.getServerName()
          + " because logdir " + logdir.toString() + " exists");
    }
.....

    return instantiateHLog(logdir, oldLogDir);
  }

?看看instantiateHLog(logdir, oldLogDir);省略一些不重要的步骤,主要的步骤如下

 if (!fs.mkdirs(dir)) { //创建.log目录下该regionserver目录,即为/hbase/.log/regionserver
      throw new IOException("Unable to mkdir " + dir);
    }
    this.oldLogDir = oldLogDir;
    if (!fs.exists(oldLogDir)) {//若/habse/.oldlogs目录不存在则创建之
      if (!fs.mkdirs(this.oldLogDir)) {
        throw new IOException("Unable to mkdir " + this.oldLogDir);
      }
    }
rollWriter();

rollWriter()函数主要完成以下功能:

1.新建一个 /regionserver目录下的文件

2.把旧文件移到/.oldlogs目录下

3.返回需要进行flush的regions

那么什么是旧文件呢?

hbase认为,如果一个文件的所有数据都已经刷到磁盘上了,该文件认为是旧文件,可以将其移除。如何判断一个文件的所有数据刷到磁盘了,用到的就是一个AtomicLong变量 seqnum来判定,这是一个递增的Long并且线程安全。一个文件的seqnum就是该文件最后写入entry的seqnum。

hbase默认一个小时会新建一个文件,并且会清除原先的旧文件。

a) Hlog维护一个ConcurrentSkipListMap<byte [], Long> lastSeqWritten的map其中byte是region的ecodedname,Long是每个entry写入Hlog的seqNum,当有新的entry写入Hlog 是putifabsent,而当memstore中的数据flush结束以后该map就会清除该region。因此该map维护的是最旧写入Hlog的entry的regionname和seqnum映射;

b) Hlog同时维护一个SortedMap<Long, Path> outputfiles,其中Path表示的是regionserver下的path,而Long指的是该Path的seqnum及path要关闭时此时的seqNum。

?

rollWriter()函数首先会创建一个新的文件,然后把原先的文件加入到outputfiles Map中,如果此时lastSeqWritten为空则说明当前所有的region都已经flush结束了,故可以把所有的outputfiles删除掉

否则需要选取合适的outputfiles进行删除,选取的是outputfiles中最老的且比lastSeqWritten中所有的value都小的path进行rename到oldlogs中。在整个过程中对该Hlog上锁防止在cleanoldlog是进行cacheflush

?

举个例子说明一下:

?

比如现在该rs下有4个文件,储存的是4个region的信息:

?

file1: RegionA,4表示的是文件名是file1,其中存储了一个entry其regionname是reginA,其seqNum是4,seqnum是递增的且新建的文件的seq比原先的大

?

?

file1:? RegionA,4??? RegionB,5???? RegionC,6? RegionD,7

?

file2:? RegionA,8??? RegionB,9???? RegionC,10?

?

file3:? RegionA,11??? RegionB,12???? RegionD,13

?

file4:??RegionB,14??????

?

如上面所示,假设上面4个文件都存在,且假设此时lastSeqWritten 中存储的是RegionB,14?

因为lastSeqWritten储存的是最新加入的entries且并没有被flush,这说明Region A,C,D都已经flush结束的,而file1,2,3,由于其seqnum都小于14,认为这些file都已经flush成功了,可以移除了,因为A,C,D都已经flush成功,而如果1,2,3中的Region B未flush那么此时lastSeqWritten存储的肯定不是14了而是小于十四的未flush的seq

?

?