Go大师课程(六): gRPC 的秘密武器

Go大师课程系列将学习

为什么选择 gRPC?

让我们从这个简单的问题开始:gRPC 的动机是什么?或者说 gRPC 试图解决的问题是什么?

嗯,答案就是沟通。

应用程序使用不同的编程语言编写。

例如,后端可以用 Go 编写,而前端(例如,Android 应用程序用 Java 编写,iOS 应用程序用 Swift 编写)

则如何相互通信?

当今的趋势是使用微服务架构。因此,即使在后端,我们也可能有许多用不同语言(如 Go、Python 或 Rust)编写的服务,具体取决于业务需求和技术限制。

因此,为了相互通信,他们必须就一组 API 契约达成一致。例如:通信渠道、身份验证机制、有效负载格式、数据模型以及如何处理错误。

有很多事情需要考虑,这就是为什么构建 API 非常困难。

不仅如此,我们希望通信高效,也就是说,快速且轻量。你知道,微服务之间的交换消息数量非常庞大。因此,通信越快越好。

此外,在某些环境中,例如移动应用程序,网络速度和带宽有限,拥有轻量级的通信协议来与服务器交互非常重要。

最后但并非最不重要的一点是,我们希望通信简单。假设我们正在构建一个包含数百甚至数千个微服务的系统。我们肯定不想花费大部分时间编写代码只是为了让它们相互通信,对吧?

我们希望有某种框架,让开发人员专注于实现其服务的核心逻辑。其余一切都交给框架处理。

什么是 gRPC?它是如何工作的?

gRPC 是一个高性能、开源、功能丰富的 RPC 框架,最初由 Google 开发,现在是云原生计算基金会(或 CNCF)的一部分,就像 Kubernetes 或 Prometheus 一样。

好的,那么ggRPC 中的"什么"代表什么?起初我以为是 Google(是的,你知道为什么)。但事实上,它在每个 gRPC 版本中代表不同的东西,例如"好"、"绿色"、"辉煌",甚至"gRPC"本身。

那么 RPC 怎么样?RPC 代表远程过程调用。它是一种允许程序执行位于其他计算机的另一个程序的过程的协议。

最棒的是,开发人员无需明确编写网络交互的细节。这些都由底层框架自动处理。

因此,在客户端代码中,我们似乎只是直接调用服务器代码的函数。即使客户端和服务器上的代码是用不同的编程语言编写的,它也能正常工作。就像在这个例子中,客户端代码是用 Go 编写的,而服务器代码是用 Rust 编写的。

那么 gRPC 如何做到这一点?基本上,客户端有一个存根,它提供与服务器相同的方法(或功能)。该存根由 gRPC 自动为您生成。

存根将在后台调用 gRPC 框架通过网络与服务器交换信息。

多亏了存根,客户端和服务器现在只需要关心实现其核心服务逻辑。

gRPC 如何生成代码?

代码生成是 gRPC 最重要的功能之一。

为了为服务器和客户端生成存根,我们首先需要编写 API 契约,其中包括协议缓冲区文件中服务及其有效负载消息的描述,如下所示:

在这个文件中,定义了一个 Hello 方法,该方法以 HelloRequest 作为输入并返回 HelloResponse。HelloRequest 只包含一个字符串 name,HelloResponse 有一个字符串greet。

很简单,对吧?我们将在后面的 protobuf 实践讲座中学习更多有关此内容的详细信息。

从此 proto 文件中,协议缓冲区编译器 (或 protoc) 会生成服务器和客户端存根代码。根据编程语言,我们必须告诉编译器为其使用正确的 gRPC 插件。

Rust 和 Go 生成的代码如下所示:

好的,那么你可能想知道为什么 gRPC 使用协议缓冲区?嗯,原因有很多。

首先,它非常容易阅读和理解。

其次,它是一种可互操作的语言,支持多种语言的自动代码生成

第三,它以二进制格式表示数据,与 JSON 或 XML 等某些基于文本的格式相比,二进制格式体积更小、传输速度更快、序列化效率更高。

它在客户端和服务器之间提供了强类型的 API 契约,使用起来非常安全。

并且它有一套完善的 API 演进规则,以确保向后和向前的兼容性。

gRPC 的类型

gRPC 有 4 种类型:

最简单的是 Unary,客户端发送 1 条请求消息,服务器回复 1 条响应。这看起来有点类似于普通的 HTTP REST API。

然后我们有客户端流。在这种情况下,客户端将发送多条消息的流,并期望服务器仅发回 1 个响应。

类似地,我们有服务器流,其中客户端只发送 1 个请求消息,而服务器使用多个响应流进行回复。

最后是双向(或 bidi)流。这是最复杂的,因为客户端和服务器将继续并行地以任意顺序发送和接收多条消息。它非常灵活且无阻塞,这意味着任何一方都无需等待响应即可发送下一条消息。

这是对 gRPC 中 4 种不同通信方式的非常高层次的概述。

gRPC 与 REST

现在,让我们快速比较一下 gRPC 和 REST,看看它们的区别。

首先,gRPC 使用 HTTP/2,众所周知,它比 REST 默认使用的 HTTP/1.1 快得多。请注意,今天我们也可以在 REST 中启用 HTTP/2,但通常它通常与 HTTP/1.1 一起使用。您可以在以下文章中了解有关如何为 REST 启用 HTTP/2 的更多信息:

其次,gRPC 使用 Protocol buffer 来序列化 payload 数据,它是二进制且较小,而 REST 使用 JSON,它是文本且较大。

gRPC 中的 API 契约非常严格,需要在 proto 文件中明确定义。而在 REST 中,它通常是松散且可选的。我们可以通过 OpenAPI 定义它,但这不是强制性的。

gRPC 内置了代码生成功能,借助 protocol buffer 编译器。而在 REST 中,我们必须使用第三方工具,如 OpenAPI 和 Swagger。

gRPC 和 REST 通信均通过 TLS/SSL 保护。

在 gRPC 中,流式传输是双向的,而在 REST 中,从客户端到服务器的请求只有单向。

因此,在我们目前提到的大多数方面,gRPC 都比 REST 更好。不过,REST 仍然有一点更好,

这是浏览器支持。虽然所有浏览器都完全支持 REST,但对 gRPC 的支持有限,并且需要带有代理层的gRPC-web在 HTTP/1 和 HTTP/2 之间进行转换。

在哪里使用 gRPC?

因此,gRPC 有很多优点,但也有自己的弱点。那么,我们应该在何时何地使用 gRPC 才能充分利用它呢?

您可能已经猜到了,微服务是 gRPC 真正大放异彩的地方,因为它可以实现低延迟和高吞吐量通信,以及强大的 API 契约。

gRPC 也适用于多语言环境,因为它为许多编程语言提供了开箱即用的代码生成

点对点实时通信也是 gRPC 的优势所在,因为它对双向流式传输有出色的支持。

最后,由于 gRPC 具有轻量级消息格式,因此对于网络受限的环境(例如移动应用程序(android/ios))来说,它是一个很好的选择。

为什么选择 HTTP/2?

gRPC 使用 HTTP/2 作为其传输协议,因此它继承了 HTTP/2 提供的一些出色功能,例如二进制帧,与其他基于文本的协议相比,它性能高、稳健、传输更轻松、解码更安全。而且由于它是二进制的,因此它与协议缓冲区完美结合。

HTTP/2 还使用 HPACK 压缩标头,这将减少开销并提高性能。

HTTP/2 中可以实现多路复用,这意味着客户端和服务器可以通过单个 TCP 连接并行发送多个请求和响应。这将有助于减少延迟并提高网络利用率。

最后,HTTP/2 允许服务器推送,即客户端只需发出 1 个请求,服务器就可以发回多个响应。这在很多情况下对于减少客户端和服务器之间的往返延迟非常有用,因为服务器确切地知道客户端需要哪些资源,并且在客户端请求之前就发送这些资源。

让我们看看这个演示,看看 HTTP/2 与 HTTP/1.1 相比有多快。基本上在这个演示中,我们将尝试从服务器加载 200 张小图像

HTTP/2 的工作原理

那么,HTTP/2 内部是如何工作的呢?它的逻辑结构可以如下图所示表示:

一条 TCP 连接承载多个双向流。每个流都有唯一标识符 ,并承载多个双向消息

每条消息(可以是请求或响应)被分解为多个二进制帧。帧是承载不同类型数据的最小单位,例如 HEADERS、SETTINGS、PRIORITY、DATA 等。

实际上,这些流实际上并不是单独流动的,而是它们的帧在连接上交错,并在到达另一端时重新组装。得益于这个二进制帧层,HTTP/2 中可以实现流复用

HTTP/2 与 HTTP/1.1

好的,现在您已经了解了 HTTP/2 的工作原理。让我们与 HTTP/1.1 进行比较,看看它们之间的区别。

  • 首先,HTTP/2是二进制协议,而HTTP/1.1是文本协议。
  • HTTP/2 中的标头经过压缩,而 HTTP/1.1 中的标头为纯文本
  • HTTP/2 允许多路复用,HTTP/1.1 则不允许
  • 在 HTTP/2 中,我们可以在单个连接中发送多个请求和响应,而在 HTTP/1.1 中我们只能发送 1 个,这意味着我们必须创建多个 TCP 连接才能发送多个请求。
  • HTTP/2 可以实现服务器推送,但 HTTP/1.1 则不行
  • HTTP/2 于 2015 年刚刚发布,而 HTTP/1.1 于 1997 年发布。
相关推荐
ALex_zry2 小时前
Go核心特性与并发编程
开发语言·后端·golang
Kookoos2 小时前
ABP VNext + Orleans:Actor 模型下的分布式状态管理最佳实践
分布式·后端·c#·.net·.netcore·abp vnext
PWRJOY2 小时前
Flask 会话管理:从原理到实战,深度解析 session 机制
后端·python·flask
奕天者3 小时前
计算机网络学习(三)——HTTP
学习·计算机网络·http
述雾学java4 小时前
Spring Boot是什么?MybatisPlus常用注解,LambdaQueryWrapper常用方法
java·spring boot·后端
程序员buddha5 小时前
SpringBoot多环境配置文件切换
java·spring boot·后端
twj_one6 小时前
SpringBoot+ELK 搭建日志监控平台
spring boot·后端·elk
咖啡啡不加糖7 小时前
Sentinel原理与SpringBoot整合实战
spring boot·后端·sentinel
Leo Han7 小时前
apache http client连接池实现原理
网络协议·http·apache
悟能不能悟7 小时前
Spring Boot中如何对密码等敏感信息进行脱敏处理
spring boot·后端·python