热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

对hbasecoprocessor使用方法不当导致的一个程序bug

在某系统中对一张表数据写入量很大,频繁的compaction导致效率很低。这张表已经presharding过了,有几百个region,由于某些原因,短期内不太允许增大region数。当时采用的方法是每小时生成一张表,每小时的数据只写对应的表。后来发现这24张表对后面的业务处

在某系统中对一张表数据写入量很大,频繁的compaction导致效率很低。这张表已经presharding过了,有几百个region,由于某些原因,短期内不太允许增大region数。当时采用的方法是每小时生成一张表,每小时的数据只写对应的表。后来发现这24张表对后面的业务处

在某系统中对一张表数据写入量很大,频繁的compaction导致效率很低。这张表已经presharding过了,有几百个region,由于某些原因,短期内不太允许增大region数。当时采用的方法是每小时生成一张表,每小时的数据只写对应的表。后来发现这24张表对后面的业务处理带来很大的麻烦。需要把这24张表合为一张表,于是写了个DisableRegionCompaction,想对指定时间前的数据禁用compaction。

看了hbase coprocessor的官网介绍(https://blogs.apache.org/hbase/entry/coprocessor_introduction)。hbase的coprocessor分为observer和endpoint两种,coprocessor类似于传统数据库的触发器,endpoint则类似于存储过程。observer又分为三种:RegionObserver,WALObserver和MasterObserver。

RegionObserver: Provides hooks for data manipulation events, Get, Put, Delete, Scan, and so on. There is an instance of a RegionObserver coprocessor for every table region and the scope of the observations they can make is constrained to that region.

WALObserver: Provides hooks for write-ahead log (WAL) related operations. This is a way to observe or intercept WAL writing and reconstruction events. A WALObserver runs in the context of WAL processing. There is one such context per region server.

MasterObserver: Provides hooks for DDL-type operation, i.e., create, delete, modify table, etc. The MasterObserver runs within the context of the HBase master.

如果要控制hbase表的compaction行为,理论上只要写一个针对region的RegionObserver coprocessor就能可以。于是写了个DisableRegionCompaction类,它实现了RegionObserver接口类,重写了preCompactSelection这一个接口,其他的接口都用的是eclipse自动生成的代码。

public void preCompactSelection(ObserverContext c, Store store, List candidates) {
    // candidates中保存的是所有要进行compaction的候选的StoreFile
    // 程序里面主要干的活是:对一个小时之前的StoreFile从candidates中剔除(remove)掉不参与compaction
}

测试的时候发现有数据丢失的情况。下图中数据是四条记录,hfile有四个文件:
hfile-log

图中这张表有4个hfile,本意是让其中18:33分的两个hfile不参与compaction,剩余的两个合并。

现象是major_compact后,凡是preCompactSelection代码中remove掉的region数据(18:33分的两个hfile)都存在,剩余参与compaction的StoreFile中数据(18:34和18:35分的两个)都丢失了!

查看region server上的log:

发现确实有2个StoreFile参与了compaction,但是结果数据为null。

查看hbase 0.94.1代码,发现是org/apache/hadoop/hbase/regionserver/Store.java的compactStore()返回的结果为空

compactStore() 代码中发现最可能是这几行有问题:

        /* include deletes, unless we are doing a major compaction */
        scanner = new StoreScanner(this, scan, scanners,
            majorCompaction ? ScanType.MAJOR_COMPACT : ScanType.MINOR_COMPACT,
            smallestReadPoint, earliestPutTs);
        if (region.getCoprocessorHost() != null) {
          InternalScanner cpScanner = region.getCoprocessorHost().preCompact(
              this, scanner);
          // NULL scanner returned from coprocessor hooks means skip normal processing
          if (cpScanner == null) {
            return null;
          }
          scanner = cpScanner;
        }

联想到preCompact也是有coprocessor接口的,于是看我自己写的DisableRegionCompaction代码(eclipse自动生成的)发现是这样写的:

public InternalScanner preCompact(
           ObserverContext c, Store store,
           InternalScanner scanner) {
       // TODO Auto-generated method stub
       return null;
    }

就是这个地方的问题了,返回了一个null的scanner,改为返回传入的scanner就可以了,因为这里并不需要重写preCompact接口。

其实在RegionObserver接口中对preCompact接口的定义:

  /**
   * Called prior to writing the {@link StoreFile}s selected for compaction into
   * a new {@code StoreFile}.  To override or modify the compaction process,
   * implementing classes have two options:
   *
   *
	Wrap the provided {@link InternalScanner} with a custom
   *   implementation that is returned from this method.  The custom scanner
   *   can then inspect {@link KeyValue}s from the wrapped scanner, applying
   *   its own policy to what gets written.
*
	Call {@link org.apache.hadoop.hbase.coprocessor.ObserverContext#bypass()}
   *   and provide a custom implementation for writing of new
   *   {@link StoreFile}s.  Note: any implementations bypassing
   *   core compaction using this approach must write out new store files
   *   themselves or the existing data will no longer be available after
   *   compaction.
*
* @param c the environment provided by the region server
   * @param store the store being compacted
   * @param scanner the scanner over existing data used in the store file
   * rewriting
   * @return the scanner to use during compaction.  Should not be {@code null}
   * unless the implementation is writing new store files on its own.
   * @throws IOException if an error occurred on the coprocessor
   */
  InternalScanner preCompact(final ObserverContext c,
      final Store store, final InternalScanner scanner) throws IOException;

对返回值有个说明“@return the scanner to use during compaction. Should not be {@code null}unless the implementation is writing new store files on its own.”

再仔细看了下hbase的代码,发现hbase里面已经有个实现了RegionObserver接口的BaseRegionObserver的抽象类了,它里面的实现就是:

  @Override
  public InternalScanner preCompact(ObserverContext e,
      final Store store, final InternalScanner scanner) throws IOException {
    return scanner;
  }

所以代码里面直接继承BaseRegionObserver这个抽象类就可以了。

在hbase官方文档(https://blogs.apache.org/hbase/entry/coprocessor_introduction)上对BaseRegionObserver类的说明是:

We provide a convenient abstract class BaseRegionObserver, which implements all RegionObserver methods with default behaviors, so you can focus on what events you have interest in, without having to be concerned about process upcalls for all of them.

看起来是对接口使用不当的低级错误。大家引己为戒,多读读hbase官方文档吧。

正如某大牛所说:

一个设计良好的系统,对于包含很多接口的接口类,一般都提供了抽象类供使用。

推荐阅读
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
  • Activiti7流程定义开发笔记
    本文介绍了Activiti7流程定义的开发笔记,包括流程定义的概念、使用activiti-explorer和activiti-eclipse-designer进行建模的方式,以及生成流程图的方法。还介绍了流程定义部署的概念和步骤,包括将bpmn和png文件添加部署到activiti数据库中的方法,以及使用ZIP包进行部署的方式。同时还提到了activiti.cfg.xml文件的作用。 ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • 大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记
    本文介绍了大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记,包括outputFormat接口实现类、自定义outputFormat步骤和案例。案例中将包含nty的日志输出到nty.log文件,其他日志输出到other.log文件。同时提供了一些相关网址供参考。 ... [详细]
  • Java如何导入和导出Excel文件的方法和步骤详解
    本文详细介绍了在SpringBoot中使用Java导入和导出Excel文件的方法和步骤,包括添加操作Excel的依赖、自定义注解等。文章还提供了示例代码,并将代码上传至GitHub供访问。 ... [详细]
  • 本文总结了初学者在使用dubbo设计架构过程中遇到的问题,并提供了相应的解决方法。问题包括传输字节流限制、分布式事务、序列化、多点部署、zk端口冲突、服务失败请求3次机制以及启动时检查。通过解决这些问题,初学者能够更好地理解和应用dubbo设计架构。 ... [详细]
  • 项目运行环境配置及可行性分析
    本文介绍了项目运行环境配置的要求,包括Jdk1.8、Tomcat7.0、Mysql、HBuilderX等工具的使用。同时对项目的技术可行性、操作可行性、经济可行性、时间可行性和法律可行性进行了分析。通过对数据库的设计和功能模块的设计,确保系统的完整性和安全性。在系统登录、系统功能模块、管理员功能模块等方面进行了详细的介绍和展示。最后提供了JAVA毕设帮助、指导、源码分享和调试部署的服务。 ... [详细]
  • Tomcat安装与配置教程及常见问题解决方法
    本文介绍了Tomcat的安装与配置教程,包括jdk版本的选择、域名解析、war文件的部署和访问、常见问题的解决方法等。其中涉及到的问题包括403问题、数据库连接问题、1130错误、2003错误、Java Runtime版本不兼容问题以及502错误等。最后还提到了项目的前后端连接代码的配置。通过本文的指导,读者可以顺利完成Tomcat的安装与配置,并解决常见的问题。 ... [详细]
  • Struts2+Sring+Hibernate简单配置
    2019独角兽企业重金招聘Python工程师标准Struts2SpringHibernate搭建全解!Struts2SpringHibernate是J2EE的最 ... [详细]
  • .htaccess文件 ... [详细]
  • 本文整理了Java中org.apache.hadoop.hive.ql.plan.ExprNodeColumnDesc.getTypeInfo()方法的一些代码示例,展 ... [详细]
  • 初探PLC 的ST 语言转换成C++ 的方法
    自动控制软件绕不开ST(StructureText)语言。它是IEC61131-3标准中唯一的一个高级语言。目前,大多数PLC产品支持ST ... [详细]
  • Allegro总结:1.防焊层(SolderMask):又称绿油层,PCB非布线层,用于制成丝网印板,将不需要焊接的地方涂上防焊剂.在防焊层上预留的焊盘大小要比实际的焊盘大一些,其差值一般 ... [详细]
  • 20209测试通过:eclipse安装svn插件
    网址不能用了,新的办法参考:https:quantum6.blog.csdn.netarticledetails117250800下载了最新的ecli ... [详细]
author-avatar
我爱妈妈的家常菜_712
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有