您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

Hbase的协处理器

2024/3/2 5:33:16发布16次查看
1.起因(why hbase coprocessor) hbase作为列族数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执行求和、计数、排序等操作。比如,在旧版本的(0.92)hbase中,统计数据表的总行数,需要使用counter方法,执行一次mapreduce job才能得到。虽
1.起因(why hbase  coprocessor)hbase作为列族数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执行求和、计数、排序等操作。比如,在旧版本的(
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添加全新的特性。终端的使用,如下面流程所示:
定义一个新的protocol接口,必须继承coprocessorprotocol.实现终端接口,该实现会被导入region环境执行。继承抽象类baseendpointcoprocessor.在客户端,终端可以被两个新的hbase client api调用 。单个region:htableinterface.coprocessorproxy(class protocol, byte[] row) 。rigons区域:htableinterface.coprocessorexec(class protocol, byte[] startkey, byte[] endkey, batch.call callable)整体的终端调用过程范例,如图2所示:
图2 终端调用过程范例
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.classesname> value>org.apache.hadoop.hbase.coprocessor.aggregateimplementationvalue> 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'
4.2统计行数代码(code snippet) import org.apache.hadoop.conf.configuration;import org.apache.hadoop.hbase.hbaseconfiguration;import org.apache.hadoop.hbase.tablename;import org.apache.hadoop.hbase.client.scan;import org.apache.hadoop.hbase.client.coprocessor.aggregationclient;import org.apache.hadoop.hbase.client.coprocessor.longcolumninterpreter;import org.apache.hadoop.hbase.coprocessor.columninterpreter;import org.apache.hadoop.hbase.util.bytes;public class myaggregationclient { private static final byte[] table_name = bytes.tobytes(bigtable1w); private static final byte[] cf = bytes.tobytes(bd); public static void main(string[] args) throws throwable { configuration customconf = new configuration(); customconf.set(hbase.zookeeper.quorum, 192.168.58.101); //提高rpc通信时长 customconf.setlong(hbase.rpc.timeout, 600000); //设置scan缓存 customconf.setlong(hbase.client.scanner.caching, 1000); configuration configuration = hbaseconfiguration.create(customconf); aggregationclient aggregationclient = new aggregationclient( configuration); scan scan = new scan(); //指定扫描列族,唯一值 scan.addfamily(cf); //long rowcount = aggregationclient.rowcount(table_name, null, scan); long rowcount = aggregationclient.rowcount(tablename.valueof(bigtable1w), new longcolumninterpreter(), scan); system.out.println(row count is + rowcount); } }
4.3 典型例子  协处理器其中的一个作用是使用observer创建二级索引。先举个实际例子:   我们要查询指定店铺指定客户购买的订单,首先有一张订单详情表,它以被处理后的订单id作为rowkey;其次有一张以客户nick为rowkey的索引表,结构如下: rowkey family dp_id+buy_nick1 tid1:null tid2:null ... dp_id+buy_nick2 tid3:null ... 该表可以通过coprocessor来构建,实例代码: 
[html] view plain copy public class testcoprocessor extends baseregionobserver {       @override        public void preput(final observercontextregioncoprocessorenvironment> e,        final put put, final waledit edit, final boolean writetowal)        throws ioexception {            configuration conf = new configuration();            htable table = new htable(conf, index_table);            listkeyvalue> kv = put.get(data.getbytes(), name.getbytes());            iteratorkeyvalue> kvitor = kv.iterator();            while (kvitor.hasnext()) {                keyvalue tmp = kvitor.next();                put indexput = new put(tmp.getvalue());                indexput.add(index.getbytes(), tmp.getrow(), bytes.tobytes(system.currenttimemillis()));                table.put(indexput);            }            table.close();        }   }   即继承baseregionobserver类,实现preput方法,在插入订单详情表之前,向索引表插入索引数据。 
4.4索引表的使用 先在索引表get索引表,获取tids,然后根据tids查询订单详情表。 当有多个查询条件(多张索引表),根据逻辑运算符(and 、or)确定tids。 4.5使用时注意 1.索引表是一张普通的hbase表,为安全考虑需要开启hlog记录日志。 2.索引表的rowkey最好是不可变量,避免索引表中产生大量的脏数据。 3.如上例子,column是横向扩展的(宽表),rowkey设计除了要考虑region均衡,也要考虑column数量,即表不要太宽。建议不超过3位数。 4.如上代码,一个put操作其实是先后向两张表put数据,为保证一致性,需要考虑异常处理,建议异常时重试。 4.6效率情况 
put操作效率不高,如上代码,每插入一条数据需要创建一个新的索引表连接(可以使用htablepool优化),向索引表插入数据。即耗时是双倍的,对hbase的集群的压力也是双倍的。当索引表有多个时,压力会更大。 查询效率比filter高,毫秒级别,因为都是rowkey的查询。 如上是估计的效率情况,需要根据实际业务场景和集群情况而定,最好做预先测试。
4.7coprocessor二级索引方案优劣 优点:在put压力不大、索引region均衡的情况下,查询很快。 缺点:业务性比较强,若有多个字段的查询,需要建立多张索引表,需要保证多张表的数据一致性,且在hbase的存储和内存上都会有更高的要求
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product