http://note.youdao.com/share/?id=d2163a7ba8ec1ec58e64683a961c5121&type=note
RPC是OB一个比较重要的各个组件间进行通信的实现机制。最近在看clog的代码,就顺着ObCLogRpc这个类,简单总结下OB进行RPC的几种写法,主要偏重于写代码和理解已有代码,不涉及到底层的RPC实现机制。
曲山的
OB代码导读 5.3.2节客户端部分介绍了ObRpcStub,建议先行阅读。
后边是当前OB实现RPC的几种典型写法:
客户端
ObCLogRpc、ObUpsRpcStub和ObRootRpcStub都继承自common::ObCommonRpcStub,common::ObCommonRpcStub提供一些基础的RPC实现,其继承自ObGeneralRpcStub,ObGeneralRpcStub继承自ObRpcStub,后者封装了RPC的底层实现,包括ObClientManager的一个指针类型成员rpc_frame_。
客户端实现rpc的几种典型写法如下:
1)rpc_frame_ -> send_request
典型实现参考ObCommonRpcStub :: send_log,是一个同步调用方式。
2)rpc_frame_ -> post_request
典型实现参考ObCLogRpc::post_log,此实现是一个异步调用方式,需要在post_request中指明接收到响应后回调使用的handler;
3)调用send_*_return_*函数,是个同步调用方式,具体可参见OB代码导读相关章节,举例如下:
1 int ObCommonRpcStub :: renew_lease(const common::ObServer& master, const common::ObServer& slave_addr, const in t64_t timeout_us) 2 { 3 return send_1_return_0(master, timeout_us, OB_RENEW_LEASE_REQUEST, DEFAULT_VERSION, slave_addr); 4 }
4)调用send_param_*/deserialize_result_*两个配对的宏,具体实现可参考ObGeneralRpcStub::register_server,也是一个同步调用方式。
其实后两者就是调用1)来完成的,这些宏会进行展开,直接传递基础数据类型或是调用输出输出参数的serialize/deserialize方法进行序列化、反序列化后传递。
服务端
服务端的调用方式都是统一的。每个RPC调用都对应一个packet_code,在server的init_func_array函数中,使用宏REGISTER_HANDLE_FUNC注册特定类型的包(也即特定类型的RPC接口)的处理函数,如上文列出的ObCommonRpcStub :: renew_lease宏,其注册方式即为在ObRootWorker类的init_func_array函数中调用:
REGISTER_HANDLE_FUNC(OB_RENEW_LEASE_REQUEST, &ObRootWorker::rt_renew_lease);
然后在server的handler_packet中写上此类型包是由IO线程直接处理还是交给特定的worker线程处理。
所有注册的处理函数接口都是一致的,接受的都是ObRequestContext& context类型的参数,表示网络包。
收到包后如何处理可以参见ObRootWorker::rt_renew_lease,无非就是从网络包中反序列化输入参数,根据参数调用业务逻辑进行处理,然后将结果打包使用send_response方法返回给客户端。