当前位置: 首页 > news >正文

sofa-pbrpc高级用法

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

sofa-pbrpc高级用法

输入图片说明

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

sofa-pbrpc高级用法包括:

  • 超时控制
  • 压缩控制
  • 带宽限制
  • 日志打印
  • RpcController使用
  • RPC失败处理
  • Server/Client配置参数
  • 多Server负载均衡与容错
  • 辅助开发工具类
  • Mock测试
  • sofa-pbrpc-client工具
  • 统计与监控
  • HTTP支持
  • Web监控

超时控制

sofa-pbrpc-clienta-pbrpc支持三个级别的超时控制,按照生效的优先级由高到低依次为:

  • Request超时:在RpcController中使用SetTimeout()函数设置超时时间(毫秒),该超时只对本次请求有效;如果不设置,则使用“Method超时”或者“Service超时”;
  • Method超时:在proto文件中指定method的超时时间(毫秒),该超时对该方法的所有请求有效;如果不设置,则使用Service超时;
  • Service超时:在proto文件中指定service的超时时间(毫秒),该超时对该服务的所有方法的所有请求都有效;如果不设置,则使用默认值(10000毫秒)。

在proto文件中指定“method超时”和“Service超时”的样例如下:

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;
        }
}

注意:

如果在proto中指定超时,需要import "sofa/pbrpc/rpc_option.proto",并且编译proto文件时还需要添加protobuf头文件路径到proto_path中,具体可参考样例“sample/timeout_sample”;

RpcController中设置超时时间的接口如下:

void SetTimeout(int64 timeout_in_ms);

压缩控制

sofa-pbrpc支持两个级别的数据压缩控制,按照生效优先级由高到低依次为:

  • Request压缩控制:在RpcController中使用SetRequestCompressType()和SetResponseCompressType()函数设置请求和回复的数据压缩类型,该设置只对本次请求有效;如果不设置,则使用“Method压缩控制”;
  • Method压缩控制:在proto文件中使用扩展option来指定method的Request或者Response的压缩类型,该超时对该方法的所有请求有效;如果不设置,则使用默认值(不压缩);

目前支持的压缩类型包括:

  • None
  • Gzip
  • Zlib
  • Snappy
  • LZ4

在proto文件中指定压缩类型的样例如下:

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_sizepengding 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_sizepengding 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

规则:

  • URL:http://host:port/method_full_name?request=request_json_string
  • request_json_string需要对特殊字符({}[]:",)进行url encode;
  • 返回:同POST;

POST PROTOBUF请求

普通的GET POST请求使用JSON传递数据,在字段增多的情况下性能下降严重。 所以在条件许可的情况下请使用HTTP POST PROTOBUF的接口,样例可以参见:python/sample/client_http_protobuf.py

Web监控

提供的页面(假设server监听端口为8080):

  • 主页:http://localhost:8080/
  • 配置参数: http://localhost:8080/options
  • 状态:http://localhost:8080/status
  • 服务列表:http://localhost:8080/services

主页示例

输入图片说明

转载于:https://my.oschina.net/u/1050511/blog/776105

相关文章:

  • combination-sum-ii(熟悉下Java排序)
  • hping网络安全工具的安装及使用
  • Android开发学习——应用安装过程
  • class path resource [applicationContext.xml] cannot be opened because it does not exis
  • Arrar.prototype.map()的用法
  • [ERROR] Plugin 'InnoDB' init function returned error
  • oracle授权动态视图权限给用户
  • RAC 11.2的新特性
  • ABP文档 - Javascript Api
  • node学习第三天(2)
  • Ansible之玩转常见运维场景(个人总结)
  • 照虎画虎——简单WeUI模板UX设计学习
  • There is no Action mapped for namespace [/] and action name [TestAction] ass
  • php中定义数组的方法详解
  • 下一步要怎么玩?
  • [译]Python中的类属性与实例属性的区别
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 2018一半小结一波
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • eclipse(luna)创建web工程
  • ECMAScript6(0):ES6简明参考手册
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • express如何解决request entity too large问题
  • Hexo+码云+git快速搭建免费的静态Blog
  • in typeof instanceof ===这些运算符有什么作用
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • JS 面试题总结
  • node和express搭建代理服务器(源码)
  • React 快速上手 - 07 前端路由 react-router
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 近期前端发展计划
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 如何正确理解,内页权重高于首页?
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (4)logging(日志模块)
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .net core Swagger 过滤部分Api
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .NET/C# 使用反射注册事件
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .NET企业级应用架构设计系列之结尾篇
  • @vue/cli脚手架
  • [2]十道算法题【Java实现】
  • [2016.7 day.5] T2
  • [④ADRV902x]: Digital Filter Configuration(发射端)
  • [BUUCTF 2018]Online Tool(特详解)