流程:
1.客户端调用函数。这个调用是在本地,并将调用参数push到栈中。
2.客户端将这些参数包装并编码,发送到服务端机器。编码常见方式:XML,JSON,二进制编码pb,thrift。
3.应用层通常使用http或自定义协议,传输层一般使用tcp,http3后可使用udp传送数据。
4.服务器接收数据包。
5.服务端解析数据。
6.服务端调用解析出来的数据信息对应的函数,并通过类似的方式返回给客户端。
注意:
服务端支持客户端rpc调用的函数通常需要注册指定,不在注册列表中的函数返回失败。分布式系统中,服务可能有成千上万。
服务间通信如果使用ip加端口的方式,调用关系就很难理清楚。使用http的restful的形式调用,又很难进行跨多个服务间的调用。通过获取匹配名字服务的服务列表,rpc调用可以指定服务名字,客户端只需要关心需要调用的服务类型,而不需要关心具体实现细节。
支持多种语言rpc调用,使用http2+pb作为底层编码和通信协议,quic协议成熟后,性能会有很大提升。
四种服务类型:
1.单项rpc,请求:客户端->服务器,返回:服务器->客户端
2.服务端流式rpc,客户端读请求,服务端多次返回,直到没有更多数据为止(服务端记录请求状态)。
3.客户端流式rpc,客户端写请求,多次写入,服务端读取完成后返回(服务端记录请求状态)。
4.双向流式rpc,两边都可以使用流来读写数据。
cpp_plugin:CppGrpcGenerator继承grpc::protobuf::compiler::CodeGenerator,虚函数Generate生成代码。cpp_generator封装了生成代码的方法。生成的文件名是.grpc.pb.h和.grpc.pb.cc和_mock.grpc.pb.h为后缀。
编译成动态库给其他语言使用。
大部分底层库的实现,包括tcp,http,udp协议相关,channelz的实现,压缩算法,序列化工具,正则匹配,异步库封装,认证安全,基础库等等。
ProtoServerReflection:反射方法实现,通过ServerContext服务报文,ServerReflectionInfo可以获取到各种反射信息。
实现了各种过滤器框架和一些插件,包括channel,client,sever过滤。主要是一些统计信息和编解码。
ThreadManager通用线程池基类,Initialize初始化线程池数量,定义覆盖虚函数完成自己的线程池任务。
WorkerThread是ThreadManager内部类,可以通过指向ThreadManager*的thd_mgr_指针控制任务执行,以状态机的形式循环执行。
AddAdminServices加入管理服务,管理服务也是一个ChannelzService类型的channelz服务。
ChannelzService继承自channelz::v1::Channelz::Service
channelz::v1::Channelz::Service提供了一个通用rpc服务的框架。
ChannelzService实现了GetTopChannels,GetServers,GetServerSockets等等获取channel,服务,socket的接口,用来判断这些对象的状态是否ok。
ClientStatusDiscoveryService(客户端状态发现服务)继承自 envoy::service::status::v3::ClientStatusDiscoveryService::Service。
实现了StreamClientStatus:判断指定客户端流是否可读可写。
DefaultHealthCheckService:
健康检测服务框架。通过AddMethod加入需要执行的rpc检测方法,然后创建线程执行Serve(void* arg)函数,内部循环取出arg队列中的CallableTag执行。DefaultHealthCheckService的内部类CheckCallHandler和WatchCallHandler内部都有一个CallableTag绑定执行函数。
获取服务端cpu负载报告,并且可以store存储。
brpc相对比grpc,细节更加完善,优化做的更好,主要是给c++语言使用。
memory fence:就是内存屏障
wait-free:不管操作系统如何调度系统,每个线程始终在做有用的事
lock-free:不管操作系统如何调度系统,至少有一个线程在做有用的事
自适应限流:不断的对请求进行采样,当采样窗口的样本数量足够时,会根据样本的平均延迟和服务当前的qps计算出下一个采样窗口的max_concurrency。需要注意:估算noload_latency,减少重测时的流量损失(排空测量的流量),应对抖动,平滑处理。
流量放大:重传导致,尽量避免重传,只在错误时重传,控制重传间隔。
ChannelOptions.backup_request_ms:保证可用性,要访问两路服务,哪个先返回就取哪个,这个就是设置间隔时间。
bthread:使用M:N线程库
bthread_id_t:64位长度,32位内存池位移+32位版本。标志1个rpc,互斥rpc过程的不同环节。
熔断:
默认某个节点发现连续三次连接超时触发熔断。从可用节点中剔除。间隔固定时间重新尝试连接恢复。
可选熔断,连接正常,请求超时。
channel:客户端连接后服务端保存的对象,和server一样是独立对象资源,可以在不同线程上使用。
命名服务以及过滤器,负载均衡图示:
从集群宕机后恢复时的客户端限流:防止频繁过载服务异常。
ParallelChannel:组合channel,包含多个子channel,并合并他们的结果。
SelectiveChannel:按负载均衡算法访问其包含的channel,把流量分给sub channel。
PartitionChannel:根据命名服务中的tag自动建立对应分库的sub channel。
DynamicPartitionChannel:根据不同的分库方式动态地建立对应的sub PartitionChannel,并根据容量把请求分配给不同的分库。
ContentionProfiler,可以分析在等待锁上花费了多少时间。适用于互斥锁这类会睡眠的锁。cpu profiler比较使用于自旋锁,或者死锁问题。
原理:自己重新实现了mutex互斥锁,在里面加上ContentionProfiler的开关,打开时就会在lock和unlock之间记录时间。
wait-free类型的不固定线程执行的队列。
类似go语言的切片slice
是一个能把请求及时、自动地送到延时最低的下游的负载均衡算法,特别适合混合部署环境。
数据分前后台,检索线程只读前台,不加锁,只有一个写线程。类似rcu的机制。
/status: 显示所有服务的主要状态。
/vars: 用户可定制的,描绘各种指标的计数器。
/connections: 所有连接的统计信息。
/flags: 所有gflags的状态,可动态修改。
/rpcz: 查看所有的RPC的细节。
cpu profiler: 分析cpu热点。
heap profiler:分析内存占用。
contention profiler: 分析锁竞争。
/health: 探测服务的存活情况
/protobufs: 查看程序中所有的protobuf结构体。
/dir: 浏览服务器上的所有文件,方便但非常危险,默认关闭。
/threads: 查看进程内所有线程的运行状况,调用时对程序性能影响较大,默认关闭。