【HBase】HBase 协处理器

文章目录一、协处理器的产生二、协处理器的类型2.1、Observer2.1.1、适用场景2.1.2、Observer 类型2.1.3、执行流程2.2.4、Observer Example2.2、Endpoint2.2.1、适用场景2.2.2、执行流程2.2.3、Endpoint Example三、协处理的加载方式3.1、静态加载与卸载3.1.1、静态加载3.1.2、静态卸载3.2、动态加载与卸载3...
摘要由CSDN通过智能技术生成

一、协处理器的产生

HBase 和 MapReduce 有很高的集成,可以使用 MR 对存储在 HBase 中的数据进行分布式计算,但是:

  • 有些情况,例如简单的加法计算或者聚合操作(求和、计数等),如果能够将这些计算推送到 RegionServer,这将大大减少服务器和客户的的数据通信开销,从而提高 HBase 的计算性能。
  • 另外,HBase 作为列式数据库,无法轻易建立“二级索引”,对于查询条件不在行健中的数据访问,效率十分低下。

在这种情况下,HBase 在 0.92 之后引入了协处理器(coprocessors),它允许用户将部分逻辑在数据存放端即 HBase RegionServer 服务端进行计算,也即允许用户在 RegionServer 运行用户自定义的代码。

协处理器的引入,执行求和、计数、排序等操作将变得更加高效,因为 RegionServer 将处理好的数据再返回给客户端,这可以极大地降低需要传输的数据量,从而获得性能上的提升。同时协处理器也允许用户扩展实现 HBase 目前所不具备的功能,如权限校验、二级索引、完整性约束等。

二、协处理器的类型

协处理器可以为全局 Region Server 上所有的表所使用,也可以为某一张表单独所使用,从这个方向划分,协处理器可分为:系统协处理器和表协处理器

从功能上看,也是为了更好保持其扩展的灵活性,协处理器又可分为观察者(Observer) 和 终端 (Endpoint) 两类。

  • Observer 提供了一些设计好的回调函数(钩子),类似于关系数据库的触发器,也可以类比面向切面编程中的 Advice;
  • Endpoint 自定义操作添加到服务器端,有点像存储过程。

2.1、Observer

Observer 是一些散布在 HBase Server 端代码中的 hook 钩子,在一些特定的事件发生时被执行,这些事件包括用户产生的事件,也包括服务器内部产生的事件。

比如: put 操作之前有钩子函数 prePut,该函数在 put 操作执行前会被 Region Server 调用;在 put 操作之后则有 postPut 钩子函数。

2.1.1、适用场景
  • 权限校验:在执行GetPut操作之前,可以使用preGetprePut方法检查权限;
  • 完整性约束: HBase 不支持关系型数据库中的外键功能,可以通过触发器在插入或者删除数据的时候,对关联的数据进行检查;
  • 二级索引:使用钩子关联行修改操作来维护二级索引。
2.1.2、Observer 类型

目前 HBase 内置实现的 Observer 主要有以下几个:

  • WALObserver:运行于 RegionServer 中,进行 WAL 写和刷新之前或之后会触发这个钩子函数,一个 RegionServer 只有一个 WAL 的上下文;
  • MasterObserver:运行于 Master 进程中,进行诸如 DDL 的操作,如 create, delete, modify table 等之前或之后会触发这个钩子函数;
  • RegionObserver:基于表的 Region 上的 Get, Put, Delete, Scan 等操作之前或之后触发,比如可以在客户端进行 Get 操作的时候定义 RegionObserver 来校验是否具有 Get 权限等;
  • BulkLoadObserver:进行 BulkLoad 的操作之前或之后会触发这个钩子函数;
  • RegionServerObserver :RegionServer 上发生的一些操作可以触发这个钩子函数,这个是 RegionServer 级别的事件;
  • EndpointObserver:每当用户调用 Endpoint 之前或之后会触发这个钩子。
2.1.3、执行流程

以 RegionObserver 为例,其执行流程大致如下图:

  • 客户端发出 put 请求
  • 该请求被分派给合适的 RegionServer 和 Region
  • CoprocessorHost 拦截该请求,然后在该表的每个 RegionObserver 上调用 prePut()
  • prePut() 处理后,在 Region 执行 Put 操作
  • Region 产生的结果再次被 CoprocessorHost 拦截,调用 postPut()
  • 终结果被返回给客户端
2.2.4、Observer Example

HBase 本身是不支持二级索引( Secondary Index)的,基于索引检索数据只能单纯地依靠 RowKey,为了能支持多条件查询,开发者需要将所有可能作为查询条件的字段尽可能拼接到 RowKey 中,这是 HBase 开发中极为常见的做法,也是推荐的做法。

在《 HBase 实战》一书中,有个例子:当 a 关注 b 时,在 follower 表添加一行数据,RowKey 为 hash(a)+hash(b),同时在 followedBy 表添加一行数据,RowKey 为 hash(b)+hash(a),这样就能实现我关注了谁谁关注了我这样的需求。

但是 HBase 不提供跨行事务去保证这两张表数据的一致性,这时候就可以利用 Observer 的 hook 函数提供一致性的保证。当 postPut 函数失败的时候,HBase 会自动重试 postPut 函数,直到 postPut 函数执行成功,通过同步重试来保证多条数据是同时插入成功的。

这其实就是二级索引的实现:在往一张表 A 中插入数据的时候,利用协处理器将 A表中的值作为行健、A 表的行健作为值插入 B 表,然后查询的时候,就可以通过 B 查询出 A 中的行健,继而快速从 A 中检索出需要的数据。

/**
 * 2.0 版本之前使用extends BaseRegionObserver 实现
 *
 * @author w1992wishes 2019/7/30 20:52
 */
public class FollowsObserver implements RegionObserver, RegionCoprocessor {
   

    private static final Logger LOGGER = LoggerFactory.getLogger(FollowsObserver.class);

    private Connection conn;

    @Override
    public void start(CoprocessorEnvironment env) throws IOException {
   
        LOGGER.info("****** start ******");
        conn = ConnectionFactory.createConnection(env.getConfiguration());
    }

    @Override
    public void stop(CoprocessorEnvironment env) throws IOException {
   
        LOGGER.info("****** stop ******");
        conn.close();
    }

    @Override
    public void postPut(ObserverContext<RegionCoprocessorEnvironment> c, Put put, WALEdit edit, Durability durability)
            throws IOException {
   

        byte[] table = c.getEnvironment().getRegion().getRegionInfo().getTable().getName();
        if (!Bytes.equals(table, FOLLOWS_TABLE_NAME)) {
   
            return;
        }

        Cell fCell = put.get(RELATION_FAM, FROM).get(0);
        String from = Bytes.toString(fCell.getValueArray());
        Cell tCell = put.get(RELATION_FAM, TO).get(0);
        String to = Bytes.toString(tCell.getValueArray());

        RelationsDAO relationsDAO = new RelationsDAO(conn);
        relationsDAO.addFollowedBy(to, from);
        LOGGER.info("****** Create followedBy relation successfully! ****** ");
    }

}

2.2、Endpoint

2.2.1、适用场景

Endpoint 和 RDMBS 的存储过程很类似,用户提供一些自定义代码,并在 HBase 服务器端执行,结果通过 RPC 返回给客户,Endpoint 可以实现 min、 max、 avg、 sum、 distinct、 group by 等功能。

以聚合为例,如果没有协处理器,当用户需要找出一张表中的最大数据,即 max 聚合操作,需要进行全表扫描,返回所以数据给客户端,然后在客户端遍历扫描结果,查找最大值。

这是一种典型的“移动数据”的计算方案,将所有数据都移动到计算一端 Client,由 Client 端统一执 行,这样无法利用底层集群的并发能力,效率低下,而利用 Coprocessor,则可以实现“移动计算”,用户可以将求最大值的代码放到 HBase Server 端,利用 HBase 集群的多个节点并发执行求最大值的操作。即在每个 Region 范围内 执行求最大值的代码,将每个 Region 的最大值在 Region Server 端计算出,仅仅将该 max 值返回给客户端。在客户端进一步将多个 Region 的最大值进一步处理而找到其中的最大值。这样整体的执行效率就会提高很多。

2.2.2、执行流程

2.2.3、Endpoint Example

第一步:首先要安装 protobuf

Protobuf Buffers 是一种轻便高效的结构化数据存储格式,可以用于数据序列化。适合做数据存储或 RPC 数据交换格式。用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

在 HBase 中使用的 Protobuf 版本为 2.5.0,所以选择安装相同版本的 Protobuf。可以从官方的下载页面找到所以版本:https://repo1.maven.org/maven2/com/google/protobuf/protoc/。

下载后,配置好环境变量。

第二步:使用Protobuf生成序列化类

与 Observer 类型不同的是,Endpoint 协处理器需要与服务区直接通信,服务端是对于 Protobuf Service 的实现,所以两者之间会有一个基于 protocol 的 RPC 接口,客户端和服务端都需要进行基于接口的代码逻辑实现。

1)先准备一个 proto 文件 Count.proto,使用 ProtoBuf 的 message 做为消息传递的格式,使用 Rpc 做为传输协议,一般会定义三个 ProtoBuf 域,用于请求、响应、和业务实现:

syntax = "proto2";

option java_package = "me.w1992wishes.hbase.inaction.coprocessors";
option java_outer_classname = "CountCoprocessor";
option java_generic_services = true;
option java_generate_equals_and_hash = true;
option optimize_for = SPEED; 

/*具体的消息
 *每个message域对应一个内部类,该内部类还包含一个Builder内部类
 *域内字段会生成对应的 setter和getter方法
 *使用 Builder 内部类来对字段赋值
 **/
message CountRequest {
    required string startKey = 1;
    required string endKey = 2;
}

message CountResponse {
    required int64 count = 1 [default = 0]; 
}
/*提供服务的类
 *该类没有Builder内部类
 */
service CountService { 
    rpc count(CountRequest) 
      returns (CountResponse); 
}

2)在命令行执行命令生成 Java 类:

protoc --java_out=E:\project\my_project\test Count.proto

运行后会生成 CountCoprocessor.java 类,将其拷贝到对应的包下面,并添加相应的依赖。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值