RPC框架分层设计

46 阅读3分钟

一、基本概念 1.本地函数调用

func main( ){ var a = 2 var b =3 result := calculate(a, b) fmt.Println(result) return } func calculate(x, y int) { z:=xy return z } (1)将a和b的值压栈 (2)通过函数指针找到calculate函数,进入函数取出栈中的值2和3,将其赋予x和y (3)计算xy,并将结果存在z (4)将z的值压栈,然后从calculate返回 (5)从栈中取出z返回值,并赋值给 result 2.远程函数调用 RPC 需要解决的问题 (1)函数映射 (2)数据转换成字节流 (3)网络传输 3.一次RPC的完整过程

IDL文件:IDL通过一种中立的方式来描述接口,使得不同平台上运行的对象和用不同语言编写的程序可以相互通信

生成代码:通过编译工具将IDL文件转换成语言对应的静态库

编解码:从内存中表示到字节序列的转化称之为编码,反之为解码,常称之为序列化和反序列化

通信协议:规范了数据在网络中传输的内容和格式,除了必要的响应请求数据外,通常还会包含额外的元数据 网络传输:通常基于成熟的网络库走TCP/UDP传输 4.RPC好处

函数职责单一,有利于分工协作和运维开发 可扩展性强,可以独立扩充资源,资源使用率更优秀 故障隔离,单个服务故障不影响整体,服务的整体可用性更高 5.RPC带来的问题

如果调用的函数所属的服务宕机应该如何处理 调用过程中网络异常,如何保证消息可达 请求量突增导致服务无法及时处理,如何应对

这些问题一般由RPC框架来解决

二、分层设计 以Apache Thrift为例

用户自己编写的业务逻辑代码 通过代码生成工具把 IDL文件转换成不同语言对应的 lib 代码,里面封装了编解码逻辑 框架的编解码层-生成代码

客户端和服务端通过同一份IDL文件生成不同的语言 数据格式:

语言特定格式:许多编程语言都内建了将内存对象编码为字节序列的支持,比如Java的java.io.Serializable序列化格式。缺点是和语言深度绑定了 文本格式:JSON\XML\CSV等,具有人类可读性,但是描述不够严谨,而且缺乏模型约束,只能采用文档约束 二进制编码:具有跨语言和高性能等优点,常见有Thrift的BinaryProtocal等

编码层的选型

兼容性:支持新增字段但不影响老得服务 通用性:跨平台跨语言 性能:从空间和时间两个维度来考虑

协议层-协议构造

LENGTH: 数据包大小,不包含自身 HEADER MAGIC:标识版本信息,协议解析时候快速校验 SEQUENCE NUMBER:表示数据包的 seqID,可用于多路复用,单连接内递增 HEADER SIZE:头部长度,从第14个字节开始计算一直到 PAYLOAD前 PROTOCOL ID: 编解码方式,有Binary和 Compact 两种 TRANSFORM ID:压缩方式,如zlib 和 snappy INFO ID: 传递一些定制的meta信息 PAYLOAD: 消息体

网络通信层-网络库

提供易用 API 封装底层 Socket API 连接管理和事件分发 功能 协议支持:tcp、udp 和 uds 等 优雅退出、异常处理等 性能 应用层 buffer 减少copy 高性能定时器、对象池等

主要是用SocketAPI进行通信,其中SocketAPI位于应用层和传输层之间