hbase 源代码分析(16)协处理器 rpc endpoint 流程

今天来分析一下协处理处理过程。

参考RPC:http://blog.csdn.net/chenfenggang/article/details/75268998
首先必须了解什么是RPC,以及一般的RPC的几个关键点。
1)服务端接口,
2)服务端实现类
3)服务端进程
4)客户端stub (包括连接的Socket)

这里将分析客户端是怎么找到服务端的接口的。包括怎么获取socket(stub)的

这次的案例 RowCountEndpoint 这个是官方给案例在example 下面。
   
   
  1. public class RowCountEndpoint extends ExampleProtos.RowCountService
  2. implements Coprocessor, CoprocessorService {
  3. private RegionCoprocessorEnvironment env;
  4. public RowCountEndpoint() {
  5. }
  6. @Override
  7. public Service getService() {
  8. return this;
  9. }
  10. @Override
  11. public void getRowCount(RpcController controller, ExampleProtos.CountRequest request,
  12. RpcCallback<ExampleProtos.CountResponse> done) {
  13. Scan scan = new Scan();
  14. scan.setFilter(new FirstKeyOnlyFilter());
  15. ExampleProtos.CountResponse response = null;
  16. InternalScanner scanner = null;
  17. try {
  18. scanner = env.getRegion().getScanner(scan);
  19. List<Cell> results = new ArrayList<Cell>();
  20. boolean hasMore = false;
  21. byte[] lastRow = null;
  22. long count = 0;
  23. do {
  24. hasMore = scanner.next(results);
  25. for (Cell kv : results) {
  26. byte[] currentRow = CellUtil.cloneRow(kv);
  27. if (lastRow == null || !Bytes.equals(lastRow, currentRow)) {
  28. lastRow = currentRow;
  29. count++;
  30. }
  31. }
  32. results.clear();
  33. } while (hasMore);
  34. response = ExampleProtos.CountResponse.newBuilder()
  35. .setCount(count).build();
  36. } catch (IOException ioe) {
  37. ResponseConverter.setControllerException(controller, ioe);
  38. } finally {
  39. if (scanner != null) {
  40. try {
  41. scanner.close();
  42. } catch (IOException ignored) {}
  43. }
  44. }
  45. done.run(response);
  46. }
  47. @Override
  48. public void start(CoprocessorEnvironment env) throws IOException {
  49. if (env instanceof RegionCoprocessorEnvironment) {
  50. this.env = (RegionCoprocessorEnvironment)env;
  51. } else {
  52. throw new CoprocessorException("Must be loaded on a table region!");
  53. }
  54. }
  55. @Override
  56. public void stop(CoprocessorEnvironment env) throws IOException {
  57. // nothing to do
  58. }
  59. }
protos// ExampleProtos.proto
   
   
  1. package hbase.pb;
  2. option java_package = "org.apache.hadoop.hbase.coprocessor.example.generated";
  3. option java_outer_classname = "ExampleProtos";
  4. option java_generic_services = true;
  5. option java_generate_equals_and_hash = true;
  6. option optimize_for = SPEED;
  7. message CountRequest {
  8. }
  9. message CountResponse {
  10. required int64 count = 1 [default = 0];
  11. }
  12. service RowCountService {
  13. rpc getRowCount(CountRequest)
  14. returns (CountResponse);
  15. }
自己写的简单客户端代码
   
   
  1. public static void main(String[] args) throws Throwable {
  2. Configuration configuration = HBaseConfiguration.create();
  3. Connection connection = ConnectionFactory.createConnection(configuration);
  4. Table table = connection.getTable(TableName.META_TABLE_NAME);
  5. //这里定义了一个callable 将在下面的方法中使用,ExampleProtos.RowCountService.class提供的是接口
  6. table.coprocessorService(ExampleProtos.RowCountService.class, null, null, new Batch.Call<RowCountEndpoint, Object>() {
  7. @Override
  8. public Object call(ExampleProtos.RowCountService instance) throws IOException {
  9. RpcController controller= new ServerRpcController();
  10. ExampleProtos.CountRequest request = ExampleProtos.CountRequest.newBuilder().build() ;
  11. BlockingRpcCallback<org.apache.hadoop.hbase.coprocessor.example.generated.ExampleProtos.CountResponse> done=
  12. new BlockingRpcCallback();
  13. instance.getKeyValueCount(controller,request,done);
  14. return done.get().getCount();
  15. }
  16. });
  17. }

coprocessorService的里面主要调用Htable里的这个方法
   
   
  1. public <T extends Service, R> void coprocessorService(final Class<T> service,
  2. byte[] startKey, byte[] endKey, final Batch.Call<T,R> callable,
  3. final Batch.Callback<R> callback) throws ServiceException, Throwable {
  4. // 获取keys的范围,根据keys的个数可以获取的region的个数。将向每一个region发送一个请求,分别求count
  5. List<byte[]> keys = getStartKeysInRange(startKey, endKey);
  6. Map<byte[],Future<R>> futures =
  7. new TreeMap<byte[],Future<R>>(Bytes.BYTES_COMPARATOR);
  8. for (final byte[] r : keys) {
  9. //这个定义了一个channel ,里面包含connection 和rpcFactory ,注意这个channel的实现类。
  10. final RegionCoprocessorRpcChannel channel =
  11. new RegionCoprocessorRpcChannel(connection, tableName, r);
  12. //submit 提交会掉用call 方法
  13. Future<R> future = pool.submit(
  14. new Callable<R>() {
  15. @Override
  16. public R call() throws Exception {
  17. //这里new 了一个instance 为 ExampleProtos.proto 定义的服务,里面有个“newStub”参数。将调用proto 生成的代码。
  18. //如下面方法
  19. T instance = ProtobufUtil.newServiceStub(service, channel);
  20. //这里是调用上面的callable的call方法 //instance 即为RowCountEndpoint,上一个方法中使用
  21. //了RowCountEndpoint.getKeyValueCount
  22. R result = callable.call(instance);
  23. byte[] region = channel.getLastRegion();
  24. if (callback != null) {
  25. callback.update(region, r, result);
  26. }
  27. return result;
  28. }
  29. });
  30. futures.put(r, future);
  31. }
  32. for (Map.Entry<byte[],Future<R>> e : futures.entrySet()) {
  33. try {
  34. e.getValue().get();
  35. }
  36. }
上面的 ProtobufUtil . newServiceStub ( service , channel ); 会调用这个这样会将包含connection等数据给 instance的 stub
   
   
  1. public static Stub newStub(
  2. com.google.protobuf.RpcChannel channel) {
  3. return new Stub(channel);
  4. }
很多时候以为这样就已经可以服务端的接口了,其实不是的应该是调用下面的方法,是客户端的实现
   
   
  1. public void getKeyValueCount(
  2. com.google.protobuf.RpcController controller,
  3. CountRequest request,
  4. com.google.protobuf.RpcCallback<CountResponse> done) {
  5. channel.callMethod(
  6. getDescriptor().getMethods().get(1),
  7. controller,
  8. request,
  9. CountResponse.getDefaultInstance(),
  10. com.google.protobuf.RpcUtil.generalizeCallback(
  11. done,
  12. CountResponse.class,
  13. CountResponse.getDefaultInstance()));
  14. }
然后调用这个
    
    
  1. public void callMethod(Descriptors.MethodDescriptor method,
  2. RpcController controller,
  3. Message request, Message responsePrototype,
  4. RpcCallback<Message> callback) {
  5. response = callExecService(controller, method, request, responsePrototype);
  6. }
根据上面channel的实现类 RegionCoprocessorRpcChannel
     
     
  1. @Override
  2. protected Message callExecService(RpcController controller,
  3. Descriptors.MethodDescriptor method, Message request, Message responsePrototype)
  4. throws IOException {
  5. //省略很多
  6. CoprocessorServiceResponse result = rpcCallerFactory.<CoprocessorServiceResponse> newCaller()
  7. .callWithRetries(callable, operationTimeout);
  8. //省略很多
  9. }
如果看过的代码关于第五章 regionLocator 获取region过程 详解就知道已经出来了。
callWithRetries的
     
     
  1. callable.prepare(tries != 0); // if called with false, check table status on ZK
  2. interceptor.intercept(context.prepare(callable, tries));
  3. return callable.call(getTimeout(callTimeout));
     
     
  1. /准备阶段设置信息。
  2. setStub(cConnection.getClient(dest));
//call阶段调用
     
     
  1. ClientProtos.GetResponse response = getStub().get(controller, request);


后面一大堆的问题就不再讨论了。基本可以说结束


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值