HBase协处理器开发之向kafka发送消息

协处理器开发之向kafka发送消息

 

一、介绍

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章节

 

图1 RegionObserver工作原理

 

3.2终端(Endpoint)

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

1、定义一个新的protocol接口,必须继承CoprocessorProtocol.

2、实现终端接口,该实现会被导入region环境执行。

3、继承抽象类BaseEndpointCoprocessor.

4、在客户端,终端可以被两个新的HBase Client API调用 。单个region:HTableInterface.coprocessorProxy(Class<T> protocol, byte[] row) 。rigons区域:HTableInterface.coprocessorExec(Class<T> protocol, byte[] startKey, byte[] endKey, Batch.Call<T,R> callable)

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

 

 

二、协处理器开发之向kafka发送消息代码案例(Observer)

1、新建一个java项目,并把需要用到的jar包导入。

 

 

2、自定义一个抽象类AbstractRegionObserver继承

org.apache.hadoop.hbase.coprocessor.BaseRegionObserver

 注意:相关的Hbase的jar包不能缺失

import java.io.IOException;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.NavigableMap;

import java.util.Set;

import java.util.TreeMap;

import java.util.TreeSet;

import java.util.concurrent.ConcurrentHashMap;

   

import org.apache.commons.collections.CollectionUtils;

import org.apache.commons.lang.StringUtils;

import org.apache.hadoop.hbase.Cell;

import org.apache.hadoop.hbase.CellUtil;

import org.apache.hadoop.hbase.CoprocessorEnvironment;

import org.apache.hadoop.hbase.TableName;

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

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

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

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

import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;

import org.apache.hadoop.hbase.util.Bytes;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

   

import com.iflytek.rlf.utils.PropertiesReader;

   

/**

*

* 系统常量

*

* @author bxji

*

*/

public abstract class AbstractRegionObserver extends BaseRegionObserver {

   public static final Logger LOG = LoggerFactory.getLogger(PlaceTrackHotelRegionObserver.class);

   

   /** 记录间拼接符 "\u0004" */

   public static String FILED_SEGMENT_1 = "\u0004";

   

   /**

    * hbase的表空间

    */

   public static final String NAMESPACE = PropertiesReader.getPerpValue("hbase.namespace", "default");

   

   /**

    * 全局缓存

    */

   public static final Map<String, Table> TABLE_MAP = new ConcurrentHashMap<String, Table>();

   

}

3、自定义一个测试类TestObserver_kafka继承我们上面写的抽象类AbstractRegionObserver;

注意:这里用到了kafka生产者对象,故必须有kafka-clinet的jar包,主要有

 

代码如下

package com.iflytek.rlf.coprocessor;

 

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

 

import org.apache.commons.lang.StringUtils;

import org.apache.hadoop.hbase.CellUtil;

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

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

import org.apache.hadoop.hbase.coprocessor.ObserverContext;

import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;

import org.apache.hadoop.hbase.regionserver.wal.WALEdit;

import org.apache.hadoop.hbase.util.Bytes;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

import com.iflytek.rlf.utils.KafkaUtil;

 

/**

 * 协处理测试:向HBase表put一条数据,处罚协处理器添加一列, 并向kafka发送消息 测试结果:由HBase shell

 * put一条数据,添加了一列并秒发一条消息 到kafka

 *

 * @author wangshoukui

 */

public class TestObserver_kafka extends AbstractRegionObserver {

 

/** 列族名称 */

private static final String TABLE_FAMILY_TXGX = "info";

 

public static final String COLUMN_NAME_YEAYS = "c1";

 

public static final List<byte[]> QUALIFIERS = new ArrayList<byte[]>();

 

public static final byte[] FAMILY = Bytes.toBytes(TABLE_FAMILY_TXGX);

 

public static final Logger LOG = LoggerFactory

.getLogger(PersonTrackRegionObserver.class);

 

static {

String[] columns = StringUtils.split(COLUMN_NAME_YEAYS, ",");

for (String column : columns) {

QUALIFIERS.add(Bytes.toBytes(column));

}

LOG.info("协处理器类TestObserver_kafka 被 加载!");

}

 

@Override

public void prePut(ObserverContext<RegionCoprocessorEnvironment> e,

Put put, WALEdit edit, Durability durability) throws IOException {

//添加1列

put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("c2"),

Bytes.toBytes("test"));

//测试向kafka中发送数据

String result1 = Bytes.toString(CellUtil.cloneValue(put.get(

Bytes.toBytes("info"), Bytes.toBytes("c1")).get(0)));

try {

KafkaUtil.sendMessage(result1.substring(0, result1.length() / 2),

result1);

} catch (Exception e1) {

}

}

}

 

4、将项目打jar包,如下:

 

 

 

5、将jar包上传到hdfs上并部署协处理器到相应表

 也可以上传到本地文件系统,但是每台集群机器都需要上传,极不方便,故上传至hdfs,如下:

hdfs dfs -put /wsk_tmp/qbpt-cube-service-api6.jar /

 

 本案列是通过alter给特定表添加协处理器,如下:

首先使表下线:

 

 

然后添加协处理器:

 

查看表结构,可知已经绑定协处理器:

 

使表上线:enable 'test6'    //上线后表才能够使用

删除协处理器:

   

 

三、测试

(作者测试是完全成功的,通过HBase shell put 一条数据,测试表会多添加一列,并向kafka发送一条消息)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值