细述hbase协处理器

1.起因(Why HBase Coprocessor)

HBase作为列族数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执行求和、计数、排序等操作。比如,在旧版本的(<0.92)Hbase中,统计数据表的总行数,需要使用Counter方法,执行一次MapReduce Job才能得到。虽然HBase在数据存储层中集成了MapReduce,能够有效用于数据表的分布式计算。然而在很多情况下,做一些简单的相加或者聚合计算的时候,如果直接将计算过程放置在server端,能够减少通讯开销,从而获得很好的性能提升。于是,HBase在0.92之后引入了协处理器(coprocessors),实现一些激动人心的新特性:能够轻易建立二次索引、复杂过滤器(谓词下推)以及访问控制等。

2.灵感来源( Source of Inspration)

HBase协处理器的灵感来自于Jeff Dean 09年的演讲( P66-67)。它根据该演讲实现了类似于bigtable的协处理器,包括以下特性:

每个表服务器的任意子表都可以运行代码 客户端的高层调用接口(客户端能够直接访问数据表的行地址,多行读写会自动分片成多个并行的RPC调用) 提供一个非常灵活的、可用于建立分布式服务的数据模型 能够自动化扩展、负载均衡、应用请求路由 HBase的协处理器灵感来自bigtable,但是实现细节不尽相同。HBase建立了一个框架,它为用户提供类库和运行时环境,使得他们的代码能够在HBase region server和master上处理。

3.细节剖析(Implementation)

协处理器分两种类型,系统协处理器可以全局导入region server上的所有数据表,表协处理器即是用户可以指定一张表使用协处理器。协处理器框架为了更好支持其行为的灵活性,提供了两个不同方面的插件。一个是观察者(observer),类似于关系数据库的触发器。另一个是终端(endpoint),动态的终端有点像存储过程。3.1观察者(Observer)

观察者的设计意图是允许用户通过插入代码来重载协处理器框架的upcall方法,而具体的事件触发的callback方法由HBase的核心代码来执行。协处理器框架处理所有的callback调用细节,协处理器自身只需要插入添加或者改变的功能。

以HBase0.92版本为例,它提供了三种观察者接口:

RegionObserver:提供客户端的数据操纵事件钩子:Get、Put、Delete、Scan等。 WALObserver:提供WAL相关操作钩子。 MasterObserver:提供DDL-类型的操作钩子。如创建、删除、修改数据表等。 这些接口可以同时使用在同一个地方,按照不同优先级顺序执行.用户可以任意基于协处理器实现复杂的HBase功能层。HBase有很多种事件可以触发观察者方法,这些事件与方法从HBase0.92版本起,都会集成在HBase API中。不过这些API可能会由于各种原因有所改动,不同版本的接口改动比较大,具体参考Java Doc。

RegionObserver工作原理,如图1所示。更多关于Observer细节请参见HBaseBook的第 9.6.3章节。

3.2终端(Endpoint)

终端是动态RPC插件的接口,它的实现代码被安装在服务器端,从而能够通过HBase RPC唤醒。客户端类库提供了非常方便的方法来调用这些动态接口,它们可以在任意时候调用一个终端,它们的实现代码会被目标region远程执行,结果会返回到终端。用户可以结合使用这些强大的插件接口,为HBase添加全新的特性。终端的使用,如下面流程所示:

  1. 定义一个新的protocol接口,必须继承CoprocessorProtocol.
  2. 实现终端接口,该实现会被导入region环境执行。
  3. 继承抽象类BaseEndpointCoprocessor.
  4. 在客户端,终端可以被两个新的HBase Client API调用 。 单个region:HTableInterface.coprocessorProxy(Class protocol, byte[] row) 。 rigons区域:HTableInterface.coprocessorExec(Class protocol, byte[] startKey, byte[] endKey, Batch.Call callable)

整体的终端调用过程范例,所示:

4.编程实践(Code Example)

在该实例中,我们通过计算HBase表中行数的一个实例,来真实感受协处理器 的方便和强大。在旧版的HBase我们需要编写MapReduce代码来汇总数据表中的行数,在0.92以上的版本HBase中,只需要编写客户端的代码即可实现,非常适合用在WebService的封装上。

4.1启用协处理器 Aggregation(Enable Coprocessor Aggregation)

我们有两个方法: 1.启动全局aggregation,能过操纵所有的表上的数据。通过修改hbase-site.xml这个文件来实现,只需要添加如下代码:

<property>

  <name>hbase.coprocessor.user.region.classes</name>

  <value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>

</property>

2.启用表aggregation,只对特定的表生效。通过HBase Shell 来实现。

  1. disable指定表。hbase> disable 'mytable'
  2. 添加aggregation hbase> alter 'mytable', METHOD => 'table_att','coprocessor'=>'|org.apache.hadoop.hbase.coprocessor.AggregateImplementation||'
  3. 重启指定表 hbase> enable 'mytable'
disable 'xyz'

alter 'xyz','coprocessor'=>'|org.apache.hadoop.hbase.coprocessor.example.RowCountEndpoint||'

enable 'xyz'
package hbase.learn.com;



import java.util.Map;



import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.client.HTable;



public class RowCount {

   public static void main(String[] args) {

       String tableName="xyz";

       // Get instance of Configuration

       Configuration configuration = HBaseConfiguration.create();



       // Get table instance

       HTable table = new HTable(configuration, tableName);

        final ExampleProtos.CountRequest request = ExampleProtos.CountRequest.getDefaultInstance();

           Map<byte[],Long> results = table.coprocessorService(ExampleProtos.RowCountService.class,

               null, null,

               new Batch.Call<ExampleProtos.RowCountService,Long>() {

                 public Long call(ExampleProtos.RowCountService counter) throws IOException {

                   ServerRpcController controller = new ServerRpcController();

                   BlockingRpcCallback<ExampleProtos.CountResponse> rpcCallback =

                       new BlockingRpcCallback<ExampleProtos.CountResponse>();

                   counter.getRowCount(controller, request, rpcCallback);

                   ExampleProtos.CountResponse response = rpcCallback.get();

                   if (controller.failedOnException()) {

                     throw controller.getFailedOn();

                   }

                   return (response != null && response.hasCount()) ? response.getCount() : 0;

                 }

               });



           long sum=0;

           int count=0;

           for(Long l:results.values()){

               sum+=l;

               count++;

           }

           System.out.println("row count = "+sum);

           System.out.println("region count = "+count);

   }

}

原文发布于微信公众号 - Spark学习技巧(bigdatatip)

原文发表时间:2018-10-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jed的技术阶梯

zookeeper案例之4个逻辑思维训练小题目

14120
来自专栏坚毅的PHP

HBase行锁探索

https://github.com/sgp2004/JavaTools 代码地址 HBase客户端的行锁会对相同rowkey的读写造成很大影响,同一个进程并发...

52460
来自专栏学海无涯

HBase之比较过滤器

最近在学习Hadoop中的HBase,通过本次实验,可以理解比较过滤器,能够掌握并运用。主要包含行比较过滤器和列族比较过滤器实验。在进行实验之前需要导入HBas...

83050
来自专栏xiaoheike

Spring Application Event Example

https://github.com/xiaoheike/SpringApplicationEventExample.git

18710
来自专栏XAI

微信支付-Java-SpringMVC基础一些代码支持

官网文档和demo代码下载地址 https://mp.weixin.qq.com/htmledition/res/bussiness-faq/wx_app_pa...

951100
来自专栏实战docker

Docker下HBase学习,三部曲之三:java开发

前两章《Docker下HBase学习,三部曲之一:极速体验》和《Docker下HBase学习,三部曲之二:集群HBase搭建》我们学习了HBase的单机和集群环...

57660
来自专栏点滴积累

geotrellis使用(五)使用scala操作Accumulo

    要想搞明白Geotrellis的数据处理情况,首先要弄清楚数据的存放,Geotrellis将数据存放在Accumulo中。     Accumulo是一...

41040
来自专栏java学习

Java基础总结大全(4)

最新通知 ●回复"每日一练"获取以前的题目! ●【新】Android视频更新了!(回复【安卓视频】获取下载链接) ●【新】Ajax知识点视频更新了!(回复【学习...

382130
来自专栏battcn

一起来学SpringBoot | 第十八篇:轻松搞定全局异常

实际项目开发中,程序往往会发生各式各样的异常情况,特别是身为服务端开发人员的我们,总是不停的编写接口提供给前端调用,分工协作的情况下,避免不了异常的发生,如果直...

15720
来自专栏Java架构师历程

spring boot应用启动原理分析

摘要: spring boot quick start 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar...

87630

扫码关注云+社区

领取腾讯云代金券