- 协处理器接口:
RegionObserver:用于处理数据修改事件,与表的region相关联。
MasterObserver:用作管理或者是DDL类型操作,属于集群级别事件。
WALObserver:提供控制WAL的钩子函数。 - 协处理器的加载③④⑤⑥
①.从配置文件加载:
<property>
<name>hbase.coprocessor.region.classes</name>
<value>com.ronnie.coprocess.RegionCoprocess,com.ronnie.hbase..</value>
</property>
<property>
<name>hbase.coprocessor.master.classes</name>
<value>com.ronnie.hbase.MasterCoprocessor</value>
</property>
<property>
<name>hbase.coprocessor.wal.classes</name>
<value>com.ronnie.hbase.WALCoprocessor</value>
</property>
②指定特定的表:
public static void main(String[] args) throws IOException {
/*
* 该方法只针对特定的表,对特定表对应的region才回去加载协处理器类。其他的都不会加载。
*/
Configuration conf = HBaseConfiguration.create();
Connection connection = ConnectionFactory.createConnection(conf);
FileSystem fileSystem = FileSystem.get(conf);
//会到该路径去找到对应的协处理类。
Path path = new Path(fileSystem.getUri() + Path.SEPARATOR + "test.jar");
HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("testTable"));
desc.addFamily(new HColumnDescriptor(Bytes.toBytes("faimly-1")));
/*
* $1表示加载协处理器的顺序。(当是user的时候)
*/
desc.setValue("COPROCESSOR$1", path.toString() +
"|" + RegionObserver.class.getCanonicalName() +
"|" + Coprocessor.PRIORITY_USER);
Admin admin = connection.getAdmin();
admin.createTable(desc);
}
3.Observer
/**
* 只作用在region服务器上
*/
public class RegionObserver extends BaseRegionObserver {
private static final byte[] FIX_ROW = "daxian".getBytes();
@Override
public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e,
Get get, List<Cell> results) throws IOException {
if(Bytes.equals(get.getRow(), FIX_ROW)){
Cell ce = CellUtil.createCell(get.getRow(), FIX_ROW, FIX_ROW, System.currentTimeMillis(), (byte)3, Bytes.toBytes(""));
KeyValue kv = KeyValueUtil.copyToNewKeyValue(ce);
kv.getValueArray();
Cell cell = new KeyValue(get.getRow(),//row
FIX_ROW,//family
FIX_ROW, //column
Bytes.toBytes(System.currentTimeMillis()));//value
results.add(cell);
e.bypass();//则会将以前的数据忽略掉,而是使用用户自定义的数据
e.complete();//告诉框架后续的操作可以被跳过,剩下没有被调用的协处理器也将被跳过,即表示该协处理器为最后一个处理器。
}
}
}
/**
* 表示在创建表之后创建对应的目录。
*/
public class MasterObserver extends BaseMasterObserver{
@Override
public void postCreateTable(
ObserverContext<MasterCoprocessorEnvironment> ctx,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
//得到创建的表的名字:两种方式均可得到创建表的名字
String tableName = regions[0].getTable().getNameAsString();
String tn = desc.getNameAsString();
//获得master对应的文件系统,getMasterFileSystem:用于用户创建表或日志文件目录等操作
FileSystem fileSystem = ctx.getEnvironment().getMasterServices().getMasterFileSystem().getFileSystem();
Path path1 = new Path(tableName + "_regions");
Path path2 = new Path(tn + "_desc");
fileSystem.mkdirs(path1);
fileSystem.mkdirs(path2);
}
}
4.endpoint、
在0.98 的版本之后,采用的google 的protobuf处理RPC调用。
message SearchRequest{
required string query = 1;//required表示必须出现,string类型的默认值为空字符串
option int32 page_number = 2;//option表示可以出现一次或是0次。int默认值为0
option int32 result_per_page = 3;
enum Corpus{
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
option Corpus corpus = 4 [default = UNIVERSAL];//对于enum,默认值为列表的第一个元素
repeated string name = 5;//repeat表示可以重复出现多次。
}
message SearchResponse{
repeated Result result = 1;//类型也可以是自定义的类型。
}
message Result{
required string url = 1;
optional string title = 2;
repeated string snippet = 3;
}
----------------------------------------------------------
message SearchResponse{
message Result{
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}
message SomeOtherMessage{
optional SearchResponse.Result result = 1;//也支持这样进行调用。
}
-----------------------------------
Group:
message SearchResponse{
repeated group Result = 1 {
required string url = 2;
optional string title = 3;
repeated string snippets = 4;
}
}
----------------------------------
有些option必须写在message外面:
option java_package = "";//对应java的包名。
option java_outer_classname = "";//对应java的类名
option optimize_for = "";//
/**
* optimize_for可以取值为:SPEED\CODE_SIZE\LITE_RUNTIME
* SPEED :默认
*
*/
option cc_generic_services|java_generic_services|python_generic_services
============================endpoint========================================
protoc -I=. --java_out=../src/main/java ./sum.proto #-I后面跟的是.proto所在的目录,--java_out后面的路径一般设为
protobuf中java/src/main/java
然后对项目进行编译 : mvn clean compile
打包为jar包:mvn install 得到对应的protobuf-java-versionid.jar
最后将jar包放到hbase的lib目录下,如果你的客户端不是region服务器,可将该包拷贝下来进行使用。
写客户端的endpoint代码:需要继承由protoc 生成的Service代码,然后进行编写。
----------------------------------------------------------------------------
public class RowCountProtocol extends Sum.SumService implements Coprocessor,CoprocessorService {
private RegionCoprocessorEnvironment environment;
/**
* 从SumService中继承而来。
*/
@Override
public void getSum(RpcController controller, SumRequest request,
RpcCallback<SumResponse> done) {
Scan scan = new Scan();
//定义过的family和column
scan.addFamily(Bytes.toBytes(request.getFamily()));
scan.addColumn(Bytes.toBytes(request.getFamily()), Bytes.toBytes(request.getColumn()));
SumResponse response = null;
try(InternalScanner scanner = environment.getRegion().getScanner(scan)) {
List<Cell> results = new ArrayList<Cell>();
boolean hasMore = false;
long sum = 0l;
do{
hasMore = scanner.next(results);
for(Cell cell : results){
sum += Bytes.toLong(CellUtil.cloneValue(cell));
}
results.clear();
}while(hasMore);
response = SumResponse.newBuilder().setSum((int) sum).build();
} catch (IOException ioe) {
ResponseConverter.setControllerException(controller, ioe);
}
done.run(response);
}
@Override
public Service getService() {
return this;
}
@Override
public void start(CoprocessorEnvironment env) throws IOException {
if(env instanceof RegionCoprocessorEnvironment){
environment = (RegionCoprocessorEnvironment) env;
}else{
throw new CoprocessorException("must loaded a table region");
}
}
@Override
public void stop(CoprocessorEnvironment env) throws IOException {
}
}