HLog代码分析

在分享replication时,有同事提出replication延时怎么样,(基于0.94.3)
本文主要代码分析一下Hlog生成及对relication的影响。具体replication请参考
http://brianf.iteye.com/blog/1776936

首先分析hlog什么时候产生:

在生成HLog对象时,会调用HLog的rollWriter(),此时由于this.writer为null,所以通过rollWriter方法会创建第一个hlog文件,之后会调用replicaton相关的参见http://brianf.iteye.com/blog/1776936

Java代码  
  1. // rollWriter sets this.hdfs_out if it can.  
  2. rollWriter();  
  3.   
  4. // handle the reflection necessary to call getNumCurrentReplicas()  
  5. this.getNumCurrentReplicas = getGetNumCurrentReplicas(this.hdfs_out);  
  6.   
  7. logSyncerThread = new LogSyncer(this.optionalFlushInterval);  

-----------------

Java代码  
  1. public byte [][] rollWriter(boolean force)  
  2.      throws FailedLogCloseException, IOException {  
  3.    // Return if nothing to flush.  
  4.    if (!force && this.writer != null && this.numEntries.get() <= 0) {  
  5.      return null;  
  6.    }  


-------------
LogRoller.run中      

Java代码  
  1. public void run() {  
  2.   while (!server.isStopped()) {  
  3.     long now = System.currentTimeMillis();  
  4.     boolean periodic = false;  
  5.     if (!rollLog.get()) {  
  6.       periodic = (now - this.lastrolltime) > this.rollperiod;  
  7.       if (!periodic) {  
  8.         synchronized (rollLog) {  
  9.           try {  
  10.             rollLog.wait(this.threadWakeFrequency);  
  11.           } catch (InterruptedException e) {  
  12.             // Fall through  
  13.           }  
  14.         }  
  15.         continue;  
  16.       }  
  17.       // Time for periodic roll  
  18.       if (LOG.isDebugEnabled()) {  
  19.         LOG.debug("Hlog roll period " + this.rollperiod + "ms elapsed");  
  20.       }  
  21.     } else if (LOG.isDebugEnabled()) {  
  22.       LOG.debug("HLog roll requested");  
  23.     }  
  24.     rollLock.lock(); // FindBugs UL_UNRELEASED_LOCK_EXCEPTION_PATH  
  25.     try {  
  26.       this.lastrolltime = now;  
  27.       // This is array of actual region names.  
  28.       byte [][] regionsToFlush = this.services.getWAL().rollWriter(rollLog.get());  


LogRoller线程默认会等待1小时,也就是默认是1个小时一个log(后面会说还有hlog size也会是一个因素)
Java代码  
  1. this.rollperiod = this.server.getConfiguration().  
  2.   getLong("hbase.regionserver.logroll.period"3600000);  



而rollLog是AtomicBoolean, 当为true时,调用rollWriter会创建新log, 什么时候rollLog为true呢?


Java代码  
  1. public void logRollRequested() {  
  2.   synchronized (rollLog) {  
  3.     rollLog.set(true);  
  4.     rollLog.notifyAll();  
  5.   }  
  6. }  


是在Hlog.syncer方法中调用的。


数据写入hbase时,如put,调用Hlog的append ,此方法中将数据写到Hlog的缓存中(List),再同步sync数据到HDSF,还有LogSyncer线程会1000ms执行一次 Hlog.syncer方法 。



Java代码  
  1. private long append(HRegionInfo info, byte [] tableName, WALEdit edits, UUID clusterId,  
  2.     final long now, HTableDescriptor htd, boolean doSync)  
  3.   throws IOException {  
  4.     if (edits.isEmpty()) return this.unflushedEntries.get();;  
  5.     if (this.closed) {  
  6.       throw new IOException("Cannot append; log is closed");  
  7.     }  
  8.     long txid = 0;  
  9.     synchronized (this.updateLock) {  
  10.       long seqNum = obtainSeqNum();  
  11.       // The 'lastSeqWritten' map holds the sequence number of the oldest  
  12.       // write for each region (i.e. the first edit added to the particular  
  13.       // memstore). . When the cache is flushed, the entry for the  
  14.       // region being flushed is removed if the sequence number of the flush  
  15.       // is greater than or equal to the value in lastSeqWritten.  
  16.       // Use encoded name.  Its shorter, guaranteed unique and a subset of  
  17.       // actual  name.  
  18.       byte [] encodedRegionName = info.getEncodedNameAsBytes();  
  19.       this.lastSeqWritten.putIfAbsent(encodedRegionName, seqNum);  
  20.       HLogKey logKey = makeKey(encodedRegionName, tableName, seqNum, now, clusterId);  
  21.       doWrite(info, logKey, edits, htd);  
  22.       this.numEntries.incrementAndGet();  
  23.       txid = this.unflushedEntries.incrementAndGet();  
  24.       if (htd.isDeferredLogFlush()) {  
  25.         lastDeferredTxid = txid;  
  26.       }  
  27.     }  
  28.     // Sync if catalog region, and if not then check if that table supports  
  29.     // deferred log flushing  
  30.     if (doSync &&   
  31.         (info.isMetaRegion() ||  
  32.         !htd.isDeferredLogFlush())) {  
  33.       // sync txn to file system  
  34.       this.sync(txid);  
  35.     }  
  36.     return txid;  
  37.   }  




其中在Hlog.syncer方法中调用checkLowReplication方法用来判断是否hlog在hdfs上的副本数低于配置项,若低于则requestLogRoll,最终调用logRollRequested方法,但是调用次数不超过默认5次(  
Java代码  
  1. this.lowReplicationRollLimit = conf.getInt(  
  2.        "hbase.regionserver.hlog.lowreplication.rolllimit"5);  


然后判断正在写的hlog是否大于一个size(64MB*0.95),若大于,说明也要生成新的Hlog
Java代码  
  1. this.blocksize = conf.getLong("hbase.regionserver.hlog.blocksize",  
  2.     getDefaultBlockSize());  
  3. // Roll at 95% of block size.  
  4. float multi = conf.getFloat("hbase.regionserver.logroll.multiplier"0.95f);  
  5. this.logrollsize = (long)(this.blocksize * multi);  
  6. ----------------  
  7.       if (tempWriter.getLength() > this.logrollsize) {  
  8.         requestLogRoll();  
  9.       }  


对于replication来说,延迟时间主要是与ZK的通讯及RPC调用slave RS时间。



hbase.regionserver.optionallogflushinterval
将Hlog同步到HDFS的间隔。如果Hlog没有积累到一定的数量,到了时间,也会触发同步。默认是1秒,单位毫秒。
默认: 1000
hbase.regionserver.logroll.period
提交commit log的间隔,不管有没有写足够的值。
默认: 3600000
hbase.master.logcleaner.ttl
Hlog存在于.oldlogdir 文件夹的最长时间, 超过了就会被 Master 的线程清理掉.
默认: 600000
hbase.master.logcleaner.plugins
值用逗号间隔的文本表示。这些WAL/HLog  cleaners会按顺序调用。可以把先调用的放在前面。可以实现自己的LogCleanerDelegat,加到Classpath下,然后在这里写上类的全路径就可以。一般都是加在默认值的前面。
具体的初始是在CleanerChore 的initCleanerChain方法,此方法同时也实现HFile的cleaner的初台化。
默认: org.apache.hadoop.hbase.master.TimeToLiveLogCleaner

hbase.regionserver.hlog.blocksize
hbase.regionserver.maxlogs

WAL的最大值由hbase.regionserver.maxlogs * hbase.regionserver.hlog.blocksize (2GB by default)决定。一旦达到这个值,Memstore flush就会被触发。通过WAL限制来触发Memstore的flush并非最佳方式,这样做可能会会一次flush很多Region,引发flush雪崩。

最好将hbase.regionserver.hlog.blocksize * hbase.regionserver.maxlogs 设置为稍微大于hbase.regionserver.global.memstore.lowerLimit * HBASE_HEAPSIZE.

你可能感兴趣的:(HLog代码分析)