使用 Google Cloud 了解松耦合架构和消息传递服务
本文将围绕谷歌云(以前称为 GCP)的 Pub/Sub 来讲解松散耦合架构。
介绍
什么是松耦合架构
本文中,松耦合架构特指“使用消息传递服务将系统松散地连接起来,实现系统间消息协调"。
在谷歌云中,这意味着以下架构。
图中左侧的 “图像上传API” 接受系统用户上传的图像,并将图像文件的原始数据存储在 “图像存储(转换前)” 中。然后,它向图中央的信息队列提交请求处理图像转换的信息。当图表右侧的 “图像转换处理” 从消息队列中找到任务请求时,就会对图像应用规定的转换流程,然后将其存储到 “图像存储(转换后)” 中。
图像上传和转换图像这种不通的任务,分别由不同的系统(服务)分担。
作为比较,市场份额最大的公共云亚马逊网络服务(AWS)的配置图也显示了类似的架构。
随着 "无服务器架构 "和 "微服务架构 "越来越常见,这种松耦合架构也越来越理所当然地被理解。本文将讨论此类架构。我们希望本文能帮助您理解这些架构。
异步处理
同步和异步
理解松耦合架构的一个重要部分是 同步处理和异步处理之间的区别。
请注意,我们在这里讨论同步和异步处理时,并不是专门针对编程,而是针对 Web API 的请求和响应(尽管它们本质上是相同的)。
同步处理
同步处理是指客户端向 API 提出处理请求,然后等待预期响应返回后再进行下一步处理的方法。
例如,gcloud 命令用于显示 Cloud Storage 桶中的对象列表。
命令一经执行,就会得到一个对象列表(预期处理结果),然后就可以对命令行进行操作。这是一个同步过程。举个例子,想象一下 Google Cloud 查询类的 API 请求,你就会发现大多数查询 API 都是同步流程。
异步处理
另一方面,异步处理是一种作业请求不会立即返回预期的处理结果,而只是接受处理,并在稍后检索结果的方法。
假设您有一个图像处理系统。当您指定一个图像文件并告诉它开始处理时,得到的只是一条"处理已接受"的信息和一个处理过程的唯一标识 ID。由于图像处理需要几分钟的时间,因此有必要经常查询系统,查看 ID 是否已处理完毕。这种处理方式属于异步处理。
处理开始的第一个请求可表述为任务提交。
松耦合架构和异步处理
使用消息传递服务构建的松耦合架构,可以说就是为了实现异步处理的架构。
这种结构包括作业请求者(作业提交者)和作业执行者(作业处理者),而消息传送服务则充当两者之间的中介。
无论如何,作业请求者都会将作业提交到消息队列。作业执行者的工作就是处理消息队列中的作业。
优势
为什么需要消息队列服务
在上图所示的架构中,左边的系统(如系统 A)和右边的系统(如系统 B)都包含云 Pub/Sub 和亚马逊 SQS 等消息传递服务,即在系统之间转发消息的服务。
对于初次接触这种配置图的人来说,会产生以下问题?
- 为什么要在两者之间使用 Pub/Sub?直接从系统 A 向系统 B 发送信息不是更快吗?
- 又或者是,如果将 A 系统和 B 系统合并为一个系统,速度岂不是会更快?
不过,在系统间插入信息服务也有明显的优势。具体表现如下
- 增强可扩展性
- 提高可维护性
- 提高可用性
增强可扩展性
其中一个优势是提高了可扩展性。
通过在中间插入消息服务,可以将工作请求方系统 A 和工作执行方系统 B 分离为两个独立的系统。这就意味着,例如 "最近,单个转换处理的工作量变大了,所以我只想提高系统 B 的处理能力。这样就可以提高系统扩展的灵活性。
如果系统 A 和系统 B 是在一台服务器上运行的单一系统,就不可能实现如此灵活的吞吐量扩展。
提高可维护性
另一个好处是提高了可维护性。
将请求工作的系统 A 和执行工作的系统 B 分离开来,作为单独的系统,可以减少计划修改时的影响范围。
在业务变化日新月异的今天,提高系统的可维护性和增加部署频率是可取的。可以说,可维护性的提高会带来商业利益。
这也可以表述为提高模块独立性。将作业请求方和作业接收方的模块分开可提高模块强度,将作业描述作为"消息 "进行交换可降低模块耦合度。这就提高了可维护性。
提高可用性
另一个不容忽视的好处是提高了可用性。
如果系统 A 和系统 B 是一个系统,那么一旦系统发生故障,两个系统都将停止运行。
但是,如果这些是独立的系统,例如,如果系统 A 停止工作,系统 B 可以继续完成已经申请的工作,反之亦然,它只能继续接受工作。
为什么更适合云?
为什么松耦合架构在 AWS 和 Google Cloud 等平台非常常见,被认为是 “亲云架构”?
这种架构本身可以在企业内部自由环境中实现,事实上,像 IBM MQ 这样的消息传递软件已经存在了几十年。
这种架构在云中使用最多,因为上述可扩展性优势在云中可以更有效,更容易地实现。
在公共云中,虚拟服务器和容器等计算资源可以通过调用 API 以编程方式即时增加。在上述例子中,如果只需要增加系统 B,就可以根据负载情况,只需按一下按钮,甚至不用按按钮,就能自动增加资源。
换句话说,松耦合架构本身并不是云所独有的,但却是一种特别容易在云中受益的架构。
用语
组件术语
在具有消息服务的松散耦合架构中,出现的组件(或角色)的角色可大致分为"任务请求实体"、“任务中介实体"和"任务处理实体”。
在许多情况下,请求作业的实体被称为生产者(Producer)。这是因为它是作业或信息的生产侧。
中介调解工作的实体称为队列(queue)。
处理作业的实体称为消费者(Consumer)。这是因为它消耗(消费)并处理作业和消息。
行为术语
pull(拉) 和 push(推)
生产者(Producer)生成的信息可以通过多种途径到达消费者(Consumer)。
有两种方法可以做到这一点:pull 方法,即消费者轮询队列以检索消息;push 方法,即消息直接传递给消费者。我们可以根据流程和程序的性质,选择合适的方法。
### FIFO (message ordering) :先进先出(报文排序)
队列的另一个特性是 FIFO 这个术语,它代表 First-In First-Out,也被表述为"先进先出" 。
在典型的报文传送服务中,报文不是先进先出的,经常会出现顺序错乱的情况。有些服务可选择配置为保证先进先出,启用先进先出可确保信息以正确的顺序出现。不过,一般来说,启用先进先出机制后,报文吞吐量(在给定时间内可传送的报文数量)会降低。
也可以使用另一个术语,如报文排序,来代替 FIFO。
At-least-once (至少一次传送)
在典型的报文传送服务中,报文传送具有 at-least-once (至少一次传送)的性质。
该术语指的是信息至少被传递一次的特性,但反过来说,信息也可能被传递多次。这是由于消息传递服务是分布式系统,而且由于临时网络故障或延迟,消息的 ack(对已收到消息的回应)可能无法正常传送。
为了防止出现系统范围内的故障,即使同一信息被传递了多次,也有必要在设计处理过程时确保无论消费者执行多少次相同的处理,所产生的状态都是相同的。这种即使多次执行处理,结果也相同的特性被称为幂等性。在分布式系统和异步处理成为常态的现代 IT 中,它被视为一个重要的概念。
某些服务可能会提供一次性(一次性交付)选项;与 FIFO 一样,启用该选项通常会降低吞吐量。
架构术语
广义上的Pub/Sub
虽然引入了生产者(Producer)、队列(queue)和消费者(Consumer)等术语,但对于非常相似的架构可能会使用不同的术语。
发布/订阅方式,有时缩写为 Pub/Sub 方式,与谷歌云服务的 Cloud Pub/Sub 不同,后者是谷歌云的一项服务。
Pub/Sub 方式指的是单个消息队列有多个订阅者的配置。
在这种情况下,生产者被称为 Publisher (发布者),队列被称为 Topic (主题),消费者被称为 Subscriber (订阅者)。
Fan-out (扇出)
在本文开头介绍的图像处理系统中,图像转换任务提交后,只需其中一个用户(消费者)处理该任务即可。
但是,在其他情况下,您可能希望同时向不同的用户组发送信息。在某些情况下,您可能希望同时向两个不同的用户组发送信息。
将信息同时发送给多个订阅者的结构称为扇出(Fan-out)。这里的 Fan 是 "扇形 "的意思,因为信息像扇形一样散开。
在谷歌云的 Cloud Pub/Sub 中,上述 Fan-out 架构是通过为单个主题创建多个"订阅资源"(主题的 "出口"角色)来实现的。而在 AWS 中,则是通过结合 Amazon SNS 和 Amazon SQS 来实现。
- 参考:Google Cloud - 构建一对多 Pub/Sub 系统
- 参考:AWS - 常见的亚马逊SNS场景
谷歌云中的松耦合架构
关键服务 Pub/Sub
在谷歌云中,Cloud Pub/Sub 是松散耦合架构中的一项关键服务。
Pub/Sub 是一种完全托管的消息传递服务,完全不需要基础设施管理。它具有高度可扩展性,允许以发布者/订阅者格式发送异步消息。
与 AWS 的比较
对于熟悉 AWS 的人来说,Pub/Sub 可被描述为"Amazon SNS 与 Amazon SQS 和 Amazon Kinesis Data Streams 的结合"。
Pub/Sub 可以处理像 Amazon SNS 这样的推送/扇出消息,也可以处理像 Amazon SQS 这样的拉(轮询)类型消息。
Pub/Sub 还具有类似 Amazon Kinesis Data Streams 的流缓冲功能。Pub/Sub 可以处理大量吞吐量,消息数据字段的最大可达到 10 MB。
与 Amazon EventBridge 也存在角色重叠,因为它被用作 Eventarc 的后端,以交付由各种谷歌云服务触发的事件。
总之,Pub/Sub 可用于 AWS 的以下用例,如果是 AWS 服务,您应从 Amazon SNS、Amazon SQS、Amazon Kinesis Data Streams、Amazon EventBridge 等服务中选择合适的服务。
用例 | AWS 服务 | 谷歌云服务 |
---|---|---|
任务的异步和并行处理 | Amazon SQS | Cloud Pub/Sub |
捕捉用户操作和服务器事件 | Amazon Kinesis Data Streams | Cloud Pub/Sub |
物联网数据流 | Amazon Kinesis Data Streams | Cloud Pub/Sub |
执行事件驱动处理(事件总线) | Amazon EventBridge | Cloud Pub/Sub |
※表中的服务名称仅为示例,实际中可能会使用其他服务
Cloud Pub/Sub vs Cloud Tasks
除了 Cloud Pub/Sub,Google Cloud 还有 Cloud Tasks 作为消息传递和异步处理产品。
Cloud Pub/Sub 和 Cloud Tasks 是非常相似的服务,它们都有内部队列和异步处理发布者请求的功能,但想定的架构不同。
Cloud Pub/Sub 采用松散耦合架构,将发布者和订阅者分开,而 Cloud Tasks 则明确调用订阅者,并允许订阅者控制处理过程。关键的一点是,订阅者可以明确调用订户并控制订户的处理。此外,还可以管理交付时间和速率。更多信息,请参阅以下文档。
架构示例
数据的并行处理
这就是本文开头引用的架构。
左侧的系统接受用户上传的图像,将图像上传到云存储,然后向 Pub/Sub 提交一条信息。信息中包含存储桶名称和图像文件的路径。右侧的系统会轮询 Pub/Sub(订阅),并在其中一个 pod(订阅者)收到消息时处理目标图像。
当大量 Pod(订阅者)处理一个接一个提交的作业时,可以保持高吞吐量。
发布者(左侧)和订阅者(右侧)分别是谷歌 Kubernetes 引擎 pod,具有高度可扩展性。
无服务器
无服务器架构尤其体现了高可扩展性。无服务器架构和松散耦合架构密不可分。
有关无服务器架构基础知识的更多信息,请参阅以下文章
- 了解使用谷歌云的无服务器架构(待续)
与其他云服务集成
消息传递服务(如 Pub/Sub)通常用于云服务之间的集成。
上图说明了如下流程。列表编号与图中的编号相对应。
-
当视频文件放入 Cloud Storage 时,就会触发 Cloud Functions(事件驱动)。
-
Cloud Functions 向 Transcoder API(完全托管的视频转换服务)提交异步任务
- 指定原始视频文件的路径和转换后视频文件的输出 Cloud Storage 路径。
-
Transcoder API 根据给定的参数从 Cloud Storage 中检索原始视频文件,并执行转换过程。
-
视频转换过程结束后,Transcoder API 会将转换后的视频文件放到一个单独的 Cloud Storage 中。
-
Transcoder API 通知 Pub/Sub 任务完成
-
另一个订阅了 Pub/Sub 的 Cloud Functions 执行后续处理。