一文读懂 gRPC 与 RPC,并优雅地掌握调试方式
什么是 gRPC?
gRPC 是一个由谷歌开发的现代开源高性能 RPC 远程过程调用( Remote Procedure Calls)框架,具备良好的兼容性,可在多个开发环境下运行。
gRPC 的应用场景
相较于目前主流的 HTTP API 接口,gRPC 接口采用了领先的 HTTP/2 底层架构设计作为底层传输协议,能够在大规模数据传输场景(例如视频流传输)和大量服务相互调用的微服务架构场景下大展身手。
数据交换采用轻量化的 Protobuf 序列化协议,使得它能够在资源受限场景(常见于手机等移动端设备)提供更快的数据处理速度的同时,减少网络传输的数据量并节省网络带宽,从而降低功耗并提升电池寿命。
在正式开始介绍 gRPC 之前,我们不妨先弄清楚到底什么是 RPC 以及它的作用,这对于后续的理解十分有帮助。
什么是 RPC ?
RPC 协议是一种远程过程调用的实现方式。假设现在有两台服务器 A 和 B。部署在 A 服务器上的服务,想调用正在 B 服务器上运行的另一个进程。但由于双方服务并不在一个内存空间而导致无法直接调用,那么就必须通过网络通讯来达到调用效果。

要建立网络通讯的无非是在传输层发起 TCP 连接。TCP 的握手机制确保了数据包能可靠地传输给对方,并且它具备以下三个特点:面向连接、可靠、基于字节流。前面两种特性都可以胜任这个场景,但唯独在基于字节流这一点恐怕值得商榷。为什么?
因为它没有边界。字节流本质上是在传输层双向通道中流淌的数据,也就是计算机能够理解的二进制 0 1 数据。所以当发送端使用 TCP 发送“南京市”+“长江大桥”字符时,接收端有可能收到的就是“南京市长”+“江大桥”,也有可能是“南京市长江大桥”等。
过于简单的 TCP 连接过程无法保证信息的唯一性和确定性,因此才需要在数据中定义消息头、消息体,并且发送方与接收方共同认可这套沟通方式,由此衍生出了 HTTP 协议和 RPC 调用等方案,它们本质上都是对数据的传递和调用方式作出了规范化定义,避免出现信息失真。
例如现在有一个购物网站,存在订单服务与用户服务(例如账号管理)两项微服务。订单服务需要使用函数查询到用户服务下的一些数据,但是两者相隔离。此时订单服务就必须通过远程调用方式获取数据。
下图的示例中,服务端(用户服务)仅需暴露出一个能够调用数据库的 getConsumerByld() 函数,客户端(订单服务)使用 RPC 便能够像在本地中直接调用 getConsumerByld() 函数并获取到所需的响应结果。RPC 成功隐藏了内部通信的复杂性,为双方提供了稳定统一的接口,使得开发者只需要关注业务逻辑,而无需关注底层网络通信细节。

RPC 的应用场景有哪些?
RPC 框架的应用场景非常广泛,特别是在微服务的分布式系统中。它可以用来实现不同进程之间的通信以及跨越不同的计算机硬件、操作系统和平台的通信。具体的应用场景包括:
- 微服务架构:在微服务架构中,每个服务通常都会运行在不同的进程中,通过 RPC 框架实现服务之间的调用和通信。
- 分布式系统中的数据同步:在分布式系统中,需要保证不同节点之间的数据一致性。通过 RPC 框架实现数据同步操作,可以确保在不同节点之间数据的同步更新。
- 面向服务的架构(SOA):在面向服务的架构中,各个服务通过互相调用和组合实现复杂应用场景,RPC 框架可以方便地实现不同服务之间的交互。
- 云计算和容器化部署:在云计算和容器化部署中,往往需要将不同的服务部署在不同的节点上,通过 RPC 框架实现不同节点之间的通信,可以提高系统的可伸缩性和可靠性。
而 gRPC 本质上就是一种由谷歌发布并开源的 RPC 框架。因此很自然拥有上述 RPC 框架的各个优势,面向的场景也是类似的。
gRPC 的优势有哪些?
先进的传输协议
HTTP/2 在同年较 gRPC 稍早前发布,因此 gRPC 很自然的将这一先进的传输协议作为底层基础,从而使得它具备更高效的传输性能,并且还能够支持流式调用,为许多实时数据传输场景(例如股票数据、语音通讯、游戏场景)提供支持,天然领先许多在千禧年之际发布的古早 RPC 框架。发起连接时会建立连接池,面对多条连接时能够显著提升网络请求性能。
科学的设计理念
同时 gRPC 采用了体积更小的 Protobuf 序列化协议保存结构体数据。Protocol Buffers 是一种跨语言、跨平台的数据结构序列化协议。相比 JSON 或 XML 协议,它更加轻量级,因此在传输数据时更加高效。同时这也决定了 gRPC 接口必定遵循 API First 理念,因为在开发工作开始前就需要在文件中定义服务接口,包含客户端如何使用服务、调用时所需传递的参数。gRPC 接口可以根据已定义的 .proto 文件自动生成客户端和服务端的通信方式,大大简化了开发过程。
良好的兼容性
gRPC 不依赖于任何特定的技术或语言栈,因此可以被广泛地应用到不同的开发环境之中。它支持多种编程语言,包括 Java、C++、Python、Go 等现代流行的编程语言。它可以在轻松地不同语言之间进行通信,这为多语言的微服务架构提供了有力支持。

虽然 gRPC 有着许多优势,但是大部分外部使用者对于 HTTP 接口更加熟悉(这也导致了 gRPC 的生态繁荣度并不如 REST/HTTP 协议),因此 gRPC 主要的应用场景是团队内部微服务间的通讯与连接,并不适合将服务公开至外部使用。并且若想要成功调用 gRPC,还可能涉及到内部系统的参数传递过程。另一个比较大的缺点便是浏览器并不支持 gRPC 服务调用,需要借助扩展或专业的接口调用工具(比如说 Apifox)才能进行接口协作。

Apifox 现已上线 gRPC 接口调试功能
目前市面上能够兼容 gRPC 接口的接口调试与管理工具十分有限,而 gRPC 现已广泛应用于微服务架构中,并且可以预见的是,它会变得越来越流行。作为业界领先的接口管理工具,Apifox 现已上线 gRPC 接口调试和管理能力,全面兼容以下四种调用类型:
- Unary:一元调用
- Server Streaming:服务端流
- Client Streming:客户端流
- Bidirectional Streaming:双向流
下文将通过一个示例场景简要演示如何在 Apifox 中新建 gRPC 项目并针对接口发起调试。
gRPC 接口管理功能要求 Apifox 版本号大于等于 2.3.0 。在 Apifox 中点击“新建项目”按钮,选择 gRPC 类型,填写项目名称后轻点“新建”按钮。

导入定义 gRPC 接口所使用的服务、方法和消息的 .proto 文件。你可以将文件拖拽至其中或使用文件在线 URL 完成导入。

Apifox 将基于 .proto 文件内容生成对应的接口信息。示例接口中自带了一元调用、服务端流、客户端流和双向流四种调用方法。

发起一元调用
一元调用指的是在一个请求中发送一个消息,并接收一个消息作为响应。相较于 JSON ,gRPC 使用 Protocol Buffers(ProtoBuf)作为默认的序列化框架,可以更加紧凑地表述数据,提升传输速度。并且 gRPC 使用 HTTP/2 作为底层传输协议,直接应用 HPACK 压缩算法对 Header 中的信息进行处理,在网络传输中减少了头部的大小,从而节省了带宽资源。这对于传输小型数据或需要实时响应的场景十分友好。
选择 SayHello 方法,在接口地址中填写 grpcb.in:9000。然后点击“自动生成”按钮生成请求体,轻点“调用”即可查看返回响应。

在 Apifox 中,你可以非常便捷地将接口地址提取至“环境”,以便团队内的其它成员或项目中的其它接口发起调用请求。

发起流式调用
服务端流、客户端流和双向流都被被称为流式调用。它允许客户端和服务器之间建立一个持久的双工流式连接,并通过流式传输来进行数据的读取和写入。流式调用的主要特点是可以在一个连接上发送和接收多个消息,支持持续交互和大规模数据传输,常用于交易所股票数据、视频语音通讯与在线游戏场景。
服务端流
正如同它在图标中所表示的意思一样,服务端流表示:一次发送,返回多个响应数据。例如订阅一分钟之内的所有股票的成交价格数据。

客户端流
在这种模式下,客户端可以连续地发送多个请求消息给服务器,而不需要等待服务器的立即响应。发起调用后,你可以持续在 Message 中持续填写请求信息,然后点击“发送”按钮。服务器在处理完所有请求后,发送一个单独的响应消息给客户端。

双向流
双向流允许客户端和服务器之间建立持久的双向通信,并可以同时传输多个消息。常见于在线游戏与实时视频通话软件,适用于实时通信和大规模数据传输场景。发起调用后客户端与服务端之间将持续保持会话,发送不同的请求内容后实时获得响应。

gRPC 接口协作
Apifox 能够基于 .proto 文件渲染出更适合人类阅读的 gRPC 接口文档,使得接口更容易在团队中进行协作。你可以点击接口右侧的菜单按钮获取协作链接,将它分享给其它团队成员对齐接口的调试方法。

Apifox 的 gRPC 接口调试功能正处于 Beta 公开测试阶段,目前的功能只是我们迈出的第一步,后续也会持续迭代更新。Apifox 作为 API 一体化协作平台,希望为不同的 API 技术提供同样优秀的体验。
想要了解更多 gRPC 相关内容可以前往帮助文档查看。