这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记,学校事情好多,记的效率太慢了。我尽量学习一些通用的东西,因为不一定选择go
什么是RPC?
RPC全称Remote Procedure Call,即是远程过程调用。
rpc主要作用是屏蔽网络编程的细节,实现调用远程服务的方法就像调用本地方法一样简单方便,同时屏蔽底层网络通信的复杂性,让我们更加专注业务逻辑的开发。
RPC要解决的问题
- 函数映射
- 数据转换成字节流
- 网络传输
函数映射问题,比如我们在本地的订单服务要调用远程的支付服务,那么我们发起调用的时候远程的服务器是怎么知道我要调用哪个服务(函数)的?如果在本地,那么可以通过指针函数,但是远程调用不行。因为两个进程的地址空间是完全不一样的。所以每个服务应该有一个ID,在rpc的过程中附上这个ID,被调用方需要维护一个函数与ID的映射表。
调用函数的时候一般要传递参数,在本地调用我们一般把参数压入栈中,让函数自己去栈中找即可。但是远程调用不行,因为两个服务的进程空间不同,远程的函数自然无法获取本地栈中的数据,所以我们需要把数据转换成字节流通过网络传输给远程。
远程调用自然要考虑网络传输问题,我们如何保证传输的高效和稳定?
RPC的5个模块
- user
- user-stub
- RPCruntime
- server-stub
- server
user就是client端,user如果想要发起远程调用,便将要调用的函数信息比如参数和函数对应的ID传输给user-stub接口,user-stub接口将user传过来的信息按照约定的规范和协议进行转码打包,然后发给本地RPCruntime,本地RPCruntime调用网络库进行网络传输将打包的信息发给远程的RPCruntime,然后远程端的RPCruntime实例将信息包发给server-stub进行解码并调用本地的sever,然后返回结果,返回结果的方式与发起调用一致
一次RPC的完整过程
- IDL文件
- 生成代码
- 编解码
- 通信协议
- 网络传输
相比于本地调用,我们不知道对方有哪些函数和参数。所以需要有一种方式来描述或者说声明我有哪些方法已经参数长什么样,这样大家都按这个方式来调用。这个描述文件就是IDL文件。
服务双方需要通过约定的规范来进行远程服务调用,双方都依赖同一份IDL文件,需要通过工具来生成对应的生成文件,具体调用的时候用户代码需要依赖生成代码,所以可以把用户代码和生成代码看作一个整体。
编解码就是序列化和反序列化。
编码只是解决了跨语言的数据交换格式的问题,如何通讯还需要制定网络协议,然后解决网络传输问题,这个是transfer做的工作。
RPC的好处
- 单一职责,开发(可采用不同的语言),有利于分工协作和运维开发。
- 可扩展性强,底层基础服务可以复用,资源使用率更高。
- 故障隔离,服务的整体可靠性高。
RPC带来的问题
- 服务宕机,对方应该怎么处理?
- 在调用过程中发生网络异常,如何保证消息可靠?
- 请求量突增导致无法及时处理,有哪些应对措施?
分层设计
以Apache Thrift为例
编解码层
数据格式
- 语言特定的格式
- 文本格式
- 二进制编码
语言特定的格式这种编码的好处是非常方便,但是坏处就是与某一种语言深度绑定,兼容性差。
文本格式具有人类可读性,数字的编码多有歧义,比如XML和CSV不能区分数字和字符串,JSON虽然能区分数字和字符串,但是不能区分整数和浮点数,而且不能指定精度,处理大量数据的时候,这个问题更严重;没有强制模型约束;由于JSON在一些语言中的序列化和反序列化只能采用反射机制,所以性能很差
二进制编码:实现方式很多,如TLV编码和Varint编码
选型
- 可扩展性,新的业务的加入不能影响老业务的使用。
- 兼容性,跨平台,多语言
- 性能,空间,时间。
协议层
协议是干什么的?为什么我们需要协议?
设计协议的目的是为了实现双方交流通信。
没有协议,就像是鸡同鸭讲话,双方都听不懂。
而RPC本质上是服务于不同进程的通信的,所以对协议的设计会更加的注重。
为什么RPC要不直接使用现有的协议如HTTP协议,而要自己去写私有协议?
首先,实际上RPC的发展是早于HTTP的。
然后是HTTP协议的数据包实际上非常的臃肿,而RPC所负责的不同进程的通信实际上是非常需要性能的,所以rpc会选择去设计一个更加紧凑的协议。
再者,rpc本身有许多自身的特性,如服务的一些信息,熔断,限流,负载均衡等等。我们将这些rpc所拥有的特定信息进行封装也能提高性能。
协议的设计
- 定长的协议,包括协议头和协议体。
- 不定长的协议,包括协议头和协议头的扩展部分和协议体。
定长的协议不面向升级,可扩展性差,一般使用不定长的协议
网络通信层
一般自己封装网络库,指标如图
什么是RPC?
RPC全称Remote Procedure Call,即是远程过程调用。
rpc主要作用是屏蔽网络编程的细节,实现调用远程服务的方法就像调用本地方法一样简单方便,同时屏蔽底层网络通信的复杂性,让我们更加专注业务逻辑的开发。
RPC要解决的问题
- 函数映射
- 数据转换成字节流
- 网络传输
函数映射问题,比如我们在本地的订单服务要调用远程的支付服务,那么我们发起调用的时候远程的服务器是怎么知道我要调用哪个服务(函数)的?如果在本地,那么可以通过指针函数,但是远程调用不行。因为两个进程的地址空间是完全不一样的。所以每个服务应该有一个ID,在rpc的过程中附上这个ID,被调用方需要维护一个函数与ID的映射表。
调用函数的时候一般要传递参数,在本地调用我们一般把参数压入栈中,让函数自己去栈中找即可。但是远程调用不行,因为两个服务的进程空间不同,远程的函数自然无法获取本地栈中的数据,所以我们需要把数据转换成字节流通过网络传输给远程。
远程调用自然要考虑网络传输问题,我们如何保证传输的高效和稳定?
RPC的5个模块
- user
- user-stub
- RPCruntime
- server-stub
- server
user就是client端,user如果想要发起远程调用,便将要调用的函数信息比如参数和函数对应的ID传输给user-stub接口,user-stub接口将user传过来的信息按照约定的规范和协议进行转码打包,然后发给本地RPCruntime,本地RPCruntime调用网络库进行网络传输将打包的信息发给远程的RPCruntime,然后远程端的RPCruntime实例将信息包发给server-stub进行解码并调用本地的sever,然后返回结果,返回结果的方式与发起调用一致
一次RPC的完整过程
- IDL文件
- 生成代码
- 编解码
- 通信协议
- 网络传输
相比于本地调用,我们不知道对方有哪些函数和参数。所以需要有一种方式来描述或者说声明我有哪些方法已经参数长什么样,这样大家都按这个方式来调用。这个描述文件就是IDL文件。
服务双方需要通过约定的规范来进行远程服务调用,双方都依赖同一份IDL文件,需要通过工具来生成对应的生成文件,具体调用的时候用户代码需要依赖生成代码,所以可以把用户代码和生成代码看作一个整体。
编解码就是序列化和反序列化。
编码只是解决了跨语言的数据交换格式的问题,如何通讯还需要制定网络协议,然后解决网络传输问题,这个是transfer做的工作。
RPC的好处
- 单一职责,开发(可采用不同的语言),有利于分工协作和运维开发。
- 可扩展性强,底层基础服务可以复用,资源使用率更高。
- 故障隔离,服务的整体可靠性高。
RPC带来的问题
- 服务宕机,对方应该怎么处理?
- 在调用过程中发生网络异常,如何保证消息可靠?
- 请求量突增导致无法及时处理,有哪些应对措施?
分层设计
以Apache Thrift为例
编解码层
数据格式
- 语言特定的格式
- 文本格式
- 二进制编码
语言特定的格式这种编码的好处是非常方便,但是坏处就是与某一种语言深度绑定,兼容性差。
文本格式具有人类可读性,数字的编码多有歧义,比如XML和CSV不能区分数字和字符串,JSON虽然能区分数字和字符串,但是不能区分整数和浮点数,而且不能指定精度,处理大量数据的时候,这个问题更严重;没有强制模型约束;由于JSON在一些语言中的序列化和反序列化只能采用反射机制,所以性能很差
二进制编码:实现方式很多,如TLV编码和Varint编码
选型
- 可扩展性,新的业务的加入不能影响老业务的使用。
- 兼容性,跨平台,多语言
- 性能,空间,时间。
协议层
协议是干什么的?为什么我们需要协议?
设计协议的目的是为了实现双方交流通信。
没有协议,就像是鸡同鸭讲话,双方都听不懂。
而RPC本质上是服务于不同进程的通信的,所以对协议的设计会更加的注重。
为什么RPC要不直接使用现有的协议如HTTP协议,而要自己去写私有协议?
首先,实际上RPC的发展是早于HTTP的。
然后是HTTP协议的数据包实际上非常的臃肿,而RPC所负责的不同进程的通信实际上是非常需要性能的,所以rpc会选择去设计一个更加紧凑的协议。
再者,rpc本身有许多自身的特性,如服务的一些信息,熔断,限流,负载均衡等等。我们将这些rpc所拥有的特定信息进行封装也能提高性能。
协议的设计
- 定长的协议,包括协议头和协议体。
- 不定长的协议,包括协议头和协议头的扩展部分和协议体。
定长的协议不面向升级,可扩展性差,一般使用不定长的协议
网络通信层
一般自己封装网络库,指标如图