这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记
RPC概念模型
①发起本地调用
②数据打包
③数据传送给对端
④数据接收
⑤解压数据
⑥数据处理
⑦结果数据打包
⑧传送返回数据
⑨接收数据
⑩解压数据
⑪数据结果返回
一次RPC的过程
IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信。(约定调用规范)
- 生成代码
通过编译器工具把IDL文件转换成语言对应的静态库。(具体调用的时候用户代码需要依赖生成代码,所以可以把用户代码和生成代码看做一个整体)
- 编解码
从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化。
- 通信协议
规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还会包含额外的元数据。
- 网络传输
通常基于成熟的网络库走TCP/UDP传输。
RPC分层设计
Sockets API
03关键指标
3.1 稳定性-保障策略
- 熔断:保护调用方,防止被调用的服务出现问题而影响到整个链路
- 限流:保护被调用方,防止大流量把服务压垮(降级处理/返回限流异常)
- 超时控制:避免浪费资源在不可用节点上(超时主动停掉不太重要的业务)
(以上三种都是快速返回,避免资源浪费在不可调用的请求上,也是服务降级的手段)
3.2稳定性-请求成功率
- 负载均街
- 重试(会加大直接下游的负载,有放大故障的风险)
防止重试风暴,限制单点重试和限制链路重试。
3.3稳定性-长尾请求
长尾请求一般是指明显高于均值的那部分占比较小的请求。业界关于延迟有一个常用的P99标准, P99 单个请求响应耗时从小到大排列,顺序处于99%位置的值即为P99值,那后面这1%就可以认为是长尾请求。在较复杂的系统中,长尾延时总是会存在。造成这个的原因非常多,常见的有网络抖动,GC,系统调度
我们预先设定一个阈值 t3 (比超时时间小,通常建议是RPC请求延时的pct99),当Req1发出去后超过t3时间都没有返回,那我直接发起重试请求Req2,这样相当于同时有两个请求运行。然后等待请求返回,只要Resp1或者Resp2任意一个返回成功的结果, 就可以立即结束这次请求,这样整体的耗时就是t4,它表示从第一个请求发出到第一个成功结果返回之 间的时间,相比于等待超时后再发出请求,这种机制能大大减少整体延时。
Kitex
整体架构
自研网络库- Netpoll
解决无法感知连接状态问题
- 引入 epoll主动监听机制,感知连接状态
解决goroutine暴涨的风险
- 建立goroutine池,复用goroutine
提升性能
- 引入Nocopy Buffer,向上层提供NoCopy的调用接口,编解码层面零拷贝