什么是RPC?
RPC 的全称是 Remote Procedure Call,即远程过程调用。简单解读字面上的意思,远程肯定是指要跨机器而非本机,所以需要用到网络编程才能实现。
从业务角度来看,RPC有两个作用
- 屏蔽远程调用跟本地调用的区别,让我们感觉就是调用项目内的方法;
- 隐藏底层网络通信的复杂性,让我们更专注于业务逻辑;
从技术角度来看,RPC有这几个作用
- 屏蔽组包解包
- 屏蔽数据发送/接收
- 网络传输
RPC vs RESTful
RPC 的消息传输可以通过 TCP、UDP 或者 HTTP等,所以有时候我们称之为 RPC over TCP、 RPC over HTTP。RPC 通过 HTTP 传输消息的时候和 RESTful的架构是类似的,但是也有不同。
首先我们比较 RPC over HTTP 和 RESTful。
首先 RPC 的客户端和服务器端是紧耦合的,客户端需要知道调用的过程的名字,过程的参数以及它们的类型、顺序等。一旦服务器更改了过程的实现, 客户端的实现很容易出问题。RESTful基于 http的语义操作资源,参数的顺序一般没有关系,也很容易的通过代理转换链接和资源位置,从这一点上来说,RESTful 更灵活。
其次,它们操作的对象不一样。 RPC 操作的是方法和过程,它要操作的是方法对象。 RESTful 操作的是资源(resource),而不是方法。
第三,RESTful执行的是对资源的操作,增加、查找、修改和删除等,主要是CURD,所以如果你要实现一个特定目的的操作,比如为名字姓张的学生的数学成绩都加上10这样的操作, RESTful的API设计起来就不是那么直观或者有意义。在这种情况下, RPC的实现更有意义,它可以实现一个 Student.Increment(Name, Score) 的方法供客户端调用。
我们再来比较一下 RPC over TCP 和 RESTful。 如果我们直接使用socket实现 RPC,除了上面的不同外,我们可以获得性能上的优势。
RPC over TCP可以通过长连接减少连接的建立所产生的花费,在调用次数非常巨大的时候(这是目前互联网公司经常遇到的情况,大并发的情况下),这个花费影响是非常巨大的。 当然 RESTful 也可以通过 keep-alive 实现长连接, 但是它最大的一个问题是它的request-response模型是阻塞的 (http1.0和 http1.1有这个问题, http 2.0没这个问题), 发送一个请求后只有等到response返回才能发送第二个请求 (有些http server实现了pipeling的功能,但不是标配), RPC的实现没有这个限制。
RPC 通信流程
- 序列化/反序列化:远程调用涉及数据的传输,就会涉及组包和解包,需要调用方和服务方约定数据格式。序列化就是将对象转换成二进制数据的过程,而反序列就是反过来将二进制转换为对象的过程。
- 常用的有JSON,Protobuf等序列化方式
RPC调用
-
Client 端工作:
- 建立与Server的连接
- 组装数据
- 发送数据包
- 接收处理结果数据包
- 解析返回数据包
-
Server 端工作:
- 监听端口
- 响应连接请求
- 接收数据包
- 解析数据包
- 调用相应方法
- 组装请求处理结果数据包
- 发送结果数据包
- 序列化协议
协议是 RPC 的核心,它规范了数据在网络中的传输内容和格式。除必须的请求、响应数据外,通常还会包含额外控制数据,如单次请求的序列化方式、超时时间、压缩方式和鉴权信息等。
协议的内容包含三部分
-
数据交换格式: 定义 RPC 的请求和响应对象在网络传输中的字节流内容,也叫作序列化方式
-
协议结构: 定义包含字段列表和各字段语义以及不同字段的排列方式
-
协议通过定义规则、格式和语义来约定数据如何在网络间传输。一次成功的 RPC 需要通信的两端都能够按照协议约定进行网络字节流的读写和对象转换。如果两端对使用的协议不能达成一致,就会出现鸡同鸭讲,无法满足远程通信的需求。
-
version: 标识协议版本
-
cmd:请求的api
-
contenttype:数据类型
-
bodylength:数据长度
RPC核心功能剖析
Comsumer
- 连接管理:保持与服务提供方长连接,用于传输请求数据也返回结果
- 负载均衡 :确保多个服务提供方节点流量均匀/合理,支持节点扩容与灰度发布
- 轮训、随机、取模 、带权重 、一致性Hash
- 请求路由:通过一系列规则过滤出可以选择的服务提供方节点列表,在应用隔离,读写分离,灰度发布中都发挥作用
-
条件路由:基于条件表达式(待比较属性 l 运算符 l 属性匹配值 l 匹配结点 )的路由规则
-
- IP分流规则举例:attribute=IP,operator=IN,value=IP1,IP2,Servers:Node1,Node2
-
标签路由:将服务分组的路由规则
-
- 超时处理 :对于长时间没有返回的请求,需要作出异常处理,及时释放资源
如下图
Provider
- 队列/线程池:将不同类型的请求,放入各自的队列,每个队列分配独立的线程池,资源隔离。
- 超时丢弃:快速失败已经超时的请求,缓解队列堆积。可以在进入队列和出队列的时候判断是否超时
- 优雅关闭:进程退出前确保接收到的请求全部处理完成
- 如果通知consumer?请求返回的时候通知,专门的协议通知
- 过载保护:服务提供方为保证正常运行,主动丢弃超出处理能力外的请求
其他功能
- 服务熔断:当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用
- 服务降级 :对业务降级,跳过异常调用,返回关键数据,确保服务可用
- 动态权重 :为刚启动节点分配较低权重,逐步提高权重
限流:保护服务节点或者集群后面的数据节点,防止瞬时流量过大使服务和数据崩溃(如前端缓存大量实效),造成不可用;还可用于平滑请求。 - 限流算法有两种,一种就是简单的请求总量计数,一种就是时间窗口限流(一般为1s),如令牌桶算法和漏牌桶算法就是时间窗口的限流算法。
- 健康检测:
- 基于可用率的健康检测。可用率的计算方式是某一个时间窗口内接口调用成功次数的百分比(成功次数 / 总调用次数)。当可用率低于某个比例就认为这个节点存在问题,把它挪到亚健康列表,这样既考虑了高低频的调用接口,也兼顾了接口响应时间不同的问题。
- 基于TCP 连接是否健康、心跳是否正常等简单维度考虑