一文搞懂RPC组成结构,与Restful区别

2,969 阅读8分钟

1、什么是RPC?

RPC(Remote Procedure Call),远程过程调用,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。通俗地讲,就是开发者能够像调用本地方法一样调用远程的服务。RPC的作用主要体现在两个方面:

  1. 屏蔽远程调用跟本地调用的区别,让我们感觉就是调用项目内的方法;
  2. 隐藏底层网络通信的复杂性,让我们更专注于业务逻辑。

两个或多个应用程序都分布在不同的服务器上,它们之间的调用都像是本地方法调用一样。比较知名开源的RPC框架有阿里的Dubbo、google的gRPC、Go语言的rpcx、Apache的thrift等。 要实现向调用本地服务一样调用远程方法可能需要涉及的知识有:

Image.jpg

  • 动态代理
  • 反射
  • 序列化、反序列化
  • 网络通信
  • 编解码
  • NIO
  • 服务发现和注册
  • 心跳与链路检测
  • 负载均衡
  • ……

2、RPC 框架基本架构

Image.png 从图上可以看出,RPC 框架主要由三部分构成:

  1. 注册中心,服务端在启动后,会将它提供的服务列表发布到注册中心;客户端向注册中心订阅服务地址。
  2. 客户端:通过本地代理模块 Proxy 调用服务端,Proxy 模块收到负责将方法、参数等数据编码转化成网络字节流;从服务列表中选取其中一个的服务地址,并将数据通过网络发送给服务端
  3. 服务端:接收到数据进行解码,得到请求信息;根据解码后的请求信息调用对应的服务,然后将调用结果返回给客户端;服务端和客户端的编解码是逆向的。

3、各组件的职责

3.1 一次 RPC 调用流程:

一次 RPC 调用流程.png

  1. 服务消费者(Client 客户端)通过本地调用的方式调用服务。
  2. 客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体。
  3. 客户端存根(Client Stub)找到远程的服务地址,并且将消息通过网络发送给服务端。
  4. 服务端存根(Server Stub)收到消息后进行解码(反序列化操作)。
  5. 服务端存根(Server Stub)根据解码结果调用本地的服务进行相关处理
  6. 服务端(Server)本地服务业务处理。
  7. 处理结果返回给服务端存根(Server Stub)。
  8. 服务端存根(Server Stub)序列化结果。
  9. 服务端存根(Server Stub)将结果通过网络发送至消费方。
  10. 客户端存根(Client Stub)接收到消息,并进行解码(反序列化)。
  11. 服务消费方得到最终结果。

3.2 注册中心

注册中心的存在是为了更好更方便的管理应用中的每一个服务,是各个分布式节点之间的纽带。注册中心主要提供以下核心功能:

Image.gif

  • 服务注册与发现:动态的增减服务节点,服务节点增减后动态的通知服务消费者,而不需要由消费者来更新配置。服务的实例列表发生变化(新增或者移除)时,通知订阅该服务的 Consumer,从而让 Consumer 能够刷新本地缓存。
  • 服务配置:动态修改服务配置,并将其推送到服务提供者和服务消费者而不需要重启服务。
  • 健康检查和服务摘除:主动的检查服务健康情况,对于宕机的服务将其摘除服务列表,Server超过一定时间未心跳时,从服务的实例列表移除.客户端长时间没有心跳也可以关闭连接。

3.2.1 CAP理论

CAP理论是分布式架构中重要理论

  • 一致性(Consistency) (所有节点在同一时间具有相同的数据)
  • 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
  • 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)

由于C与A的特性无法共存.CAP 不可能都取,只能取其中2个,要么AP要么CP

3.2.2 微服务架构中常见的注册中心

Zookeeper Zoopkeeper 在国内很长一段时间都是注册中心一哥.大部分是因为Dubbo 在国能的盛行.

Eureka Eureka是一家在线影片租赁提供商Netflix开源的, 这家公司的理念还是满超前的.

Nacos Nacos 是阿里开源的, 功能其实也很多, 服务注册, 配置管理, 动态 DNS 服务, 元数据管理

3.3 客户端Client

服务端其实包括了两个部分:一部分是接口定义或者叫契约,对客户端提供的其实只是提供的服务契约,让客户端知道请求和返回信息;另一部分是服务真正的实现。就跟我们在本地开发Service一样,会先定义Interface然后再写impl实现。服务端的做法其实和接口和实现分离十分类似。

客户端并不关心也不需要知道服务端的具体实现,只需要服务端对外暴露需要的接口规范。客户端要做的事情有:

  • 实现RPC协议,把请求和响应正确的编解码并传输到服务端或者从服务端接收响应,实现序列化或者反序列化
  • 实现服务发现,服务端必须知道真正要调用的服务的实现,当然这个逻辑需要通过动态代理来进行统一封装,这样才能在实际调用的时候实现无感知,一般契约和具体的实现会通过一个类似URL的唯一标识进行绑定
  • 以及负载均衡,必须能够拉取到服务端信息,并通过一定的负载均衡策略选择服务端实例来提供服务,具体负载均衡策略可以参考【5】

3.4 服务端Server

Server端要实现的工作有:

  • 加载服务,并缓存启动服务注册
  • 对外暴露接口
  • 本地调用具体实现
  • 和客户端一样实现RPC协议,完成编解码序列化反序列化等工作 因此实现RPC一些这一部分一般都会单独做成一个模块,然后客户端和服务端就不用分别再去做这部分工作了。

4、简单对比 RPC 和 Restful API

面对对象不同:RPC 更侧重于动作。Restful 的主体是资源
RESTful 是面向资源的设计架构,但在系统中有很多对象不能抽象成资源,比如登录,修改密码等而 RPC 可以通过动作去操作资源。所以在操作的全面性上 RPC 大于 RESTful。
传输效率:RPC 效率更高。RPC,使用自定义的 TCP 协议,可以让请求报文体积更小,或者使用 HTTP2 协议,也可以很好的减少报文的体积,提高传输效率。复杂度:RPC 实现复杂,流程繁琐。REST 调用及测试都很方便。

RPC 实现需要实现编码,序列化,网络传输等。而 RESTful 不要关注这些,RESTful 实现更简单。灵活性:HTTP 相对更规范,更标准,更通用,无论哪种语言都支持 HTTP 协议。RPC 可以实现跨语言调用,但整体灵活性不如 RESTful。

总结:RPC 主要用于公司内部的服务调用,性能消耗低,传输效率高,实现复杂。、

HTTP 主要用于对外的异构环境,浏览器接口调用,App 接口调用,第三方接口调用等。

RPC 使用场景(大型的网站,内部子系统较多、接口非常多的情况下适合使用 RPC):

  1. 长链接。不必每次通信都要像 HTTP 一样去 3 次握手,减少了网络开销。
  2. 注册发布机制。RPC 框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作。
  3. 安全性,没有暴露资源操作。
  4. 微服务支持。就是最近流行的服务化架构、服务化治理,RPC 框架是一个强力的支撑。

【参考】

【1】如何手撸一个较为完整的RPC框架
【2】RPC基本原理以及如何用Netty来实现RPC
【3】花了一个星期,我终于把RPC框架整明白了!
【4】谈一谈我所理解的微服务中的注册中心
【5】rpc之负载均衡

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。