gRPC vs REST:两种API架构风格的对比

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"想知道未来是不是gRPC的天下?本文会具体介绍两种API架构风格:REST和gRPC,并讨论它们之间的区别。不过,首先,我们会解释什么是API,以及为什么它对微服务基础设施而言至关重要。之后,我们会介绍gRPC的基础——RPC,并探讨gRPC和REST API之间的重要差异。根据它们的对比结果,我们最后会分析什么时候应该使用哪种架构类型。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"API是什么"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"API,即应用程序编程接口。这些接口充当软件中介,为应用程序之间的交互和对话建立特定的定义和规则。API负责将响应从用户传递到系统,然后从系统返回给用户。听起来还是有点糊涂?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/60\/60372699d270a9261f9224438d37cdfb.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"API的工作机制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假设我们正在预订一个酒店。我们在笔记本电脑上访问酒店预订页面,连接到互联网的这个页面会将数据(我们的请求)发送到服务器。然后,服务器检索数据,解析它,一旦所需的操作得到执行,它就会向我们发送一个响应,并在我们的界面上提供信息。这个过程需要API才能实现。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"API 指定了一个应用程序(网页或移动应用)可以向另一个应用程序发出的请求类型,并进一步确定:如何发出这些请求;使用哪些数据格式;以及用户必须遵循的实践。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文会对比gRPC 和REST 两大架构风格,因为它们代表了人们创建API时最常用的两种架构风格。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"API和微服务"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一方面,在单体应用程序中,项目的所有功能都包含在一个单元中,更准确地说是包含在一个代码库中。另一方面,微服务架构由一些较小的服务组成,这些服务使用HTTP等协议相互通信。作为微服务架构一部分的组件服务通过API相互通信和交互。换句话说,API允许集成到微服务应用程序中的所有服务互相连接和通信。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最常用的架构风格是REST API。但构建API时主要有3种模型:RPC(远程过程调用)、REST(表征状态传输)和GraphQL。在本文中,我们将重点介绍前两个。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什么是RPC?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RPC使用客户端-服务器模型。请求服务器(换句话说就是客户端)请求一条消息,该消息由RPC转换并发送到另一台服务器。服务器收到请求后将响应发送回客户端。当服务器处理这个调用时,客户端被阻塞,服务器内部的消息传递被隐藏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此外,RPC允许客户端以特定格式请求函数,并以完全相同的格式接收响应。在URL中可以找到使用RPC API提交调用的方法。RPC支持本地和分布式环境中的远程过程调用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"与REST API一样,RPC还建立了交互规则以及用户如何提交“调用”(请求)以调用方法与服务通信和交互的机制。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什么是REST?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用REST API时,来自后端数据的响应通过JSON或XML消息格式传递给客户端(或用户)。这种架构模型倾向于遵循HTTP协议。然而,在维护RCP模型的同时,RCP设计也时常从HTTP中汲取一些想法。事实上,不管使用的是哪种模型(RPC或REST),大多数现代API实现都将API映射到相同的HTTP协议时。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当REST API公开可用时,每个集成微服务应用程序的服务都可以作为资源呈现给用户\/客户端,资源可以通过以下HTTP命令访问:"},{"type":"codeinline","content":[{"type":"text","text":"GET"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"DELETE"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"POST"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"PUT"}]},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什么是gRPC?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"gRPC是Google Remote Procedure Call的简写,是基于RCP架构的变体。该技术遵循一个使用HTTP 2.0协议的RPC API实现,但HTTP不会呈现给API开发人员或服务器。因此,开发人员无需担心RPC概念如何映射到HTTP,从而降低了复杂性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"总的来说,gRPC旨在加快微服务之间的数据传输。它的基础方法是确定一个服务,建立方法和相应的参数来实现远程调用和返回类型。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此外,它以"},{"type":"text","marks":[{"type":"strong"}],"text":"一个IDL(接口描述语言)表示RPC API模型"},{"type":"text","text":",这为确定远程过程提供了更直接的方法。默认情况下,IDL使用"},{"type":"text","marks":[{"type":"strong"}],"text":"Protocol Buffers"},{"type":"text","text":"(但也可以使用其他替代方案)来描述服务接口以及负载消息的结构。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"gRPC与REST:对比"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"现在,我们对gRPC和REST有了一个初步认识,下面我们来看看它们的主要区别。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"HTTP 1.1 vs HTTP 2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"REST API遵循一个通常基于HTTP 1.1构建的"},{"type":"text","marks":[{"type":"strong"}],"text":"请求-响应通信模型"},{"type":"text","text":"。不幸的是,这意味着如果一个微服务收到来自多个客户端的多个请求,该模型必须每次只处理一个请求,拖慢了整个系统的速度。REST API也可以构建在HTTP 2上,但通信的请求-响应模型保持不变,这使得REST API无法充分利用HTTP 2的优势,例如"},{"type":"text","marks":[{"type":"strong"}],"text":"流式通信"},{"type":"text","text":"和"},{"type":"text","marks":[{"type":"strong"}],"text":"双向支持"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"gRPC没有面临类似的障碍。它建立在HTTP 2之上,且遵循客户端-响应通信模型。这让它支持双向通信和流式通信,因为gRPC能接收来自多个客户端的多个请求,并通过不断地流式传输信息来同时处理这些请求。此外,gRPC还可以处理“一元”交互,例如构建在HTTP 1.1上的交互。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"总之,gRPC能处理一元交互和多种类型的流:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一元:客户端发出单个请求并接收单个响应。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服务器流:服务器对客户端的请求响应一个消息流。当全部数据发送完毕后,服务器会再发送一条状态消息来完成流程。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客户端流:客户端向服务器发送一个消息流,并接收单个响应消息。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"双向流:客户端和服务器的两个流互相独立,也就是说它们都能以任何顺序传输消息。客户端负责发起并结束双向流。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/15\/155a193c6cbba97475ed4bb8c4304093.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"流类型"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"浏览器支持"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这可能是REST相对于gRPC的主要优势之一。一方面,所有浏览器都完全支持REST。另一方面,gRPC获得的浏览器支持仍然非常有限。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不幸的是,它需要gRPC-web和一个代理层来执行HTTP 1.1和HTTP 2之间的转换。因此,gRPC主要用于内部\/私有系统(特定组织的后端数据和应用程序功能中的API程序)。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"负载数据结构"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如前所述,gRPC默认使用Protocol Buffers来序列化负载数据。这个方案更轻便,因为它支持高度压缩的格式并减少了消息的大小。此外,Protobuf(或Protocol Buffer)是二进制的;它对结构化数据进行序列化和反序列化,以便通信和传输。换句话说,强类型消息可以自动从Protobuf转换为客户端和服务器的编程语言。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比之下,REST主要依靠JSON或XML格式来发送和接收数据。事实上,即使它不强制要求任何结构,JSON也是最流行的格式,因为它具有灵活性和发送动态数据的能力,而不必遵循严格的结构。使用JSON的另一显著优势是其人类可读水平,这方面Protobuf尚无法与之竞争。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"尽管如此,JSON在数据传输方面并不够轻量或快速。其原因在于,在使用REST时,必须将JSON(或其他格式)序列化并转换为客户端和服务器端使用的编程语言。这在传输数据的过程中增加了一个额外步骤,从而可能会损害性能并增加出现错误的可能性。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"代码生成功能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"与gRPC不同,REST API不提供内置代码生成功能,这意味着开发人员必须使用Swagger或Postman等第三方工具为API请求生成代码。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比之下,gRPC由于其protoc编译器而具有原生代码生成功能,该编译器与多种编程语言兼容。这对于集成了以不同语言和平台开发的各种服务的微服务系统来说尤其方便。此外,内置的代码生成器还有助于创建SDK(软件开发工具包)。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"gRPC与REST:对比表"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2a\/2a885d8675c884668da19cafd345b487.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"何时使用gRPC,何时使用REST?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如前所述,尽管gRPC提供了许多优势,但它有一个主要障碍:浏览器兼容性低。因此,gRPC的用例一般局限在内部\/私有系统。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比之下,正如我们所讨论的那样,REST API可能有其缺点,但它们仍然是连接基于微服务的系统的最流行的API。此外,REST遵循HTTP协议标准化并提供通用支持,使这种API架构风格成为Web服务开发以及应用程序和微服务集成的首选。然而,这并不意味着我们应该忽视gRPC的应用场景。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"gRPC架构风格具有很多值得(并且应该)探索的有前途的特性。它是处理多语言系统和实时流的绝佳选择,例如,当运营需要轻量级消息传输(可以由序列化Protobuf消息支持)的IoT系统时,gRPC就很合适。此外,gRPC也可以考虑用于移动应用程序,因为它们不需要浏览器,且消息体积更小,不会拖慢移动设备的速度。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"结论"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"gRPC提供了很多优势。与REST不同,它可以充分利用HTTP 2,使用多路复用流并遵循二进制协议。此外,由于Protobuf消息结构,它还具备性能优势,支持多语言环境的内置代码生成功能也是一大好处。这些因素使gRPC成为了一种很有前途的API架构风格。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"尽管如此,浏览器支持不足使gRPC很难匹敌REST的通用支持能力。REST仍然是微服务系统中的粘合剂,是最流行的解决方案。因此它很可能会存在很长时间,而且说实话,它是一个非常成熟和成功的架构。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文链接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https:\/\/www.imaginarycloud.com\/blog\/grpc-vs-rest\/?fileGuid=3WQyP6YQDvcqhcXx"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章