`
yangbutao
  • 浏览: 1086 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

关于HBase MVCC的设计原理以及MVCC所引起的一个scan问题

阅读更多
最近在使用HBase0.94版本的时,偶尔会出现,HRegionInfo was null or empty in Meta 的警告

java.io.IOException: HRegionInfo was null or empty in Meta for writetest, row=lot_let,9399239430349923234234,99999999999999
at org.apache.hadoop.hbase.client.MetaScanner.metaScan(MetaScanner.java:170)




在客户端的MetaScanner.metaScan实现中

metaTable = new HTable(configuration, HConstants.META_TABLE_NAME);

Result startRowResult = metaTable.getRowOrBefore(searchRow,HConstants.CATALOG_FAMILY);

if (startRowResult == null) { throw new TableNotFoundException("Cannot find row in .META. for table: " + Bytes.toString(tableName) + ", row=" + Bytes.toStringBinary(searchRow)); }
byte[] value = startRowResult.getValue(HConstants.CATALOG_FAMILY,
HConstants.REGIONINFO_QUALIFIER);
if (value == null || value.length == 0) { throw new IOException("HRegionInfo was null or empty in Meta for " + Bytes.toString(tableName) + ", row=" + Bytes.toStringBinary(searchRow)); }

可以发现在扫描MetaScanner,rowkey所在的范围在Meta 表中不存在;通过RPC定位到服务端的实现




HRegion中:


public Result getClosestRowBefore(final byte [] row, final byte [] family)

  throws IOException {

    if (coprocessorHost != null) {

      Result result = new Result();

      if (coprocessorHost.preGetClosestRowBefore(row, family, result)) {

        return result;

      }

    }

    // look across all the HStores for this region and determine what the

    // closest key is across all column families, since the data may be sparse

    checkRow(row, "getClosestRowBefore");

    startRegionOperation();

    this.readRequestsCount.increment();

    try {

      Store store = getStore(family);

      // get the closest key. (HStore.getRowKeyAtOrBefore can return null)

      KeyValue key = store.getRowKeyAtOrBefore(row);

      Result result = null;

      if (key != null) {

        Get get = new Get(key.getRow());

        get.addFamily(family);

        result = get(get, null);

      }

      if (coprocessorHost != null) {

        coprocessorHost.postGetClosestRowBefore(row, family, result);

      }

      return result;

    } finally {

      closeRegionOperation();

    }

  }

在 KeyValue key = store.getRowKeyAtOrBefore(row);中获得了Meta表的rowkey,但是在后续的实现中


     if (key != null) {

        Get get = new Get(key.getRow());

        get.addFamily(family);

        result = get(get, null);

      }

获得空的result导致了这个问题;

为什么会存在这个现象。




先讲一下HBase 的MVCC的原理,

MVCC是保证数据一致性的手段,HBase在写数据的过程中,需要经过好几个阶段,写HLog,写memstore,更新MVCC;

只有更新了MVCC,才算真正memstore写成功,其中事务的隔离需要有mvcc的来控制,比如读数据不可以获取别的线程还未提交的数据。

1、put、delete数据都会调用applyFamilyMapToMemstore

HRegion中


private long applyFamilyMapToMemstore(Map<byte[], List<KeyValue>> familyMap,

    MultiVersionConsistencyControl.WriteEntry localizedWriteEntry) {

    long size = 0;

    boolean freemvcc = false;




    try {

      if (localizedWriteEntry == null) {

//开始一个写memstore,mvcc中的memstoreWrite++,并add待write pending队列中

        localizedWriteEntry = mvcc.beginMemstoreInsert();

        freemvcc = true;

      }




      for (Map.Entry<byte[], List<KeyValue>> e : familyMap.entrySet()) {

        byte[] family = e.getKey();

        List<KeyValue> edits = e.getValue();




        Store store = getStore(family);

        for (KeyValue kv: edits) {

          kv.setMemstoreTS(localizedWriteEntry.getWriteNumber());

          size += store.add(kv);

        }

      }

    } finally {

      if (freemvcc) {

        mvcc.completeMemstoreInsert(localizedWriteEntry);

      }

    }




     return size;

   }




  mvcc.completeMemstoreInsert,更新mvcc 的memstoreRead,也就是可以读的位置, 并通知readWaiters.notifyAll(),释放因flushcache调用waitForRead引起的阻塞;

waitForRead参见以下代码:

       public void waitForRead(WriteEntry e) {

    boolean interrupted = false;

    synchronized (readWaiters) {

//小于,表示还有写未提交

      while (memstoreRead < e.getWriteNumber()) {

        try {

          readWaiters.wait(0);

        } catch (InterruptedException ie) {

          // We were interrupted... finish the loop -- i.e. cleanup --and then

          // on our way out, reset the interrupt flag.

          interrupted = true;

        }

      }

    }

    if (interrupted) Thread.currentThread().interrupt();

  }





2、  在flushcache的过程中,获取到memstore中的keyvalues后,会调用mvcc.waitForRead(w)(因memstore所有的keyvalue,包括还未真正提交的,所以要等待其他事务提交后,才可以进行后续的flush操作,保证事务的一致性。



      w = mvcc.beginMemstoreInsert();


      mvcc.advanceMemstore(w);

    mvcc.waitForRead(w);




3、scan数据


在RegionScannerImpl.next方法实现中:


    public synchronized boolean next(List<KeyValue> outResults, int limit)

        throws IOException {

      if (this.filterClosed) {

        throw new UnknownScannerException("Scanner was closed (timed out?) " +

            "after we renewed it. Could be caused by a very slow scanner " +

            "or a lengthy garbage collection");

      }

      startRegionOperation();

      readRequestsCount.increment();

      try {




        // This could be a new thread from the last time we called next().

//this.readPoint在构造的时,初始化(readpoint为当前hregion的mvcc中的memstoreRead,为当前可读的点)和当前线程绑定

        MultiVersionConsistencyControl.setThreadReadPoint(this.readPt);




在MemStore中过滤掉还未提交的事务(新的keyvalue中有最新的point)





    protected KeyValue getNext(Iterator<KeyValue> it) {

      long readPoint = MultiVersionConsistencyControl.getThreadReadPoint();




      while (it.hasNext()) {

        KeyValue v = it.next();

//过滤掉大于当前线程readPoint的keyvalue

        if (v.getMemstoreTS() <= readPoint) {

          return v;

        }

      }




      return null;

    }



纵观MVCC的整个过程,再分析HRegion中的getClosestRowBefore方法实现,

      KeyValue key = store.getRowKeyAtOrBefore(row);

这个调用不会进行MVCC的控制,可以读到memstore中所有的数据

而get方法是会进行MVCC进行控制的,所以一种可能情况是在get调用的时, store.getRowKeyAtOrBefore(row)读到的key值还未提交,

所有都过滤掉了,查询范围为null。
分享到:
评论

相关推荐

    HBase数据库设计.doc

    - **时间戳(TimeStamp)**:每个单元格都有一个或多个版本,每个版本都有对应的时间戳。 - **单元格(Cell)**:由行键、列族和时间戳唯一定义的数据单元。 总的来说,HBase是一种面向大数据的列式存储系统,适用...

    hbase 表设计

    Apache HBase是一个开源的非关系型分布式数据库,它是Google Bigtable的开源实现。HBase特别适合于需要快速随机读写大量数据的应用场景。HBase架构与传统的关系型数据库(如MySQL、PostgreSQL、Oracle等)有着显著的...

    hbase原理和设计

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

    hbase 学习 hbase原理 hbase资料

    - **时间戳(Timestamp)**:每个值都有一个时间戳,用于记录数据的版本。 3. **HBase的操作** - **Put操作**:将数据写入表中,对应于传统的INSERT操作。 - **Get操作**:根据行键和列族/列获取数据,对应于...

    大数据书籍-Hbase架构设计(高清)

    书中详细阐述了Hbase的核心原理、生态环境以及在实际项目中的架构设计与性能优化策略,旨在帮助读者全面理解并掌握Hbase的运用。 Hbase作为Apache Hadoop生态系统的一部分,是一款开源的、非关系型的分布式数据库,...

    HBASE架构和原理解析

    1. **大规模存储**:一个HBase表可以包含数十亿行和上百万列,这使得HBase能够高效地处理海量数据。 2. **面向列族**:HBase表中的数据按照列族进行组织,而非传统的行或列方式。这意味着同一列族中的列会被存储在...

    HBase的工作原理及使用介绍

    里面包含HBase非关系数据库的工作原理,使用它的优点,缺点.

    HBase技术原理

    这种设计使得HBase能够在查询时快速定位到所需数据。 在HBase中,数据被分片存储在多个节点上,每个节点称为Region Server。Region是HBase的基本存储单元,负责一部分行键范围内的所有数据。当表中的数据增长时,...

    Hbase 表设计与操作

    HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。 HBase是Google Bigtable的开源实现,类似Google Bigtable...

    HbaseTemplate 操作hbase

    在IT行业中,尤其是在大数据处理领域,HBase是一个广泛使用的分布式、高性能、列式存储的NoSQL数据库。HBase是建立在Hadoop文件系统(HDFS)之上,为处理大规模数据提供了一个高效的数据存储解决方案。而Spring Data...

    浅谈HBASE数据结构设计.pdf

    ZooKeeper是一个分布式协调服务,它可以帮助HBase集群中的所有节点同步状态信息,以及执行选举等操作。 6. HBase的数据操作 - Get和Scan:Get操作用于获取单行数据,而Scan操作用于遍历多行数据。Scan可以指定起始...

    nosql&hbase;原理

    HBase是NoSQL家族中的列式存储数据库,它构建在Hadoop文件系统(HDFS)之上,是Hadoop生态中的一个组件。HBase利用HDFS的高可靠性、可伸缩性和实时读写能力,提供了分布式的数据存储解决方案。HBase支持数十亿行数据...

    HBase 基本原理

    HBase 基本原理,出版于 2014,HBase is a NoSQL database that primarily works on top of Hadoop. HBase is based on the storage architecture followed by the BigTable. HBase inherits the storage design ...

    Hbase的JavaAPI

    通过`Table`的`getScanner(Scan scan)`方法创建一个扫描器,`Scan`对象可以设置扫描范围(行键)、过滤器等。然后使用`ResultScanner.next()`或`ResultScanner.iterator()`遍历结果。 5. **批处理操作** 使用`...

    hbase_常用配置参数_以及学习笔记讲解_以及各种原理图.zip

    HBase,全称为Hierarchical Database,是Apache基金会的一个开源NoSQL数据库,主要设计用于处理海量半结构化数据的大数据存储。HBase构建于Hadoop之上,利用HDFS提供高容错性和可扩展性,适用于实时读写操作。在这个...

    hbase的rowkey设计与hbase的协处理器运用.docx

    HBase 是一个基于 HDFS 的分布式、面向列的 NoSQL 数据库,具有高性能、可靠性和扩展性等特点。本文将详细介绍 HBase 的 RowKey 设计和协处理器运用。 HBase 的介绍 HBase 是一个基于 HDFS 的分布式、面向列的 ...

Global site tag (gtag.js) - Google Analytics