【转】HBase Log splitting

通常有两种情况日志文件需要进行replay:当集群启动时,或者当服务器出错时。当master启动—(备份master转正也包括在内)—它会检查HBase在文件系统上的根目录下的.logs文件是否还有一些文件,目前没有安排相应的region server。日志文件名称不仅包含了服务器名称,而且还包含了该服务器对应的启动码。该数字在region server每次重启后都会被重置,这样master就能用它来验证某个日志是否已经被抛弃。

 

Log被抛弃的原因可能是服务器出错了,也可能是一个正常的集群重启。因为所有的region servers在重启过程中,它们的log文件内容都有可能未被持久化。除非用户使用了graceful stop(参见the section called “Node Decommission”)过程,此时服务器才有机会在停止运行之前,将所有pending的修改操作flush出去。正常的停止脚本,只是简单的令服务器失败,然后在集群重启时再进行log的replay。如果不这样的话,关闭一个集群就可能需要非常长的时间,同时可能会因为memstore的并行flush引起一个非常大的IO高峰。

 

Master也会使用ZooKeeper来监控服务器的状况,当它检测到一个服务器失败时,在将它上面的regions重新分配之前,它会立即启动一个所属它log文件的恢复过程,这发生在ServerShutdowHandler类中。

 

在log中的修改操作可以被replay之前,需要把它们按照region分离出来。这个过程就是log splitting:读取日志然后按照每条记录所属的region分组。这些分好组的修改操作将会保存在目标region附近的一个文件中,用于后续的恢复。

 

Logs splitting的实现在几乎每个HBase版本中都有些不同:早期版本通过master上的单个进程读取文件。后来对它进行了优化改成了多线程的。0.92.0版本中,最终引入了分布式log splitting的概念,将实际的工作从master转移到了所有的region servers中。

 

考虑一个具有很多region servers和log文件的大集群,在以前master不得不自个串行地去恢复每个日志文件—不仅IO超载而且内存使用也会超载。这也意味着那些具有pending的修改操作的regions必须等到log split和恢复完成之后才能被打开。

 

新的分布式模式使用ZooKeeper来将每个被抛弃的log文件分配给一个region server。同时通过ZooKeeper来进行工作分配,如果master指出某个log可以被处理了,这些region servers为接受该任务就会进行竞争性选举。最终一个region server会成功,然后开始通过单个线程(避免导致region server过载)读取和split该log文件。

注:可用通过设置hbase.master.distributed.log.splitting来关闭这种分布式log splitting方式。将它设为false,就是关闭,此时会退回到老的那种直接由master执行的方式。在非分布式模式下,writers是多线程的,线程数由hbase.regionserver.hlog.splitlog.writer.threads控制,默认设为3。如果要增加线程数,需要经过仔细的权衡考虑,因为性能很可能受限于单个log reader的性能限制。

Split过程会首先将修改操作写入到HBase根文件夹下的splitlog目录下。如下:


    0 /hbase/.corrupt
      0 /hbase/splitlog/foo.internal,60020,1309851880898_hdfs%3A%2F%2F \
localhost%2Fhbase%2F.logs%2Ffoo.internal%2C60020%2C1309850971208%2F \
foo.internal%252C60020%252C1309850971208.1309851641956/testtable/ \
d9ffc3a5cd016ae58e23d7a6cb937949/recovered.edits/0000000000000002352

为了与其他日志文件的split输出进行区分,该路径已经包含了日志文件名,因该过程可能是并发执行的。同时路径也包含了table名称,region名称(hash值),以及recovered.edits目录。最后,split文件的名称就是针对相应的region的第一个修改操作的序列号。

 

.corrupt目录包含那些无法被解析的日志文件。它会受hbase.hlog.split.skip.errors属性影响,如果设为true,意味着当无法从日志文件中读出任何修改操作时,会将该文件移入.corrupt目录。如果设为false,那么此时会抛出一个IOExpectation,同时会停止整个的log splitting过程。

 

一旦log被成功的splitting后,那么每个regions对应的文件就会被移入实际的region目录下。对于该region来说它的恢复工作现在才就绪。这也是为什么splitting必须要拦截那些受影响的regions的打开操作的原因,因为它必须要将那些pending的修改操作进行replay。


http://blog.cloudera.com/blog/2012/07/hbase-log-splitting/

http://duanple.blog.163.com/blog/static/709717672011923111743139/


你可能感兴趣的:(【转】HBase Log splitting)