sofa-pbrpc高級用法

sofa-pbrpc高級用法

輸入圖片說明

sofa-pbrpc開源地址: https://github.com/baidu/sofa-pbrpcpython

sofa-pbrpc高級用法包括:c++

  • 超時控制
  • 壓縮控制
  • 帶寬限制
  • 日誌打印
  • RpcController使用
  • RPC失敗處理
  • Server/Client配置參數
  • 多Server負載均衡與容錯
  • 輔助開發工具類
  • Mock測試
  • sofa-pbrpc-client工具
  • 統計與監控
  • HTTP支持
  • Web監控

超時控制

sofa-pbrpc-clienta-pbrpc支持三個級別的超時控制,按照生效的優先級由高到低依次爲:git

  • Request超時:在RpcController中使用SetTimeout()函數設置超時時間(毫秒),該超時只對本次請求有效;若是不設置,則使用「Method超時」或者「Service超時」;
  • Method超時:在proto文件中指定method的超時時間(毫秒),該超時對該方法的全部請求有效;若是不設置,則使用Service超時;
  • Service超時:在proto文件中指定service的超時時間(毫秒),該超時對該服務的全部方法的全部請求都有效;若是不設置,則使用默認值(10000毫秒)。

在proto文件中指定「method超時」和「Service超時」的樣例以下:github

import "sofa/pbrpc/rpc_option.proto";

package sofa.pbrpc.test;

option cc_generic_services = true;

message SleepRequest {
        required int32 sleep_time = 1; // in seconds
}

message SleepResponse {
        required string message = 1;
}

service SleepServer {
        // The service timeout is 2 seconds.
        option (sofa.pbrpc.service_timeout) = 2000;
        
        rpc SleepWithServiceTimeout(SleepRequest) returns(SleepResponse);
        
        // The method timeout is 4 seconds.
        rpc SleepWithMethodTimeout(SleepRequest) returns(SleepResponse) {
                option (sofa.pbrpc.method_timeout) = 4000;
        }
}

注意:shell

若是在proto中指定超時,須要import "sofa/pbrpc/rpc_option.proto",而且編譯proto文件時還須要添加protobuf頭文件路徑到proto_path中,具體可參考樣例「sample/timeout_sample」;json

RpcController中設置超時時間的接口以下:網絡

void SetTimeout(int64 timeout_in_ms);

壓縮控制

sofa-pbrpc支持兩個級別的數據壓縮控制,按照生效優先級由高到低依次爲:app

  • Request壓縮控制:在RpcController中使用SetRequestCompressType()和SetResponseCompressType()函數設置請求和回覆的數據壓縮類型,該設置只對本次請求有效;若是不設置,則使用「Method壓縮控制」;
  • Method壓縮控制:在proto文件中使用擴展option來指定method的Request或者Response的壓縮類型,該超時對該方法的全部請求有效;若是不設置,則使用默認值(不壓縮);

目前支持的壓縮類型包括:負載均衡

  • None
  • Gzip
  • Zlib
  • Snappy
  • LZ4

在proto文件中指定壓縮類型的樣例以下:curl

import "sofa/pbrpc/rpc_option.proto";

package sofa.pbrpc.test;

option cc_generic_services = true;

message EchoRequest {
        required string message = 1;
}

message EchoResponse {
        required string message = 1;
}

service EchoServer {
        rpc Echo(EchoRequest) returns(EchoResponse) {
                option (sofa.pbrpc.request_compress_type) = CompressTypeGzip;
                option (sofa.pbrpc.response_compress_type) = CompressTypeGzip;
        }
}

RpcController中設置壓縮類型的接口以下:

// Set compress type of the request message.
// Supported types:
//   CompressTypeNone
//   CompressTypeGzip
//   CompressTypeZlib
//   CompressTypeSnappy
//   CompressTypeLZ4
void SetRequestCompressType(CompressType compress_type);

// Set expected compress type of the response message.
// Supported types:
//   CompressTypeNone
//   CompressTypeGzip
//   CompressTypeZlib
//   CompressTypeSnappy
//   CompressTypeLZ4
void SetResponseCompressType(CompressType compress_type);

帶寬限制

sofa-pbrpc支持在RpcServer和RpcClient級別在Options中指定參數就能夠控制網絡帶寬限制,包括「出帶寬」、「入帶寬」,使流量控制對應用層透明,簡化應用層的工做。 在RpcServerOptions和RpcClientOptions中能夠分別指定Server端和Client端的最大入帶寬「max_throughput_in」和最大出帶寬「max_throughput_out」,參數用法與語義以下(默認爲-1,表示不控制):

// Network throughput limit.
// The network bandwidth is shared by all connections:
// * busy connections get more bandwidth.
// * the total bandwidth of all connections will not exceed the limit.
int max_throughput_in;     // max network in throughput for all connections.
                          // in MB/s, should >= -1, -1 means no limit, default -1.
int max_throughput_out;    // max network out throughput for all connections.
                          // in MB/s, should >= -1, -1 means no limit, default -1.

對於client端,若是限定了帶寬流量,同時請求發送速度過快,來不及發出去的請求就會積壓在Request Pending Buffer中。用戶能夠在Options指定該buffer的大小,若是buffer滿了,請求就會當即返回RPC_ERROR_SEND_BUFFER_FULL的錯誤,用戶能夠根據須要進行處理,譬如減緩發送速度。在 RpcServerOptions 和 RpcClientOptions 中均可以指定「max_pending_buffer_size」:

int max_pending_buffer_size; // max size of pending buffer for one connection.
                            // in MB, should >= 0, 0 means no buffer, default 2.

另外需注意:流量控制依據的是用戶業務數據的數據量,不包含socket底層的包頭協議數據的數據量,因此通常實際出入的數據量會比指定的略大。

如下是某實際系統中的網絡流量監控圖(帶寬限制設置爲15MB/s): 輸入圖片說明

日誌打印

sofa-pbrpc提供日誌打印函數SLOG(),將日誌打印到標準錯誤輸出,使用方式相似於printf()。

日誌級別由高到低爲:

  • FATAL
  • ERROR
  • WARNING
  • INFO
  • TRACE
  • DEBUG

經過打印級別控制日誌輸出,只會輸出高於或者等於打印級別的日誌,默認級別爲ERROR。

用戶可經過SOFA_PBRPC_SET_LOG_LEVEL()設置打印級別,譬如設置爲INFO:

SOFA_PBRPC_SET_LOG_LEVEL(INFO);

日誌使用樣例:

SLOG(ERROR, "error message: %s", message);

RpcController使用

RpcController用於控制單次請求的調用過程。

在Client端調用方法時,都須要傳入一個RpcController,其做用是:

  • 在發送請求前:控制請求的超時時間,設置Request或者Response的壓縮類型;
  • 在請求完成後:獲取本地和遠程的網絡地址,獲取(成功/失敗)狀態,若是失敗可獲取錯誤信息,檢查請求是否已發送至遠端; 在Server端服務實現中,外層也會傳入一個RpcController,其做用是:

獲取本地和遠程的網絡地址; 若是服務失敗,設置失敗標誌和錯誤信息;

使用RpcController時需注意以下幾點:

  • RpcController用於控制單次請求的調用過程,每次RPC請求都須要建立一個RpcController,在本次請求完成前,其不得釋放或者重用;
  • 請求完成後,該RpcController可使用Reset()方法恢復初始狀態以進行重用;
  • RpcController的不一樣接口有不一樣的使用時間範圍,只有在規定的時間範圍內使用,接口才能返回正確結果,不然行爲是不肯定的;

RPC失敗處理

RPC請求失敗時,RpcController的Failed()接口會返回true,同時錯誤信息能夠從ErrorCode()和ErrorText()中得到。

錯誤的緣由主要有兩大類:

  • RPC類的錯誤:包括緩衝區滿、請求沒有發出去(網絡錯誤)、請求發出去了但沒有在規定時間內獲得回覆(超時);其中網絡錯誤的緣由又有多種,譬如鏈接不上、網絡異常、請求的服務不存在等。
  • 服務執行自己的錯誤(非RPC錯誤):Server端在服務執行過程當中遇到了錯誤,使用SetFailed(reason)接口設置錯誤標識和失敗緣由;Client端的RpcController的操做以下:
    1. Failed()會返回true;
    2. ErrorCode()返回的錯誤碼是RPC_ERROR_FROM_USER(錯誤碼的更多定義可參見文件"sofa/pbrpc/rpc_error_code.h");
    3. ErrorText()返回的錯誤描述就是Server端經過SetFailed()傳入的reason;

Server/Client配置參數

RpcServerOptions

參數名 參數說明
work_thread_num 工做線程數
max_pending_buffer_size pengding buffer 大小 (MB)
max_throughput_in 最大入帶寬限制 (MB/s)
max_throughput_out 最大出帶寬限制 (MB/s)
keep_alive_time 空閒鏈接維持時間 (s)

RpcClientOptions

參數名 參數說明
work_thread_num 工做線程數
callback_thread_num 回調線程數
max_pending_buffer_size pengding buffer 大小 (MB)
max_throughput_in 最大入帶寬限制 (MB/s)
max_throughput_out 最大出帶寬限制 (MB/s)

多Server負載均衡與容錯

在建立RpcChannel時,能夠指定多個功能對等的Server地址。在調用服務時,會根據負載均衡策略選擇合適的Server發送請求,並自動進行容錯和探活處理。

RpcChannel支持點對多點的構造函數:

RpcChannel(RpcClient* rpc_client,
               const std::vector<std::string>& address_list,
               const RpcChannelOptions& options = RpcChannelOptions());

    // Create multiple server points by address provider.
    // The "rpc_client" is owned by the caller.
    // The "address_provider" is owned by the caller.
    RpcChannel(RpcClient* rpc_client,
               AddressProvider* address_provider,
               const RpcChannelOptions& options = RpcChannelOptions());

在上面第二個函數中,用戶能夠提供一個AddressProvider,支持動態增長或者刪除server地址。

負載均衡策略:

  • 對於每一個單點channel,記錄其「未完成的調用數(Not Done Calling Count)」,數量越少,表示負載越輕;
  • 下次選擇server的時候,優先選擇「未完成的調用數」最少的機器;
  • 在「未完成的調用數」相同的狀況下,優先選擇「最近最長時間未使用的機器」。

容錯與探活策略:

  • 每一個server內置一個BuiltinService,提供Health()方法用於探活;
  • 在Client端維護兩個隊列:「活動隊列」和「待探活隊列」;
  • RPC調用選擇server的時候,優先從「活動隊列」中選擇;
  • 一旦某個server的RPC調用出錯,則將其加入「待探活隊列」;
  • Client週期性地(每隔5秒)向「待探活隊列」中的機器發送探活請求,若是探活成功,則從新放回到「活動隊列」。

具體策略實現能夠參考 src/sofa/pbrpc/dynamic_rpc_channel_impl.cc

使用樣例代碼能夠參考 test/perf_test/client_multi_server.cc

AddressProvider的高級使用能夠參考 sample/multi_server_sample

輔助開發工具類

sofa-pbrpc提供了一些方便用戶開發的工具類,包括:

類別 頭文件 說明
智能指針 sofa/pbrpc/smart_ptr/smart_ptr.hpp 包括scoped_ptr,shared_ptr,weak_ptr等
原子操做 sofa/pbrpc/atomic.h 支持fetch,inc,dec,cas等
鎖操做 sofa/pbrpc/locks.h 提供了互斥鎖,自旋鎖,讀寫鎖的封裝
定時管理 sofa/pbrpc/timeout_manager.h 高效的提供了定時器功能

具體使用方法請直接參考頭文件。

Mock測試

sofa-pbrpc提供了Mock測試支持,便於用戶編寫測試程序。

Mock功能的接口主要參考"sofa/pbrpc/mock_test_helper.h"文件,使用樣例可參考"sample/mock_sample/"。

主要提供了五個宏:

// Enable or disable the mock feature.  Default disabled.
// The mock channel and mock methods will take effect iff mock enabled.
#define SOFA_PBRPC_ENABLE_MOCK() ::sofa::pbrpc::enable_mock()
#define SOFA_PBRPC_DISABLE_MOCK() ::sofa::pbrpc::disable_mock()

// If you create a channel with address of SOFA_PBRPC_MOCK_CHANNEL_ADDRESS, then the channel is a mock
// channel.  The mock channel will not create real socket connection, but just uses mock methods.
#define SOFA_PBRPC_MOCK_CHANNEL_ADDRESS "/mock/"

// All mock method implements should use this function signature.
typedef ExtClosure<void(
::google::protobuf::RpcController*,
const ::google::protobuf::Message*,
::google::protobuf::Message*,
::google::protobuf::Closure*)> MockMethodHookFunction;

// Register a mock method implement.  If mock enabled, all channels will prefer to call mock
// method first. If the corresponding mock method is not registered, then call the real method.
//
// "method_name" is the full name of the method to be mocked, should be a c-style string.
// "mock_method" is the mock method hook function, should be type of "MockMethodHookFunction*".
//
// For example:
//     MockMethodHookFunction* mock_method = sofa::pbrpc::NewPermanentExtClosure(&MockEcho);
//     SOFA_PBRPC_REGISTER_MOCK_METHOD("sofa.pbrpc.test.EchoServer.Echo", mock_method);
#define SOFA_PBRPC_REGISTER_MOCK_METHOD(method_name, mock_method) \
::sofa::pbrpc::MockTestHelper::GlobalInstance()->RegisterMockMethod(method_name, (mock_method))

// Clear all registered mock methods.  This will not delete the cleared hook functions, which
// are take ownership by user.
#define SOFA_PBRPC_CLEAR_MOCK_METHOD() \ 
::sofa::pbrpc::MockTestHelper::GlobalInstance()->ClearMockMethod()#

sofa-pbrpc-client工具

sofa-pbrpc提供了一個客戶端工具sofa-pbrpc-client(位於"bin/"),用於查詢server狀態、獲取服務列表及proto描述、獲取服務調用統計、構建文本快速發送rpc請求等。

具體功能:

  • 查詢server的健康情況(health)、配置參數(option)、負載狀況(status);
  • 查詢server對外提供的服務列表(list);
  • 獲取服務的protobuf描述信息(desc);
  • 獲取服務調用統計(stat),包括處理請求數、平均處理時間、最大處理時間等;
  • 使用text格式的請求數據,以通用的方式向server的某個method發送rpc請求調用(call); 使用幫助:
Usage: sofa-pbrpc-client <server-address> <sub-command> [args]
Available subcommands:
  * help : print this usage help.
  * health :check if the server is healthy.
  * status :get status of the server.
  * option : get RpcServerOptions of the server.
  * list : list all services provided by the server.
  * desc  <protobuf-type-name> :get descriptor of a protobuf type (service/message/enum).
  * call  <method-full-name> <request-message-text> [timeout-in-ms] : call a method using the text format of request message.The "timeout-in-ms" is optional, default is 3000 milli-seconds.
  * stat  [service-full-name] [period-in-seconds] :  get the service statistics in the latest period of seconds.The "service-full-name" is optional, default is "all".The "period-in-seconds" is optional, default is 60 seconds.

使用注意:

  • health、status、option、stat命令要求server端配置知足:disable_builtin_service = false;
  • list、desc、call命令要求server端配置知足:disable_builtin_service = false && disable_list_service = false;
  • 使用"call"命令發起rpc調用時,用戶須要按照protobuf的text格式構造Request數據,其使用google.protobuf.TextFormat進行序列化和反序列化。返回的Response數據也使用text格式打印出來。實際上,text格式也就是message->DebugString()打印出來的格式。若是字符串中包含回車,在做爲命令行參數時建議使用單引號括起來。實現上,sofa-pbrpc-client首先獲取Server端服務的描述信息,而後經過反射的方式構建請求數據,發送rpc請求。這個功能對調試頗有幫助,另外這個思路也能夠用來實現http代理。

使用樣例: 向監聽地址爲127.0.0.1:12321的server發送rpc調用"sofa.pbrpc.test.EchoServer.Echo"

$ ./sofa-pbrpc-client 127.0.0.1:12321 call sofa.pbrpc.test.EchoServer.Echo \
'message:"hello from qinzuoyan01"'
Response:
------------------------------
message: "echo message: hello from qinzuoyan01"
------------------------------

統計與監控

sofa-pbrpc支持對服務的調用進行統計,並之內建服務的方式導出統計信息。內建服務的proto定義參見"sofa/pbrpc/builtin_service.proto"。

包含以下統計項:

  • 服務在最近N秒中調用的總成功次數、總失敗次數;
  • 服務各個方法在最近N秒中調用的總成功次數、總失敗次數、成功請求的平均耗時和最大耗時、失敗請求的平均耗時和最大耗時;
  • server端最多存儲最近600秒的統計數據; 使用sofa-pbrpc-client工具,能夠很容易地獲取統計信息,譬如:
$ ./sofa-pbrpc-client 127.0.0.1:12321 stat sofa.pbrpc.test.EchoServer 10

上述命令用於獲取"sofa.pbrpc.test.EchoServer.Echo"在最近10秒的調用統計,結果樣例以下:

Response:
------------------------------
service_stats {
  service_name: "sofa.pbrpc.test.EchoServer"
  period_seconds: 10
  succeed_count: 1151699
  failed_count: 0
  method_stats {
    method_name: "sofa.pbrpc.test.EchoServer.Echo"
    succeed_count: 1151699
    succeed_avg_time_us: 0.98021704
    succeed_max_time_us: 1108
    failed_count: 0
    failed_avg_time_us: 0
    failed_max_time_us: 0
  }
}
------------------------------

除此以外,內建服務還提供了一些監控server狀態的接口。sofa-pbrpc-client工具也提供了這些子命令:

  • 使用"health"子命令檢查server是否存在;
  • 使用"status"子命令查看server的一些狀態信息,包括鏈接數、服務數、以及Pending Buffer的一些信息;
  • 使用"option"子命令查看server當前的配置參數;
  • 使用"list"子命令查看server註冊了哪些服務;
  • 使用"desc"子命令查詢服務相關類型的proto描述;

HTTP支持

sofa-pbrpc從1.0.1開始支持HTTP方式調用服務,同時支持原生POST,GET以及擴展的POST PROTOBUF三種方式提交。另外還提供了Web監控頁面,方便開發和測試。

樣例能夠參見sample/echo/client_http.sh。

POST請求

curl -d '{"message":"Hello, world!"}' http://localhost:12321/sofa.pbrpc.test.EchoServer.Echo

規則:

  • URL:http://host:port/method_full_name
  • Body:Request Message的json字符串;
  • 返回:Content-Type: application/json;Body: Response Message的json字符串;

GET請求

curl http://localhost:12321/sofa.pbrpc.test.EchoServer.Echo?request=%7B%22message%22%3A%22Hello%2C%20world%21%22%7D

規則:

POST PROTOBUF請求

普通的GET POST請求使用JSON傳遞數據,在字段增多的狀況下性能降低嚴重。 因此在條件許可的狀況下請使用HTTP POST PROTOBUF的接口,樣例能夠參見:python/sample/client_http_protobuf.py

Web監控

提供的頁面(假設server監聽端口爲8080):

主頁示例

輸入圖片說明

相關文章
相關標籤/搜索