`

HBase HLog结构和原理

阅读更多

一. HLog在HDFS上位置和RegionServer对应关系

HLog持久化在HDFS之上, HLog存储位置查看:

hadoop fs -ls /hbase/.logs

通过HBase架构图, HLog与HRegionServer一一对应,

Found 5 items                                                                                  
drwxr-xr-x - hadoop cug-admin  0 2013-04-11 14:23 /hbase/.logs/HADOOPCLUS02,61020,1365661380729
drwxr-xr-x - hadoop cug-admin  0 2013-04-11 14:23 /hbase/.logs/HADOOPCLUS03,61020,1365661378638
drwxr-xr-x - hadoop cug-admin  0 2013-04-11 14:23 /hbase/.logs/HADOOPCLUS04,61020,1365661379200
drwxr-xr-x - hadoop cug-admin  0 2013-04-11 14:22 /hbase/.logs/HADOOPCLUS05,61020,1365661378053
drwxr-xr-x - hadoop cug-admin  0 2013-04-11 14:23 /hbase/.logs/HADOOPCLUS06,61020,1365661378832

HADOOPCLUS02 ~ HADOOPCLUS06 为RegionServer.

上面显示的文件目录为HLog存储. 如果HLog已经失效(所有之前的写入MemStore已经持久化在HDFS),HLog存在于HDFS之上的文件会从/hbase/.logs转移至/hbase/.oldlogs, oldlogs会删除, HLog的生命周期结束.

二. HBase写流程和写HLog的阶段点.

向HBase Put数据时通过HBaseClient-->连接ZooKeeper--->-ROOT--->.META.-->RegionServer-->Region:

Region写数据之前会先检查MemStore.

1. 如果此Region的MemStore已经有缓存已有写入的数据, 则直接返回;

2. 如果没有缓存, 写入HLog(WAL), 再写入MemStore.成功后再返回.

MemStore内存达到一定的值调用flush成为StoreFile,存到HDFS.

在对HBase插入数据时,插入到内存MemStore所以很快,对于安全性不高的应用可以关闭HLog,可以获得更高的写性能.

三. HLog相关源码.

HBase Hlog

1. 总览.

写入HLog主要靠HLog对象的doWrite(HRegionInfo info, HLogKey logKey, WALEdit logEdit)

或者completeCacheFlush(final byte [] encodedRegionName, final byte [] tableName, final long logSeqId, final boolean isMetaRegion),

在这两方法中调用this.writer.append(new HLog.Entry(logKey, logEdit));方法写入操作.

在方法内构造HLog.Entry:使用当前构造好的writer, 见上图引用对象,

 完整实现类: org.apache.hadoop.hbase.regionserver.wal.SequenceFileLogWriter,

HLog 方法createWriterInstance(fs, newPath, conf) 创建 Writer对象.

2. SequenceFileLogWriter 和SequenceFileLogReader

在SequenceFileLogWriter 类中可以看到, 使用Hadoop SequenceFile.Writer写入到文件系统. SequenceFile是HLog在Hadoop存储的文件格式.

HLog.Entry为HLog存储的最小单位.

public class SequenceFileLogWriter implements HLog.Writer {
  private final Log LOG = LogFactory.getLog(this.getClass());
  // The hadoop sequence file we delegate to.
  private SequenceFile.Writer writer;
  // The dfsclient out stream gotten made accessible or null if not available.
  private OutputStream dfsClient_out;
  // The syncFs method from hdfs-200 or null if not available.
  private Method syncFs;
  // init writer need the key;
  private Class<? extends HLogKey> keyClass;
  @Override
  public void init(FileSystem fs, Path path, Configuration conf)
      throws IOException {
      // 1. create Hadoop file SequenceFile.Writer for writer initation.
      // 2. Get at the private FSDataOutputStream inside in SequenceFile so we can call sync on it. for dfsClient_out initation.
  }
  @Override
  public void append(HLog.Entry entry) throws IOException {
    this.writer.append(entry.getKey(), entry.getEdit());
  }
  @Override
  public void sync() throws IOException {
    if (this.syncFs != null) {
      try {
       this.syncFs.invoke(this.writer, HLog.NO_ARGS);
      } catch (Exception e) {
        throw new IOException("Reflection", e);
      }
    }
  }
}

 SequenceFileLogReader为读取HLog.Entry对象使用.

3. HLog.Entry与属性logSeqNum

每一个Entry包含了 HLogKey和WALEdit 

HLogKey包含了基本信息:  

  private byte [] encodedRegionName;
  private byte [] tablename;
  private long logSeqNum;
  // Time at which this edit was written.
  private long writeTime;
  private byte clusterId;

logSeqNum是一个重要的字段值, sequence number是作为StoreFile里的一个元数据字段,可以针对StoreFile直接得到longSeqNum;

public class StoreFile {
  static final String HFILE_BLOCK_CACHE_SIZE_KEY = "hfile.block.cache.size";
  private static BlockCache hfileBlockCache = null;
  // Is this from an in-memory store
  private boolean inMemory;
  // Keys for metadata stored in backing HFile.
  // Set when we obtain a Reader.  StoreFile row 140
  private long sequenceid = -1;
  /**
   * @return This files maximum edit sequence id.
   */
  public long getMaxSequenceId() {
    return this.sequenceid;
  }
  /**
   * Return the highest sequence ID found across all storefiles in
   * the given list. Store files that were created by a mapreduce
   * bulk load are ignored, as they do not correspond to any edit
   * log items.
   * @return 0 if no non-bulk-load files are provided or, this is Store that
   * does not yet have any store files.
   */
  public static long getMaxSequenceIdInList(List<StoreFile> sfs) {
    long max = 0;
    for (StoreFile sf : sfs) {
      if (!sf.isBulkLoadResult()) {
        max = Math.max(max, sf.getMaxSequenceId());
      }
    }
    return max;
  }
    /**
     * Writes meta data. important for maxSequenceId WRITE!!
     * Call before {@link #close()} since its written as meta data to this file.
     * @param maxSequenceId Maximum sequence id.
     * @param majorCompaction True if this file is product of a major compaction
     * @throws IOException problem writing to FS
     */
    public void appendMetadata(final long maxSequenceId, final boolean majorCompaction)
    throws IOException {
      writer.appendFileInfo(MAX_SEQ_ID_KEY, Bytes.toBytes(maxSequenceId));
      writer.appendFileInfo(MAJOR_COMPACTION_KEY,
          Bytes.toBytes(majorCompaction));
      appendTimeRangeMetadata();
    }
  }
  /**
   * Opens reader on this store file.  Called by Constructor.
   * @return Reader for the store file.
   * @throws IOException
   * @see #closeReader()
   */
  private Reader open() throws IOException {
     // ........
     this.sequenceid = Bytes.toLong(b);
      if (isReference()) {
        if (Reference.isTopFileRegion(this.reference.getFileRegion())) {
          this.sequenceid += 1;
        }      
      }
     this.reader.setSequenceID(this.sequenceid);
     return this.reader;
   }
}

 Store 类对StoreFile进行了管理, 如compact.在 很多StoreFile进行合并时, 取值最大的longSeqNum;

public class Store implements HeapSize {
  /**
   * Compact the StoreFiles.  This method may take some time, so the calling
   * thread must be able to block for long periods.   *
   * <p>During this time, the Store can work as usual, getting values from
   * StoreFiles and writing new StoreFiles from the memstore.   *
   * Existing StoreFiles are not destroyed until the new compacted StoreFile is
   * completely written-out to disk.   *
   * <p>The compactLock prevents multiple simultaneous compactions.
   * The structureLock prevents us from interfering with other write operations.   *
   * <p>We don't want to hold the structureLock for the whole time, as a compact()
   * can be lengthy and we want to allow cache-flushes during this period.   *
   * @param forceMajor True to force a major compaction regardless of thresholds
   * @return row to split around if a split is needed, null otherwise
   * @throws IOException
   */
  StoreSize compact(final boolean forceMajor) throws IOException {
    boolean forceSplit = this.region.shouldForceSplit();
    boolean majorcompaction = forceMajor;
    synchronized (compactLock) {
      /* get store file sizes for incremental compacting selection.
       * normal skew:
       *
       *         older ----> newer
       *     _
       *    | |   _
       *    | |  | |   _
       *  --|-|- |-|- |-|---_-------_-------  minCompactSize
       *    | |  | |  | |  | |  _  | |
       *    | |  | |  | |  | | | | | |
       *    | |  | |  | |  | | | | | |
       */
      // .............
      this.lastCompactSize = totalSize;

      // Max-sequenceID is the last key in the files we're compacting
      long maxId = StoreFile.getMaxSequenceIdInList(filesToCompact);

      // Ready to go.  Have list of files to compact.
      LOG.info("Started compaction of " + filesToCompact.size() + " file(s) in cf=" +
          this.storeNameStr +
        (references? ", hasReferences=true,": " ") + " into " +
          region.getTmpDir() + ", seqid=" + maxId +
          ", totalSize=" + StringUtils.humanReadableInt(totalSize));
      StoreFile.Writer writer = compact(filesToCompact, majorcompaction, maxId);
      // Move the compaction into place.
      StoreFile sf = completeCompaction(filesToCompact, writer);
    }
    return checkSplit(forceSplit);
  }
  /**
   * Do a minor/major compaction.  Uses the scan infrastructure to make it easy.
   *
   * @param filesToCompact which files to compact
   * @param majorCompaction true to major compact (prune all deletes, max versions, etc)
   * @param maxId Readers maximum sequence id.
   * @return Product of compaction or null if all cells expired or deleted and
   * nothing made it through the compaction.
   * @throws IOException
   */
  private StoreFile.Writer compact(final List<StoreFile> filesToCompact,
                               final boolean majorCompaction, final long maxId)
      throws IOException {
    // Make the instantiation lazy in case compaction produces no product; i.e.
    // where all source cells are expired or deleted.
    StoreFile.Writer writer = null;
    try {
      // ......
    } finally {
      if (writer != null) {
      	// !!!! StoreFile.Writer  write Metadata for maxid.
        writer.appendMetadata(maxId, majorCompaction);
        writer.close();
      }
    }
    return writer;
  }
}

 在compact时, 第一个compact(final boolean forceMajor)调用

compact(final List<StoreFile> filesToCompact, final boolean majorCompaction, final long maxId)
此方法最后写入writer.appendMetadata(maxId, majorCompaction); 也就是StoreFile中的appendMetadata方法.

可见, 是在finally中写入最大的logSeqNum. 这样StoreFile在取得每个logSeqNum, 可以由open读取logSeqNum; 

clusterId 保存在Hadoop集群ID.

4. HLog的生命周期

这里就涉及到HLog的生命周期问题了.如果HLog的logSeqNum对应的HFile已经存储在HDFS了(主要是比较HLog的logSeqNum是否比与其对应的表的HDFS StoreFile的maxLongSeqNum小),那么HLog就没有存在的必要了.移动到.oldlogs目录,最后删除.

反过来如果此时系统down了,可以通过HLog把数据从HDFS中读取,把要原来Put的数据读取出来, 重新刷新到HBase.

补充资料:

HBase 架构101 –预写日志系统 (WAL) 

http://cloudera.iteye.com/blog/911700

HLog的结构和生命周期

http://www.spnguru.com/2011/03/hlog%e7%9a%84%e7%bb%93%e6%9e%84%e5%92%8c%e7%94%9f%e5%91%bd%e5%91%a8%e6%9c%9f/

 

分享到:
评论
3 楼 marlay 2015-06-01  
"如果此Region的MemStore已经有缓存已有写入的数据, 则直接返回"
这个不对吧,任何的写入都会 “数据会首先会被写入WAL,之后将被写到实际存放数据的MemStore中” ,请确认
2 楼 greatwqs 2013-04-27  
触发是由于HRegion定时调用Flushcache:
protected boolean internalFlushcache(final HLog wal, final long myseqid) throws IOException(){
completeCacheFlush();
}
这种情况写HLog
completeCacheFlush(final byte [] encodedRegionName, final byte [] tableName, final long logSeqId, final boolean isMetaRegion)
public void completeCacheFlush(final byte [] encodedRegionName, 
    final byte [] tableName, final long logSeqId, final boolean isMetaRegion) 
throws IOException { 
  try { 
    if (this.closed) { 
      return; 
    } 
    synchronized (updateLock) { 
      long now = System.currentTimeMillis(); 
      WALEdit edit = completeCacheFlushLogEdit();
      //这一句表名是Flush这种操作的日志 
      HLogKey key = makeKey(encodedRegionName, tableName, logSeqId, 
          System.currentTimeMillis());
          //这一句表明该日志记录下了表名、分区名、当前的日志SequenceId 
      this.writer.append(new Entry(key, edit));
      //这一句写入日志文件 
      writeTime += System.currentTimeMillis() - now; 
      writeOps++; 
      this.numEntries.incrementAndGet(); 
      Long seq = this.lastSeqWritten.get(encodedRegionName); 
      if (seq != null && logSeqId >= seq.longValue()) { 
        this.lastSeqWritten.remove(encodedRegionName);
        //每个Region最后更新SequenceId被删除,表明该Region没有数据需要持久化。 
      } 
    } 
    // sync txn to file system 
    this.sync();
    //这种flush操作很重要,一定要同步到hdfs的其他节点上 
  } finally { 
    this.cacheFlushLock.unlock(); 
  } 
} 
1 楼 greatwqs 2013-04-27  

相关推荐

    hbase原理和设计

    ### HBase原理与设计 #### 一、HBase概述 HBase是一个开源的、高性能的分布式存储系统,基于Hadoop之上构建。它提供了一个高度可靠、面向列的存储方案,适用于处理大规模的数据集。HBase的设计特点包括: 1. **高...

    深入学习hbase原理资料整理

    《深入学习HBase原理》 HBase,全称为Hadoop Database,是一款高度可扩展的、高性能的、面向列的分布式数据库。它源自Google的Bigtable论文,并在其基础上为Hadoop生态系统提供了一种强大的非结构化数据存储解决...

    hbase-0.98.1源码包

    通过阅读源码,开发者可以更深入地理解HBase的工作原理,优化应用程序性能,解决遇到的问题,或者为HBase贡献新的功能和改进。此外,还可以对比不同版本的源码,了解HBase的发展历程和技术演进。

    HBase大数据技术原理与实践.pptx

    HBase的表结构由Cell组成,每个Cell包含RowKey(行键)、Column(列,由列族和列限定符组成)、Timestamp(时间戳)和Value(值)。所有的列族名、列名和值都是二进制类型,时间戳为long型。表可以设置命名空间,...

    hbase基本原理PPT教案.pptx

    1. **表存储结构**:HBase中的数据以表格形式组织,由行和列构成,列进一步划分为列族。 2. **Row Key**:行键是检索记录的主要依据,可以是任意字符串,最长64KB,按字典序排序存储。设计Row Key时,通常考虑位置...

    HBase实战源码

    源码分析是理解HBase工作原理和技术细节的重要途径。HBase在大数据领域扮演着关键角色,它能够处理海量数据并提供实时访问。下面,我们将深入探讨HBase的核心概念和源码中的关键组件。 1. **HBase架构**:HBase基于...

    HBASE基础应用的介绍

    HBase基于Google Bigtable论文的思想实现,旨在为海量结构化或半结构化数据提供高效的随机读写访问能力。作为一种NoSQL数据库,HBase支持高并发读写操作,并且能够自动处理数据的分布存储与负载均衡。 #### 二、...

    hbase-0.98.8-src.tar.gz

    2. 面向列:与传统的关系型数据库不同,HBase是面向列的,这使得它更适合处理稀疏的数据结构。 3. 实时读写:HBase提供低延迟的读写操作,适合实时数据查询。 4. 按需存储:只有被访问过的列才会被存储和计算,节省...

    HBase在小米中的应用实践

    ### HBase原理简介 HBase是一种分布式的、面向列的开源数据库,其设计灵感来源于Google的Bigtable论文。HBase提供了高性能的随机读写能力,适用于海量非结构化/半结构化数据存储。 #### 数据模型 HBase的数据模型...

    传智黑马赵星老师hadoop七天课程资料笔记-第六天(全)

    5. **hbase存储结构.png** 和 **hbase存储结构.png** - 可能是关于HBase在HDFS上的物理存储方式,包括HFile和HLog的格式,以及如何进行数据压缩和分布。 6. **第六天-HBase.ppt** - 这个PPT很可能是课程的主要内容...

    Hbase权威指南随书源代码源码包

    通过研究这些源码,读者可以了解到HBase的内部工作原理,如MemStore、HLog、BlockCache等关键组件的作用,以及它们如何协同工作以实现高效的数据存储和检索。此外,还能学习到如何根据业务需求来设计合理的表结构,...

    第4章-分布式数据库HBase.pdf

    HBase的实现原理涉及了其数据模型的设计,例如列族和时间戳等概念,以及内部的MemStore和HLog等重要组件。HBase的运行机制则包括RegionServer的负载均衡、数据的读写流程、数据的一致性模型和版本控制等。这些机制...

    HBase报告1

    【HBase原理与架构】 HBase是一个开源的分布式列式数据库,源于Google的Bigtable设计,它是Apache Hadoop项目的一...通过理解其基本原理和架构,我们可以更好地利用HBase来处理海量数据场景下的复杂查询和分析任务。

    hbase-2.1.7-bin.tar.gz

    《HBase 2.1.7:大数据组件的基石》 HBase,全称为Apache HBase,是一款基于谷歌Bigtable模型、设计用于处理海量数据的开源...通过理解和掌握HBase的原理和操作,开发者能更好地构建和优化大数据存储和分析系统。

    HBase概述——HBase的存储模型.pdf

    在HBase的具体实现中,LSM树体现在MemStore和HLog两个关键组件上。当数据写入时,首先会被追加到HLog,确保数据的持久性,随后添加到MemStore,这是一个内存中的数据结构。当MemStore满载后,系统会执行Flush操作,...

    HBase原理——要弄懂的sequenceId

    在HBase分布式数据库中,HLog(又称WAL,Write-Ahead Log)是关键的数据持久化组件,确保数据的一致性和可靠性。当我们讨论HBase的`sequenceId`时,我们实际上是在探讨如何在HBase的内存组件Memstore与持久化的HLog...

    hbase官方文档

    HBase是一款开源的、分布式的、版本化的非关系型数据库系统,它构建于Hadoop之上,主要用来存储非结构化和半结构化数据。该系统提供了高可靠性、高性能、面向列、可伸缩等特性,适合处理PB级别的大规模数据。 **...

    Hbase分布式数据库 v2.4.16.zip

    HBase 2.4.16 版本是其稳定版本,提供了高可靠性和高性能的数据存储解决方案,尤其适合处理大规模的非结构化数据。 ### 1. HBase 架构 HBase 的核心架构由 Region Server、Master Server 和 ZooKeeper 组成。...

    Ruby脚本hackery手动修复损坏的hbase_Ruby_下载.zip

    总之,使用Ruby进行HBase的修复工作是一项技术性极强的任务,需要对HBase的内部结构、数据模型以及Ruby编程有深入的理解。通过这样的脚本,我们可以自动化和定制化数据恢复过程,提高系统的健壮性和容错性。

Global site tag (gtag.js) - Google Analytics