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 年发布。
相关推荐
源代码•宸8 分钟前
GoLang八股(Go语言基础)
开发语言·后端·golang·map·defer·recover·panic
czlczl200209259 分钟前
OAuth 2.0 解析:后端开发者视角的原理与流程讲解
java·spring boot·后端
颜淡慕潇17 分钟前
Spring Boot 3.3.x、3.4.x、3.5.x 深度对比与演进分析
java·后端·架构
布列瑟农的星空17 分钟前
WebAssembly入门(一)——Emscripten
前端·后端
小突突突2 小时前
Spring框架中的单例bean是线程安全的吗?
java·后端·spring
iso少年2 小时前
Go 语言并发编程核心与用法
开发语言·后端·golang
掘金码甲哥2 小时前
云原生算力平台的架构解读
后端
码事漫谈2 小时前
智谱AI从清华实验室到“全球大模型第一股”的六年征程
后端
码事漫谈2 小时前
现代软件开发中常用架构的系统梳理与实践指南
后端
飞鸟真人2 小时前
关于python -m http.server的一些安全问题
python·安全·http