Hlog的相关处理流程:
在对hbase中数据进行更新操作put/delete/append/increment操作时,记录操作日志供日志重播的相关处理。
Hlog的写入通过regionserver实例生成时生成的FSLog为的实例。
通过LogRoller线程定期去检查并删除过期的日志文件。
定期检查的时间间隔通过hbase.regionserver.logroll.period进行配置,默认为3600000ms
如果检查时间还没有达到上面的间隔时间时,线程等待的wake(唤醒)时间,hbase.server.thread.wakefrequency,
默认为10*1000ms
FSLog实例内部有一个FSLog.LogSyncer线程实例,并启动此实例。此线程主要用来把log写入到hdfs中
此线程的执行间隔通过hbase.regionserver.optionallogflushinterval配置,默认为1000ms
如果此值配置为小于0的值,表示实时写入hlog日志
在执行更新操作时如果开启有日志记录,调用appendNoSync-->append写入日志,
每一个日志中记录的seqid默认第一次时为当前rs中所有region中最大的seqid加一(FSHLog.logSeqNum),
每append一次后,logSeqNum的值为加一。同时此值也是flsuh时hfile中的fileinfo中记录的最大的seqid值。
此方法把要记录的日志写入到FSLog.LogSyncer.pendingWrites队列中。等待LogSyncer的run方法去sync
注意:如果是对meta的log写入时,每一次写入都会执行sync操作,保证meta数据的不丢失。
publicvoidrun(){
try{
//awaiting with a timeout doesn't always
//throw exceptions on interrupt
while(!this.isInterrupted()&& !closeLogSyncer.get()){
try{
如果没有最新的数据要写入到HDFS,现在未flush的log的值小于或等于上一次提交的值,表示没有新记录
unflushedEntries在每append一次值会加一。
if(unflushedEntries.get()<=syncedTillHere){
synchronized(closeLogSyncer){
线程等待
closeLogSyncer.wait(this.optionalFlushInterval);
}
}
//Calling sync since we waited or hadunflushedentries.
//Entries appended but not sync'd are taken care of here AKA
//deferred log flush
否则,执行log的写入HDFS操作。使用unflushedEntries的值当txid
sync();
}catch(IOExceptione){
LOG.error("Errorwhile syncing, requesting close of hlog ",e);
requestLogRoll();
Threads.sleep(this.optionalFlushInterval);
}
}
}catch(InterruptedExceptione){
LOG.debug(getName()+" interrupted while waiting forsync requests");
}finally{
LOG.info(getName()+" exiting");
}
}
使用unflushedEntries的值当成txid
privatevoidsyncer()throws IOException {
syncer(this.unflushedEntries.get());// sync all pending items
}