http://note.youdao.com/share/?id=d2163a7ba8ec1ec58e64683a961c5121&type=notephp
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方法返回給客戶端。