HBase协处理器及实例

2023-11-02 18:48
文章标签 实例 hbase 协处理器

本文主要是介绍HBase协处理器及实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

为什么引入协处理器?

HBase作为列数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执行求和、计数、排序等操作。

比如,在旧版本(<0.92)的Hbase中,统计数据表的总行数,需要使用Counter方法,执行一次MapReduce Job才能得到。

虽然HBase在数据存储层中集成了MapReduce,能够有效用于数据表的分布式计算。然而在很多情况下,做一些简单的相加或者聚合计算的时候,如果直接将计算过程放置在server端,能够减少通讯开销,从而获得很好的性能提升。于是, HBase在0.92之后引入了协处理器(coprocessors)。
协处理器实现了一些激动人心的新特性:能够轻易建立二次索引、复杂过滤器(谓词下推)以及访问控制等。

灵感来源

HBase协处理器的灵感来自于Jeff Dean 09年的演讲。它根据该演讲实现了类似于bigtable的协处理器,包括以下特性:
1、每个表服务器的任意子表都可以运行代码。
2、客户端的高层调用接口 (客户端能够直接访问数据表的行地址,多行读写会自动分片成多个并行的RPC调用)。
3、提供一个非常灵活的、可用于建立分布式服务的数据模型。
4。能够自动化扩展、负载均衡、应用请求路由

HBase的协处理器灵感来自 bigtable,但是实现细节不尽相同。 HBase建立了一个框架,它为用户提供类库和运行时环境,使得他们的代码能够在HBase region server和master上处理。

协处理器类型

协处理器分两种类型:
系统协处理器:可以全局导入region server上的所有数据表。
表协处理器:用户可以指定一张表使用协处理器。

协处理器插件

协处理器框架为了更好支持其行为的灵活性,提供了两个不同方面的插件。
一个是观察者(observer),类似于关系数据库的触发器。
另一个是终端(endpoint),动态的终端有点像存储过程。

Observer

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

以HBase0.92版本为例,它提供了三种观察者接口
RegionObserver:提供客户端的数据操纵事件钩子: Get、 Put、 Delete、Scan等。
WALObserver:提供WAL相关操作钩子。
MasterObserver:提供DDL-类型的操作钩子。如创建、删除、修改数据表等。

这些接口可以同时使用在同一个地方,按照不同优先级顺序执行。用户可以任意基于协处理器实现复杂的HBase功能层。 HBase有很多种事件可以触发观察者方法,这些事件与方法从HBase0.92版本起,都会集成在HBase API中。不过这些API可能会由于各种原因有所改动,不同版本的接口改动比较大。
RegionObserver工作原理,如图1所示。

EndPoint

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

终端的使用如下面流程所示:
定义一个新的protocol接口,必须继承CoprocessorProtocol。
实现终端接口,该实现会被导入region环境执行。
继承抽象类BaseEndpointCoprocessor。
在客户端,终端可以被两个新的HBase Client API调用。
单个region:

HTableInterface.coprocessorProxy(Class<T> protocol, byte[] row) 

regions区域:

HTableInterface.coprocessorExec(Class<T> protocol, byte[] startKey, byte[] endKey, Batch.Call<T,R> callable)

整体的EndPoint调用过程范例,如图所示:

官方给的示例程序大体流程:

对Endpoint进行设置的三个方法:
A. 启动全局aggregation,能过操纵所有的表上的数据。通过修改hbase-site.xml这个文件来实现,只需要添加如下代码:

<property><name>hbase.coprocessor.user.region.classes</name><value>org.apache.hadoop.hbase.coprocessor.RowCountEndpoint</value>
</property>

B. 启用表aggregation,只对特定的表生效。通过HBase Shell 来实现。
(1)disable指定表。

hbase> disable 'mytable'    

(2)添加aggregation 。

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

(3)重启指定表 。

hbase> enable 'mytable'

C. API调用

HTableDescriptor htd=new HTableDescriptor("testTable");
htd.setValue("CORPROCESSOR$1" , 
path.toString+"|"+RowCountEndpoint.class.getCanonicalName()+"|"+Coprocessor.Priority.USER);

其中path为jar在HDFS中的路径。

Demo1:

package Coprocessor;import java.io.IOException;
import java.util.Iterator;
import java.util.Map;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.HConnection;
import org.apache.hadoop.hbase.client.HConnectionManager;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.coprocessor.Batch;
import org.apache.hadoop.hbase.coprocessor.example.generated.ExampleProtos;
import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
import org.apache.hadoop.hbase.ipc.ServerRpcController;import com.google.protobuf.ServiceException;public class CoprocessorRowCounter 
{private String rootDir;private String zkServer;private String port;private Configuration conf; private HConnection hConn = null;private CoprocessorRowCounter(String rootDir,String zkServer,String port) throws IOException{this.rootDir = rootDir;this.zkServer = zkServer;this.port = port;conf = HBaseConfiguration.create();conf.set("hbase.rootdir", rootDir);conf.set("hbase.zookeeper.quorum", zkServer);conf.set("hbase.zookeeper.property.clientPort", port);hConn = HConnectionManager.createConnection(conf);  }public static void main(String[] args) throws ServiceException, Throwable {String rootDir = "hdfs://hadoop1:8020/hbase";String zkServer = "hadoop1";String port = "2181";CoprocessorRowCounter conn = new CoprocessorRowCounter(rootDir,zkServer,port);//Configuration conf = HBaseConfiguration.create();HTable table = new HTable(conn.conf, "students"); //发送请求final ExampleProtos.CountRequest request = ExampleProtos.CountRequest.getDefaultInstance();//回调函数 call方法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>();//实现在server端counter.getRowCount(controller, request, rpcCallback);ExampleProtos.CountResponse response = rpcCallback.get();if (controller.failedOnException()) {throw controller.getFailedOn();}//返回return (response != null && response.hasCount()) ? response.getCount() : 0;}});int sum = 0;int count = 0;/* Iterator<Long> iter = results.values().iterator();Long val = iter.next();*/for (Long  l : results.values()) {sum += l;count++;}System.out.println("row count = " + sum);System.out.println("region count = " + count);}
}

运行结果:

row count = 4
region count = 1

注意:

  1. 协处理器配置的加载顺序:先加载配置文件中定义的协处理器,后加载表描述符中的协处理器。
  2. COPROCESSOR$<number>中的number定义了加载的顺序。
  3. 协处理器配置格式

移除协处理器

Demo2:

package Coprocessor;import java.io.IOException;
import java.util.List;import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.util.Bytes;public class RegionObserver extends BaseRegionObserver{private static byte[] fixed_rowkey = Bytes.toBytes("Ivy");//preGetOp代替preGet/*public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e,Get get, List<Cell> results) throws IOException {if (Bytes.equals(get.getRow(), fixed_rowkey)) {//行键  列族 列Cell cell = new KeyValue(get.getRow(), Bytes.toBytes("time"), Bytes.toBytes("time"));results.add(cell);}}*/@Overridepublic void preGet(ObserverContext<RegionCoprocessorEnvironment> c,Get get, List<KeyValue> result) throws IOException {if (Bytes.equals(get.getRow(), fixed_rowkey)) {//行键  列族 列KeyValue kv = new KeyValue(get.getRow(), Bytes.toBytes("time"), Bytes.toBytes("time"),Bytes.toBytes(System.currentTimeMillis()));result.add(kv);}}
}

打成jar包,上传到hdfs上面。

增加协处理器

disable 'students'
alter 'students','coprocessor'=>'hdfs://nameservice1/liguodong/coprocessor.jar|Coprocessor.RegionObserver||'
enable 'students'

package HbaseAPI;import java.io.IOException;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HConnection;
import org.apache.hadoop.hbase.client.HConnectionManager;
import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.compress.Compression.Algorithm;
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
import org.apache.hadoop.hbase.util.Bytes;public class HBaseConnection {private String rootDir;private String zkServer;private String port;private Configuration conf; private HConnection hConn = null;private HBaseConnection(String rootDir,String zkServer,String port) throws IOException{this.rootDir = rootDir;this.zkServer = zkServer;this.port = port;conf = HBaseConfiguration.create();conf.set("hbase.rootdir", rootDir);conf.set("hbase.zookeeper.quorum", zkServer);conf.set("hbase.zookeeper.property.clientPort", port);hConn = HConnectionManager.createConnection(conf);  }//获取数据public Result getData(String tableName,String rowkey) throws IOException{HTableInterface table = hConn.getTable(tableName);//用来获取单个行的相关信息Get get = new Get(Bytes.toBytes(rowkey));return table.get(get);}public void format(Result result){//行键String rowkey = Bytes.toString(result.getRow());//Return an cells of a Result as an array of KeyValuesKeyValue[] kvs = result.raw();for (KeyValue kv : kvs) {//列族名String family = Bytes.toString(kv.getFamily());//列名String qualifier = Bytes.toString(kv.getQualifier());//String value = Bytes.toString(result.getValue(Bytes.toBytes(family), Bytes.toBytes(qualifier)));String value = Bytes.toString(kv.getValue());System.out.println("rowkey->"+rowkey+", family->"+family+", qualifier->"+qualifier);System.out.println("value->"+value);    }}public static void main(String[] args) throws IOException {String rootDir = "hdfs://hadoop1:8020/hbase";String zkServer = "hadoop1";String port = "2181";//初始化HBaseConnection conn = new HBaseConnection(rootDir,zkServer,port);//输出结果Result result = conn.getData("students", "Ivy");conn.format(result);result = conn.getData("students", "Tom");conn.format(result);}
}

这篇关于HBase协处理器及实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/332567

相关文章

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

mysqld_multi在Linux服务器上运行多个MySQL实例

《mysqld_multi在Linux服务器上运行多个MySQL实例》在Linux系统上使用mysqld_multi来启动和管理多个MySQL实例是一种常见的做法,这种方式允许你在同一台机器上运行多个... 目录1. 安装mysql2. 配置文件示例配置文件3. 创建数据目录4. 启动和管理实例启动所有实例

Java function函数式接口的使用方法与实例

《Javafunction函数式接口的使用方法与实例》:本文主要介绍Javafunction函数式接口的使用方法与实例,函数式接口如一支未完成的诗篇,用Lambda表达式作韵脚,将代码的机械美感... 目录引言-当代码遇见诗性一、函数式接口的生物学解构1.1 函数式接口的基因密码1.2 六大核心接口的形态学

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

MySQL的索引失效的原因实例及解决方案

《MySQL的索引失效的原因实例及解决方案》这篇文章主要讨论了MySQL索引失效的常见原因及其解决方案,它涵盖了数据类型不匹配、隐式转换、函数或表达式、范围查询、LIKE查询、OR条件、全表扫描、索引... 目录1. 数据类型不匹配2. 隐式转换3. 函数或表达式4. 范围查询之后的列5. like 查询6

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss