splitlog期间丢失数据的问题

    splitlog是保证在重启或rs挂掉后,恢复hlog的重要手段。master需要将hlog写到各个region目录下的recovered.edits目录中,然后由各台rs自行replay这个目录来恢复数据。这个过程中,master会启动一个读线程和多个写线程,一边读到内存中,一边将内存队列中的数据写到各个目录中去。
    当master将.logs下的数据写到recovered.edits后,会把.logs目录下的文件mv到.oldlogs中。如果splitlog期间master挂掉,下次启动时会重复以上过程。但是杯具的是,master并不会等待recovered.edits写完以后再将.logs下的文件mv到.oldlogs中,而是当.logs下的文件读入内存结束以后就执行mv操作。因此如果这些数据在内存还没有写完成recovered.edits时,mv操作又结束时master就挂掉,则数据就丢失了。当然实际情况出现的概率还是比较小的,因为master并不是一次把.logs全部读入内存,而是128MB地读,所以只有当最后一个128MB在内存中时,才会执行mv操作,这时就有丢失数据的风险了。应对以下代码做调整:
Index: src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogSplitter.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogSplitter.java	(revision 99281)
+++ src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogSplitter.java	(working copy)
@@ -289,10 +289,10 @@
             "Discovered orphan hlog after split. Maybe the "
             + "HRegionServer was not dead when we started");
       }
-      archiveLogs(srcDir, corruptedLogs, processedLogs, oldLogDir, fs, conf);
     } finally {
       LOG.info("Finishing writing output logs and closing down.");
       splits = outputSink.finishWritingAndClose();
+      archiveLogs(srcDir, corruptedLogs, processedLogs, oldLogDir, fs, conf);
     }
     return splits;
   }

    即将mv操作移动到等所有写线程结束以后再做。这样数据就不会丢失了。带来的副作用是在异常退出而下次启动时有可能在recovered.edits下面重复写log文件(因为上次退出时有可能留下一些文件)。但这最多增加一点重启的时间,总要比丢失数据好。

你可能感兴趣的:(split)