Hbase自0.92之后开始支持Coprocessor(协处理器),旨在使用户可以将自己的代码放在regionserver上来运行,即将计算程序移动到数据所在的位置进行运算。这一点与MapReduce的思想一致。Hbase的Coprocess分为observer和endpoint两大类。简单说,observer相当于关系型数据库中的触发器,而endpoint则相当于关系型数据库中的存储过程。关于HBase Coprocessor的介绍网上有很多的文档,由于我也是刚刚学习,从很多好人贡献的文档上了解了很多。
这里记录一下自己在一个完全分布式系统上部署自定义的Coprocessor的过程,本文会介绍两种部署的方法:一种是在hbase-site.xml中配置;第二种是使用表描述符来配置(alter);前者会被所有的表的所有的region加载,而后者只会对指定的表的所有region加载。本文会结合自己的实验过程指出哪些地方为易错点。
首先,还是先来看下环境:
hadoop1.updb.com 192.168.0.101 Role:master
hadoop2.updb.com 192.168.0.102 Role:regionserver
hadoop3.updb.com 192.168.0.103 Role:regionserver
hadoop4.updb.com 192.168.0.104 Role:regionserver
hadoop5.updb.com 192.168.0.105 Role:regionserver
首先编码自定义的Coprocessor,该段代码摘自《Hbase权威指南》,只是修改了package的名字:
/** * coprocessor * 当用户在使用get命令从表中取特定的row时,就会触发这个自定义的observer coprocessor * 触发条件是用户使用get指定的rowkey与程序中指定的FIXED_ROW一致为@@@GETTIME@@@时 * 触发后的操作是程序会在服务端生成一个keyvalue实例,并将这个实例返回给客户端。这个kv实例是以 * @@@GETTIME@@@为rowkey,列族和列标识符均为@@@GETTIME@@@,列值为服务器端的时间 */ package org.apache.hbase.kora.coprocessor; import java.io.IOException; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.regionserver.HRegion; import org.apache.hadoop.hbase.util.Bytes; public class RegionObserverExample extends BaseRegionObserver { public static final Log LOG = LogFactory.getLog(HRegion.class); public static final byte[] FIXED_ROW = Bytes.toBytes("@@@GETTIME@@@"); @Override public void preGet(ObserverContext<RegionCoprocessorEnvironment> c, Get get, List<KeyValue> result) throws IOException { LOG.debug("Got preGet for row: " + Bytes.toStringBinary(get.getRow())); if (Bytes.equals(get.getRow(), FIXED_ROW)) { KeyValue kv = new KeyValue(get.getRow(), FIXED_ROW, FIXED_ROW, Bytes.toBytes(System.currentTimeMillis())); LOG.debug("Had a match, adding fake kv: " + kv); result.add(kv); } } }
编码完成后需要将该类编译并打成jar包,类名上右击--Export,弹出如下窗口
选择JAR file,然后Next,出现如下窗口
指定jar文件的保存路径,然后finish,就完成了RegionObserverExample类的编译和打包,接下来就需要将打好的jar文件使用ftp的方式上传到hbase集群的master服务器上,这里为hadoop1。
## 已经上传到hadoop1上 [grid@hadoop1 ~]$ ls /var/ftp/pub/RegionObserverExample.jar /var/ftp/pub/RegionObserverExample.jar ## 由于是完全分布式系统,为了方便管理,我们将jar包存放到hadoop hdfs的根目录下的jars目录下 [grid@hadoop1 ~]$ hdfs dfs -put /var/ftp/pub/RegionObserverExample.jar /jars ## OK,验证已经上传成功 [grid@hadoop1 ~]$ hdfs dfs -ls /jars Found 1 items -rw-r--r-- 4 grid supergroup 3884 2014-11-15 04:46 /jars/RegionObserverExample.jar
然后需要将打好的jar包放到hbase安装目录下的lib目录下,并修改hbase-site.xml配置文件
## cp jar包到hbase安装目录下的lib目录,所有节点上都做这样的操作 [grid@hadoop1 ~]$ cp /var/ftp/pub/RegionObserverExample.jar /opt/hbase-0.98.4-hadoop2/lib/ ## 然后修改hbase-site.xml文件,添加一个选项 <!-- 这里要注意value中一定要写完整的类名(即把包名写全),否则报ClassNotFound错 --> <property> <name>hbase.coprocessor.region.classes</name> <value>org.apache.hbase.kora.coprocessor.RegionObserverExample</value> </property>
在master上修改配置文件完成之后,将修改后的文件scp到其他个regionserver上,然后重启hbase使配置生效。重启之后来看是否能够正确的触发
## 使用get命令从kora表中取rowkey为@@@GETTIME@@@的行 hbase(main):014:0> get 'kora', '@@@GETTIME@@@' COLUMN CELL @@@GETTIME@@@:@@@GETTIM timestamp=9223372036854775807, value=\x00\x00\x01I\xB0@\xA0\xE0 E@@@ 1 row(s) in 0.0420 seconds ## 将列值转化为uninx 时间 hbase(main):015:0> Time.at(Bytes.toLong("\x00\x00\x01I\xB0\x0BZ\x0B".to_java_bytes)/ 1000) => Sat Nov 15 04:42:54 +0800 2014 ## 从上面的测试中看出,我们自定义的Coprocessor已经成功的部署到分布式系统中了。
需要留意的是在hbase-site.xml配置的Coprocessor默认是会被每张表的每个region加载。如果只想要某个表使用这个observer coprocessor,就需要使用表描述符的加载方式,这种方式同样的需要拷贝jar包到hbase安装目录下的lib目录中去,与上面不同的是不用在hbase-site.xml中设置Coprocessor,而是使用alter来把Coprocessor与表绑定。如下
## cp jar包到hbase安装目录下的lib目录,所有节点上都做这样的操作 [grid@hadoop1 ~]$ cp /var/ftp/pub/RegionObserverExample.jar /opt/hbase-0.98.4-hadoop2/lib/ ## 注释掉hbase-site.xml中的Coprocessor的配置 [grid@hadoop1 ~]$ tail -7 /opt/hbase-0.98.4-hadoop2/conf/hbase-site.xml <!-- <property> <name>hbase.coprocessor.region.classes</name> <value>org.apache.hbase.kora.coprocessor.RegionObserverExample</value> </property> --> </configuration>
在hbase shell中使用alter命令来为kora表来设定Coprocessor
## 格式:[coprocessor jar file location] | class name | [priority] | [arguments] ## 列子:hbase> alter 't1', ## 'coprocessor'=>'hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2' ## 由于一定设置了classpath,所以可以忽略jar file location,如下: hbase(main):101:0> alter 'kora', hbase(main):102:0* 'coprocessor' => '|org.apache.hbase.kora.coprocessor.RegionObserverExample|' Updating all regions with the new schema... 0/1 regions updated. 1/1 regions updated. Done. 0 row(s) in 2.5670 seconds
设置成功,decribe下表
hbase(main):103:0> describe 'kora' DESCRIPTION ENABLED 'kora', {TABLE_ATTRIBUTES => {coprocessor$1 => '|org.apache.hbase.kora.coprocessor.RegionObserverExa true mple|'}, {NAME => 'project', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_ CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'} 1 row(s) in 0.0580 seconds
ok,已经设置成功,下面来测试一下
## kora表,指定了Coprocessor hbase(main):104:0> get 'kora', '@@@GETTIME@@@' COLUMN CELL @@@GETTIME@@@:@@@GETTIME@@@ timestamp=9223372036854775807, value=\x00\x00\x01I\xB0\x985W 1 row(s) in 0.0360 seconds ## testtable,没有指定Coprocessor hbase(main):105:0> get 'testtable', '@@@GETTIME@@@' COLUMN CELL 0 row(s) in 0.0180 seconds
需要注意的是,Coprocessor的优先级有SYSTEM和USER两种,SYSTEM优先于USER加载。使用表描述符设置Coprocessor时,不要设置优先级这一项,否则无法成功触发,如
'coprocessor' => '|org.apache.hbase.kora.coprocessor.RegionObserverExample|USER|'
虽然也能成功设置Coprocessor,但是测试时是无法触发的,在上述环境中亲自测试过的,而且hbase帮助文档中优先级这个项用户不是必输项,只有类名是必输项。我们可以根据自己的需求来选择使用哪种方式来配置自己的Coprocessor。
本文出自 “勇敢向前,坚决向左” 博客,转载请与作者联系!