关于Rest和RPC

在设计API的时候,很多人会拿 REST 与 RPC 相比较,发现自己对这两者并不是很理解,于是查阅了网上相关资料加上自己的理解写下本篇文章以加深印象。

什么是REST

表现层状态转换(Representational State Transfer,缩写:REST)源自Roy Thomas Fielding博士于2000年发表的博士论文,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。表现层状态转换是根基于超文本传输协议(HTTP)之上而确定的一组约束和属性,是一种设计提供万维网络服务的软件构建风格。符合或兼容于这种架构风格(简称为 REST 或 RESTful)的网络服务,允许客户端发出以统一资源标识符访问和操作网络资源的请求,而与预先定义好的无状态操作集一致化。因此表现层状态转换提供了在互联网络的计算系统之间,彼此资源可交互使用的协作性质(interoperability)。相对于其它种类的网络服务,例如SOAP服务,则是以本身所定义的操作集,来访问网络上的资源。

REST架构

一套理想的、完全满足REST风格的系统应该满足以下六大原则:

  1. 客户端-服务器分离(Client-Server)
    客户端-服务器结构限制的目的是将客户端和服务器端的关注点分离。将用户界面所关注的逻辑和数据存储所关注的逻辑分离开来有助于提高用户界面的跨平台的可移植性。通过简化服务器模块也有助于服务器模块的可扩展性

  2. 无状态(Stateless)
    无状态是REST的一条核心原则,服务器不能保存客户端的信息;每一次从客户端发送的请求中,要包含所有的必须的状态信息,会话信息由客户端保存,服务器端根据这些状态信息来处理请求。
    客户端承担状态维护职责后,可能会产生一些新的问题,比如身份认证授权等可信问题,需要一些针对性的解决方案。
    服务器可以将会话状态信息传递给其他服务,比如数据库服务,这样可以保持一段时间的状态信息,从而实现认证功能。

  3. 可缓存(Cacheability)
    使用无状态的设计原则可能会需要多次请求,或者在请求中带有额外的冗余信息。如同万维网一样,客户端和中间的通讯传递者可以将回复缓存起来,管理良好的缓存机制可以减少客户端-服务器之间的交互,甚至完全避免客户端-服务器交互,这进一步提了高性能和可扩展性。

  4. 统一接口(Uniform Interface)
    这是 RESTful 系统设计的另一条核心原则。它简化了系统架构,减少了耦合性,可以让所有模块各自独立的进行改进。包括下列四个限制:

    • 请求中包含资源的 ID(Resource identification in requests)
    • 请求中包含了各种独立资源的标识,例如,在Web服务中的URI。资源本身和发送给客户端的标识是独立。例如,服务器可以将自身的数据库信息以HTML、XML或者JSON的方式发送给客户端,但是这些可能都不是服务器的内部记录方式。
    • 资源通过标识来操作(Resource manipulation through representations)
      当客户端拥有一个资源的标识,包括附带的元数据,则它就有足够的信息来删除这个资源。
    • 消息的自我描述性(Self-descriptive messages)
      每一个消息都包含足够的信息来描述如何来处理这个信息. 例如,媒体类型 (media-type) 就可以确定需要什么样的分析器来分析媒体数据.
    • 用超媒体驱动应用状态(Hypermedia as the engine of application state (HATEOAS))
      同用户访问Web服务器的Home页面相似,当一个 REST 客户端访问了最初的REST应用的URI之后,REST 客户端应该可以使用服务器端提供的链接,动态的发现所有的可用的资源和可执行的操作。随着访问的进行,服务器在响应中提供文字超链接,以便客户端可以得到当前可用的操作。客户端无需用确定的编码的方式记录下服务器端所提供的动态应用的结构信息。
  5. 分层系统(Layered System)
    客户端一般不知道是否直接连接到了最终的服务器,或者是路径上的中间服务器。中间服务器可以通过负载均衡和共享缓存的机制提高系统的可扩展性,这样可也便于安全策略的部署。

  6. 按需代码(Code-On-Demand,可选)
    服务器可以通过发送可执行代码给客户端的方式临时性的扩展功能或者定制功能,例如Java Applet、Flash或JavaScript。

REST的优点

  • 可更高效利用缓存来提高响应速度
  • 通讯本身的无状态性可以让不同的服务器的处理一系列请求中的不同请求,提高服务器的扩展性
  • 浏览器即可作为客户端,简化软件需求
  • 相对于其他叠加在HTTP协议之上的机制,REST的软件依赖性更小
  • 不需要额外的资源发现机制
  • 在软件技术演进中的长期的兼容性更好

REST的不足

  • REST 与 HTTP 完全绑定,不适合应用于要求高性能传输的场景中
  • REST 没有传输可靠性支持
  • REST 难以应对复杂的业务逻辑,缺乏对自然进行”部分”和”批量”处理的能力

目前,一种理论上较优秀的可以解决以上这几类问题的方案是GraphQL

什么是RPC

分布式计算中,远程过程调用(英语:Remote Procedure Call,RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。

进程间的通信

不可否认,RPC 出现的最初目的就是为了让计算机能够与调用本地方法一样调用远程方法
程序分布在不同的地址空间里。如果在同一主机里,RPC可以通过不同的虚拟地址空间(即便使用相同的物理地址)进行通讯,而在不同的主机间,则通过不同的物理地址进行交互。

如何表示数据

无论是讲参数传递给另外一个进程,还是从另外一个进程中取回执行结果,都涉及数据的序列化反序列化问题,常见的有:

  • Java RMI 的 Java 对象序列化流协议
  • gRPC 的 Protocol Buffers
  • Web Service 的 XML 序列化
  • 众多轻量级 RPC 支持的 JSON 序列化

如何传递数据

  • HTTP协议
    A服务器的应用可以通过HTTP将数据传输到B服务器,B服务器接收到数据后执行数据中调用的指定方法、函数,例如谷歌的gRPC就是在HTTP上进行数据传输的。但是由于HTTP报头中有太多不需要的信息造成带宽的浪费,所以很多人都是用比HTTP传输效率高的TCP、UDP进行数据传输。
  • TCP、UDP
    例如著名的Netty就是基于TCP、UDP上进行传输的,当然你也可以不使用框架,自己编写Socket实现网络数据传输。

如何表示方法

  • 同步调用
    A服务器的应用调用B服务器上应用的方法、函数后,A服务器的应用会处在阻塞状态,只有等到B服务器上的应用通过网络返回结果后,A服务器的应用才会继续往下执行。
  • 异步调用
    A服务器的应用调用B服务器上应用的方法、函数后,A服务器的应用并不会进入阻塞状态等待结果的返回,可以通过回调通知等方式获得返回的结果。

对比和区别

其实,REST 无论是在思想上、概念上还是在使用范围上,跟 RPC 都不尽相同,只能算是有一点相似。

  • REST 和 RPC 从思想上差异的核心是抽象的目标,RPC 是面向方法的 ,而 REST 是面向资源的。
  • REST 和 RPC 在概念上的不同是指 REST 它不是一种协议(协议都带有一定的规范性和强制性),只是一种软件架构风格,尽管有一些指导规则,并不受任何强制的约束。
  • 至于使用范围,REST 和 RPC 都常用于微服务架构中,作为主流的两种远程调用方式,REST 接口更加规范,通用适配性要求高,建议对外的接口都统一成 REST,而组件内部的各个模块,可以选择 RPC。