这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记。最近听了青训营老师讲的rpc课程,于是我对于rpc相关知识点做了一些总结和归纳,记录如下~
那么先让我们来了解什么是rpc:
RPC是远程过程调用(Remote Procedure Call)的缩写形式。 那么rpc思想是如何实现的呢?
例让我们先看一个例子,一个本地函数的调用流程:
- 将变量值压栈
- 通过函数指针找到函数,进入函数取出栈中的值2和3将其赋予x和y
- 计算x*y,并将结果存在z
- 将z的值压栈,然后从函数返回
- 从栈中取出z返回值,并赋值给result(接受函数的变量)
rpc的思想是这样的 调用一个远程函数,将函数方法部署在不同的机器上(属于不同的进程)解决问题:
调用流程:
- 函数映射(通过id找到函数)
- 数据转化为字节流(其中json是一种字节流)
- 网络传输
- 远程调用
与本地函数一个重要差别在于:本地函数通过函数指针调用函数,而rpc利用id调用函数。
一次rpc的完整过程:
idl文件: 通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同的语言编写的程序可以相互通信
生成代码: 通过编译器工具把idl工具转换成语言对应的静态库
编解码: 从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化
通信协议: 规范了数据在网络中的传输内容和格式。除必须的请求响应数据外,通常还会包含额外的元数据
网络传输: 通常基于成熟的tcp和udp传输
rpc的好处:
- 单一职责,有利于分工协作(不同语言)和运维开发()。
- 可拓展性强,资源使用效率高
- 故障隔离。服务的整体可靠性跟高
带来的问题:
- 服务如果宕机,对方如何处理
- 调用过程经常出现网络异常,如何保证消息的可达性?
- 请求量徒增服务器无法处理,有哪些应对措施?
小结:
- 本地函数调用和rpc调用的区别:函数映射,数据转成字节流,网络传输
- rpc的概念模型:User,User-Stub,rpc-runtime,server-stub,server
- 一次rpc的完整过程,
- rpc带来好处的同时也带来了不少新问题,将由rpc框架解决
2.rpc分层设计 (以apache thrift为例):
code -> 生成代码(转换不同语言逻辑)-> 框架编解码层 -> 框架协议层 -> 框架的网络通信层
1.编解码层(可以用任何语言编写rpc服务,必须依赖同一份idl文件)
idl数据格式:
- 语言特定的编码格式:内建了将对象编码为字节序列的支持,例如java有java.io.Serializable
- 文本格式:json,xml,csv等文本格式,具有人类可读性
- 二进制编码:跨语言binaryprotopal,protobuf
- 整体打包完为字节流结构 二进制编码:TLV编码: tag:标签,可以理解为类型 len:长度 value:值 TLV编码有可改进空间:由于len和tag无用,可以直接忽略
2.编解码层的选型考虑:
- 兼容性:新增字段不影响老程序
- 通用性:支持跨平台,跨语言
- 性能:从空间和时间两个维度考虑,也就是编码后数据大小和编码耗费时长
3.协议层
将数据转换为了字节流,还需要通信协议
特殊结束符:知道那些部分是不需要读的
变长协议:定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度
协议构造: LENGTH:数据包大小,不包含其自身 HEADER MAGIC:表示版本信息,解析协议时快速校验, SEQUENCE NUMBER:表示数据包的seqid,可用于多路复用,单连接内递增 HEADER SIZE:头部长度,从第14个字节开始计算一直到PAYLOAD前 PROTOCOL ID:编解码方法,有Binary和Compact 两种 TRANSFORM ID:压缩方式,如zlib和snappy INFO ID:传递一些定制的meta信息 PAYLOAD:消息体
协议解析:(分析协议类型)(分析编码方式) (解码) MagicNumber-> PayLoadCodec -> PatLoad
4.网络通信层(利用socket api)
server的accept如果没有client信息会一直阻塞
1.提供简单易用的api 封装底层socket api,链接管理和事件开发
2.功能 协议支持:tcp,udp,uds 优雅退出,异常处理
3.性能 应用层buffer减少copy 高性能定时器,对象池