协处理器
hbase作为数据库最经常被人诟病的特性包括:
无法轻易建立“二级索引”,难以求和、计数、排序等操作
比如,在旧版本的(<0.92)Hbase中,统计数据表的行数,需要使用Counter方法,执行一次MapReduce Job 才能得到。虽然Hbase在数据存储层中集成了MapReduce,能够有效用于数据表的分布式计算
然而在很多情况下,做一些简单的相加或者聚合计算的时候,如果直接将计算过程放置在Server端,能够减少通讯开销,从而获得很好的性能提升。于是,Hbase在0.92之后引入了协处理器,实现一些激动人心的新特性:能够轻易建立二级索引、复杂过滤器以及访问控制等
Hbase协处理器的灵感来自于Jeff Dean 09年的演讲。它根据该演讲实现了类似bigtable的协处理器,包括一下特性:
1) 每个表服务器的任意子表都可以运行代码
2) 客户端的高层调用接口(客户端能够直接访问数据表的行地址,多行读写会自动分片成多个RPC调用)
3) 提供一个非常灵活、可用于建立分布式服务的数据模型
4) 能够自动化拓展、负载均衡、应用请求路由
Hbase的协处理器灵感来自bigtable。但是实现细节不尽相同。Hbase建立了一个框架,它为用户提供类库和运行时环境,使得他们的代码能够在Hbase region server 和 master 上处理
协处理器分为两种类型,系统协处理器可以全局导入regionserver上的所有数据表,表写吹即是用户可以指定一张表使用协处理器
协处理器框架为了更好支持其行为的灵活性,提供了两个不同方面的插件。一个是观察者(Observer),类似于关系数据库的触发器。另一个是终端(endpoint),动态的终端有点像存储过程
Observer
观察者的设计意图是允许用户通过插入代码来重载处理器框架的upcall方法,而具体的时间出发的callback方法有Hbase 的核心代码来执行。协处理器框架处理所有的callbback
调用细节,协处理器资深只需要插入添加或者改变的功能
以Hbase0.92为例,它提供了三种观察者接口:
RegionObserver:提供客户端的数据操纵时间钩子:Get、Put、Delete、Scan等。
WALObserver:提供WAL相关操作的钩子
MasterObserver:提供DDL类型的操作钩子。如创建、删除、修改数据表等。
这些接口可以同时使用在同一个地方,按照不同优先级顺序执行,用户可以任意基于协处理器实现复杂的Hbase功能层。Hbase有很多时间可以触发观察者方法,这些时间与方法从Hbase0.92版本起,都会集成在Hbase API中。不过这些API可能会由于各种原因有所改动,不同版本的接口改动比较大
Observer模型
EndPonit
终端是动态RPC插件的接口,它的实现代码被安装在服务器端,从而能够通过Hbase RPC唤醒。客户端类库提供了非常方便的方法来调用这些动态接口,他们可以在任意时候调用一个终端,他们的实现代码会被目标region远程执行,结果会返回到终端。用户可以结合使用这些强大的插件接口,为Hbase添加全新的特性。终端的使用,如下面的流程所示:
定义一个新的protocol接口,必须继承CoprocessorProtocol
实现终端接口,该实现会被导入region环境执行。
继承抽象类,BaseEndpointCoprocessor
在客户端,终端可以被两个新的Hbase Client API 调用。单个region:
HTableInterface.coprocessorProxy(Class protocol,byte[] row).regions区域:HTableInterface.coprocessorExec(Class protocol,byte [] startKey,byte[] endkey,Batch.Call callable)
有三个方法对EndPoint进行设置:
A.启动全局aggregation,能通过操纵所有表上的数据。通过修改hbase-site.xml这个文件来实现,只需要添加如下代码
hbase.coprocessor.user.region.classes
org.apache.hadoop.hbase.coprocessor.RowCountEndpoint
B.启用表aggregation,只对特定的表生效,通过Hbase Shell来实现.
(1)disable指定表。hbase>disable 'mytable'
(2)添加aggregation hbase > alter 'mytable',METHOD=>'table_att','coprocessor'=>'|org.apache.hadoop.hbase.coprocessor.RowCountEndponit||'
(3)重启指定表hbase>enable 'mytable'
C.API调用
HTableDescriptor htd = new HTableDescriptor("testTable");
htd.setValue("CORPROCESSOR$1",path.tiString+"|"+RowCountEndpoint.class.getCanonicalName()+"|"+Coprocessor.Priority.USER);