1.1远程函数调用(RPC-Remote Procedure Calls)
RPC需要解决的问题
- 函数映射
- 数据转换成字节流
- 网络传输
1.2RPC概念模型
RPC的过程由五个模型组成
User、User-Stub、RPC-Runtime、Server-Stub、Server。
User发起本地调用User-stub,然后参数打包交给RPCRuntime,接着把数据传输给对端。对端接收到之后交给server-stub来解压数据再交给Server执行业务逻辑。 返回相同流程。
1.3 一次RPC的完整过程
- IDL文件
IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信 - 生成代码
通过编译器工具把IDL文件转换成语言对应的静态库 - 编解码
从内存中表示到字节序列的转换成为编码,反之为解码,也常叫做序列化和反序列化。 - 通信协议
规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还会包含额外的元数据 - 网络传输
通常基于成熟的网络库走TCP/UDP传输
1.4 RPC的好处
- 单一职责,有利于分工写作和运维开发
- 可扩展性强,资源使用率更优
- 故障隔离,服务的整体可靠性更高
2.1 分层设计-以Apache Thrift为例
2.2 编解码层-生成代码
客户端和服务端依赖同一份IDL文件生成不同语言的生成代码。
2.3 编解码层-数据格式
- 语言特定的格式
许多编程语言都内建了将内存对象编码为字节序列的支持,例如Java有java.io.Serializable - 文本格式
JSON、XML、CSV等文本格式,具有人类可读性 - 二进制编码
具备跨语言和高性能等优点,常见有Thrift的BinaryProtocol,Protobuf等
2.4 编解码层-二进制编码
TLV编码
- Tag:标签,可以理解为类型
- Lenght:长度
- Value: 值,Value也可以是个TLV结构
2.5 编解码层-选型
- 兼容性
支持自动增加新的字段,而不影响老的服务。 - 通用性
支持跨平台、跨语言 - 性能
从空间和时间两个维度来考虑,也就是编码后数据大小和编码耗费时长。
2.6 协议层-概念
- 特殊结束符:一个特殊字符作为每个协议单元的结束的标识。例如http协议
- 变长协议:以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度。
2.7 协议层-协议构造
- LENGTH:数据包大小,不包含自身
- HEADER MAGIC: 标识版本信息,协议解析时候快速校验。
- SEQUENCE NUMBER:表示数据包的seqID 可用于多路复用,单连接内递增
- HEADER SIZE:头部长度,从第14个字节开始 计算一直到PAYLOAD前
- PROTOCOL ID:编解码方式,有Binary和 Compact两种
- TRANSFORM ID:压缩方式,如ZIib和snappy
- INFO ID:传递一些定制的meta信息
- PAYLOAD:消息体
2.8 协议层-协议解析
2.9 网络通信层-Sockets API
- 创建一个socket首先bind一个地址(ip加端口)
- listen监听进来的链接放到一个队列。
- accept客户端发起请求会接收一个连接的请求
- read和write进行通信
- colse关闭套接字
2.10 网络通信层 - 网络库
- 提供易用API
封装底层Socket API
连接管理和事件分发 - 功能
协议支持:tcp、udp和uds等
优雅退出、异常处理等 - 性能
应用层buffer减少copy
高性能定时器、对象池等
3.1 稳定性-保障策略
- 熔断:保护调用方, 防止被调用的服务出现问题而影响到整个链路
- 限流:保护被调用方,防止大流量把服务压垮
- 超时控制:避免浪费资源在不可用节点上
3.2 稳定性-请求成功率
- 负载均衡:均匀的调用节点,防止请求过大。
- 重试:调用失败重试几次才会失败。
3.3 稳定性-长尾请求
长尾请求:明显高于平均响应时间的请求
Backup Request
设置一个应该响应的时间t3。如果没有返回就重发。
3.4 稳定性-注册中间件
在框架中注册中间件(拦截器)