这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记
1 基本概念
本地函数调用
远程函数调用
RPC概念模型
①发起本地调用 ②数据打包 ③数据传送给对端 ④数据接收 ⑤解压数据 ⑥数据处理 ⑦结果数据打包 ⑧传送返回数据 ⑨接收数据 ⑩解压数据 ⑪数据结果返回
一次PRC的完整过程
IDL (Interface description language)文件
- IDL 通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信
生成代码
- 通过编译器工具把 IDL 文件转换成语言对应的静态库
编解码
- 从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化
通信协议
- 规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还会包含额外的元数据
网络传输
- 通常基于成熟的网络库走 TCP/UDP 传输
PRC的好处
- 单一职责,有利于分工协作和运维开发
- 可扩展性强,资源使用率更优
- 故障隔离,服务的整体可靠性更高
2 分层设计
以Apache Thrift为例
编解码层
编解码层--生成代码
编解码层--数据格式
编解码层--二进制编码
我们可以用二进制编码的方式,表示任意的信息。只要建立起字符集和字符编码,并且得到大家的认同,我们就可以在计算机里面表示这样的信息了。
编解码层--选型
通用性:
通用性有两个层面的意义:
第一、技术层面,序列化协议是否支持跨平台、跨语言。如果不支持,在技术层面上的通用性就大大降低了。
第二、流行程度,序列化和反序列化需要多方参与,很少人使用的协议往往意味着易贵的学习成本;另一方面,流行度低的协议,往往缺乏稳定而成熟的跨语言、跨平台的公共包。
兼容性:
移动互联时代,业务系统需求的更新周期变得更快,新的需求不断涌现,而老的系统还是需要继续维护。如果序列化协议具有良好的可扩展性,支持自动增加新的业务字段,而不影响老的服务,这将大大提供系统的灵活度。
协议层
这层除了通讯的数据还会增加一些需要的数据。
协议层--概念
协议层--协议构造
协议层解析
通过MagicNumber知道协议的类型,从PayloadCodeC得到编码的方式,进行解析。
网络通信层
网络通信层--Sockets API
套接字编程中的客户端必须知道两个信息:服务器的IP地址,以及端口号。
socket函数创建一个套接字,bind将一个套接字绑定到一个地址上。listen监听进来的连接,backlog的含义有点复杂,这里先简单的描述:指定挂起的连接队列的长度,当客户端连接的时候,服务器可能正在处理其他逻辑而未调用accept接受连接,此时会导致这个连接被挂起,内核维护挂起的连接队列,backlog则指定这个队列的长度,accept函数从队列中取出连接请求并接收它,然后这个连接就从挂起队列移除。如果队列未满,客户端调用connect马上成功,如果队列末满,客户端调用connect马上成功,如果满了可能会阻塞等待队伍未满(实际上在linux中测试并不是这样的结果)。Linux的backlog默认是128,通常情况下,我们也指定为128即可。
网络通信层--网络库
小结
3 关键指标
稳定性
保障策略
-
熔断:保护调用方,防止被调用的服务出现问题而影响到整个链路
-
限流:保护被调用方,防止大流量把服务压垮
-
超时控制:避免浪费资源在不可用节点上
请求成功率
- 负载均街
- 重试(会加大直接下游的负载,有放大故障的风险)
防止重试风暴,限制单点重试和限制链路重试。
长尾请求
长尾请求一般是指明显高于均值的那部分占比较小的请求。业界关于延迟有一个常用的P99标准,P99单个请求响应耗时从小到大排列,顺序处于99%位置的值即为P99值,那后面这1%就可以认为是长尾请求。在较复杂的系统中,长尾延时总是会存在。造成这个的原因非常多,常见的有网络抖动,GC,系统调度。
我们预先设定一个阈值t3(比超时时间小,通常建议是RPC请求延时的ptc99),当Req1发出去后超过t3时间都没有返回,那我们直接发起重试清求Req2,这样相当于同时有两个请求运行。然后等待请求返回,只要Resp1或者Resp2任意一个返回成功的结果,就可以立即结束这次请求,这样整体的耗时就是t4,它表示从第一个请求发出到第一个成功结果返回之间的时间,相比于等待超时后再发出请求,这种机制能大大减少整体延时。转载请联系作者获得授权,非商业转载请注明出处。
注册中间件
Kitex Client 和 Server 的创建接口均采用 Option 模式,提供了极大的灵活性,很方便就能注入这些稳定性策略
易用性
开箱即用
- 合理的默认参数选项、丰富的文档
周边工具
- 生成代码工具、脚手架工具
扩展性
-
Middleware:middleware 会被构造成一个有序调用链逐个执行,比如服务发现、路由、负载均衡、超时控制等
-
Option:作为初始化参数
-
核心层是支持扩展的:编解码、协议、网络传输层
-
代码生成工具也支持插件扩展
观测性
-
三件套:Log、Metric 和 Tracing
-
内置观测性服务,用于观察框架内部状态
- 当前环境变量
- 配置参数
- 缓存信息
- 内置 pprof 服务用于排查问题
高性能
-
连接池和多路复用:复用连接,减少频繁建联带来的开销
-
高性能编解码协议:Thrift、Protobuf、Flatbuffer 和 Cap'n Proto 等
-
高性能网络库:Netpoll 和 Netty 等