云发布/订阅:托管事件发布全解析
1. 订阅概述
订阅在其他消息传递系统中有时被称为队列,它代表了监听或消费特定主题消息的需求或意图。订阅还承担了大部分与消费者接收消息配置相关的责任,根据特定配置,可实现一些有趣的消费模式。
1.1 订阅的重要特性
- 消息副本独立 :每个订阅都会收到发送到其主题的每条消息的不同副本,消费者可以访问主题中的消息,而不会影响其他对该主题消息感兴趣的人。一个消费者从一个订阅中读取消息,对其他订阅没有任何影响。
- 消息全量可见 :每个订阅都能看到你在主题上发送的所有消息。如果更多消费者为该主题创建订阅,你就可以将消息广播给更广泛的受众。
- 多消费者共享 :多个消费者可以从同一个订阅中消费消息,因此可以使用订阅将主题中的消息分发给多个消费者。一旦一个消费者从订阅中消费了一条消息,该消息就不再在同一主题上可用,下一个消费者将获得不同的消息。这种安排确保了同一订阅的两个消费者不会处理相同的消息。
1.2 订阅类型
订阅有两种类型:拉取(pull)和推送(push),这与消费者获取消息的方式有关。区别在于订阅是等待消费者请求消息(拉取),还是在新消息到达时主动向特定 URL 发送请求(推送)。
1.3 消息确认截止时间
在消息被视为已送达之前,你必须确认已收到消息。每个订阅除了推送或拉取配置外,还必须指定一个确认截止时间。这个截止时间以秒为单位,作为一个计时器,用于在假设消费者出现问题之前等待的时间。
下面是确认截止时间过期的流程图:
graph LR
A[Consumer 1 从订阅中拉取消息] --> B[Consumer 1 在确认消息接收前异常退出]
B --> C[确认截止时间到期]
C --> D[消息放回订阅队列]
D --> E[Consumer 2 拉取消息]
E --> F[Consumer 2 确认消息接收]
2. 示例配置
假设有一个生产者向两个主题(主题 1 和主题 2)发送三条消息(消息 A、消息 B 和消息 C),有四个不同的消费者(消费者 1、消费者 2、消费者 3 和消费者 4)最终接收这些消息。
2.1 主题 1 的消息处理
生产者向主题 1 发送消息 A,消费者 1 和消费者 2 各自有自己的订阅。由于订阅会收到发送到主题的所有消息的副本,因此消费者 1 和消费者 2 都会收到消息 A 的通知。
2.2 主题 2 的消息处理
生产者向主题 2 发送消息 B 和消息 C,消费者 3 和消费者 4 使用相同的订阅(订阅 3)来消费主题 2 的消息。由于订阅每个消息只有一个副本,且消息一旦被消费者消费就不再可用,因此消息 B 和消息 C 很可能会被拆分。可能的情况是,其中一个消息(例如消息 B)会发送给消费者 3,另一个消息(例如消息 C)会发送给消费者 4。多个消费者使用同一订阅的最终结果是他们会分担工作,各自获得发送的所有消息的一部分。
不过要注意,这只是可能的情况,并非绝对。消息也可能会互换(消费者 3 收到消息 C,消费者 4 收到消息 B),或者一个消费者可能会收到消息 B 和消息 C(例如,如果其中一个消费者被其他工作压得喘不过气来)。
| 主题 | 消息 | 消费者 | 订阅情况 | 消息分配 |
|---|---|---|---|---|
| 主题 1 | 消息 A | 消费者 1、消费者 2 | 各自有订阅 | 消费者 1 和消费者 2 都收到消息 A |
| 主题 2 | 消息 B、消息 C | 消费者 3、消费者 4 | 共同使用订阅 3 | 可能消费者 3 收到消息 B,消费者 4 收到消息 C,但不绝对 |
3. 实践操作
3.1 启用 API
在开始编写与云发布/订阅交互的代码之前,你必须启用 API。操作步骤如下:
1. 在浏览器中访问云控制台。
2. 在顶部的主搜索框中输入“Cloud Pub/Sub API”(记得包含斜杠)。
3. 搜索结果应该只有一个,点击它会进入一个带有大“启用”按钮的页面,点击该按钮即可启用 API。
3.2 发送第一条消息
要使用云发布/订阅广播消息,首先需要一个主题。发送消息时,使用主题对消息进行分类。可以在代码中创建主题,也可以先在云控制台中创建。
3.2.1 在云控制台创建主题
- 在左侧导航栏中,在“大数据”下方找到“Pub/Sub”条目并点击。
- 你会看到一个空页面,上面有一个按钮提示你创建主题,点击该按钮。
- 在出现的输入框中输入主题名称,主题的完全限定名称是一个以“projects/”开头的长路径,这可以在云发布/订阅中唯一标识你的主题。为第一个主题选择一个简单的名称,例如“first - topic”,然后点击“创建”。
3.2.2 安装 Node.js 客户端库
在编写代码之前,需要安装云发布/订阅的 Node.js 客户端库。可以使用 npm 运行以下命令进行安装:
npm install @google - cloud/pubsub@0.13.1
3.2.3 编写发布消息的代码
const pubsub = require('@google - cloud/pubsub')({
projectId: 'your - project - id'
});
const topic = pubsub.topic('first - topic');
topic.publish('Hello world!').then((data) => {
const messageId = data[0][0];
console.log('Message was published with ID', messageId);
});
运行这段代码,你会看到类似以下的输出:
> Message was published with ID 105836352786463
这里看到的消息 ID 是在该主题内保证唯一的标识符。
3.3 接收第一条消息
要从云发布/订阅接收消息,首先需要创建一个订阅。订阅是从主题消费消息的方式,主题上的每个订阅都会收到发送到该主题的每条消息的副本。
3.3.1 在云控制台创建订阅
- 回到 Pub/Sub 部分的主题列表,点击之前创建的主题名称。
- 主题展开后,会显示当前没有订阅,但右上角会有一个“新建订阅”按钮,点击该按钮。
- 在接下来的页面中,将订阅命名为“first - subscription”,“交付类型”暂时选择“拉取”。
- 点击“创建”,你会回到主题列表页面。点击你创建的主题,应该会在列表中看到你创建的订阅。
3.3.2 编写消费消息的代码
const pubsub = require('@google - cloud/pubsub')({
projectId: 'your - project - id'
});
const topic = pubsub.topic('first - topic');
const subscription = topic.subscription('first - subscription');
subscription.pull().then((data) => {
const message = data[0][0];
console.log('Got message', message.id, 'saying', message.data);
});
运行上述代码,你会看到类似以下的输出:
> Got message 105838342611690 saying Hello world!
不过,这里遗漏了一个重要步骤:确认消息。如果在大约 10 秒后再次运行相同的代码,你会再次得到相同的消息。这是因为订阅知道已经将消息提供给了消费者,但消费者从未确认收到该消息。
3.3.3 编写消费并确认消息的代码
const pubsub = require('@google - cloud/pubsub')({
projectId: 'your - project - id'
});
const topic = pubsub.topic('first - topic');
const subscription = topic.subscription('first - subscription');
subscription.pull().then((data) => {
const message = data[0][0];
console.log('Got message', message.id, 'saying', message.data);
message.ack().then(() => {
console.log('Acknowledged message ID', message.id,
'with ackId', message.ackId);
});
});
运行这段代码,你会看到消费者向云发布/订阅发送确认消息,表明已收到该消息。再次尝试拉取消息时,会发现该消息已消失,因为云发布/订阅认为该消息已从该订阅中消费,不会再次发送给同一订阅。
4. 推送订阅
到目前为止,你接收的所有消息都是从订阅中拉取的,即你明确要求订阅提供可用的消息。不过,还有另一种消费消息的方式,不需要你主动请求,而是云发布/订阅在新消息到达时将其推送给你。
4.1 推送订阅的配置
这种类型的订阅需要你配置当新消息到达时,云发布/订阅应将推送通知发送到哪里。通常,发布/订阅会向你指定的端点进行 HTTP 调用,其中包含与使用常规拉取订阅时相同的消息数据。
4.2 处理推送通知
首先,你需要编写一个处理程序,该处理程序接受带有消息体的传入 HTTP 请求。处理程序收到消息后,负责确认消息,但确认推送消息的方式与拉取订阅有所不同。使用拉取订阅时,你需要单独调用云发布/订阅,告知其你已收到并处理了消息;而使用推送订阅时,你将依靠 HTTP 响应代码来进行通信。在这种情况下,HTTP 代码 204(无内容)表示你已成功接收并处理了消息,任何其他代码(例如 500 服务器错误或 404 未找到)则表示出现了某种故障。
以下是一个使用 Express.js 编写的简单处理程序示例:
const express = require('express');
const app = express();
app.post('/message', (req, res) => {
console.log('Got message:', req.message);
res.status(204).send()
});
4.3 创建推送订阅
要指示云发布/订阅将消息发送到这个处理程序,你可以通过创建一个配置了 URL 的新订阅来实现。以下是使用云控制台创建推送订阅的步骤:
1. 在控制台的 Pub/Sub 区域,你可以重用之前创建的主题(first - topic),直接创建新订阅。
2. 假设你已将带有基本处理程序的简单 Express.js 应用部署到自己的域名(例如 your - domain.com)。浏览到该主题并点击顶部的“创建订阅”按钮,你会看到一个表单,在其中可以指定订阅名称和推送消息的 URL。例如,将订阅名称设为“push - subscription”,URL 设为“https://your - domain.com/message”(注意代码中的路径是“/message”)。
3. 点击“创建”后,云发布/订阅会将该主题的传入消息路由到你的处理程序,无需进行拉取或确认操作。
注意 :你可能会收到关于是否拥有该域名的错误提示,这是正常现象,这是 Google 确保消息仅发送到你拥有的域名的方式。要了解如何将你的域名列入白名单以用作 Pub/Sub 推送端点,请查看 https://cloud.google.com/pubsub/docs/push#other - endpoints。
下面是一个 mermaid 流程图,展示了推送订阅的处理流程:
graph LR
A[新消息到达主题] --> B[Pub/Sub 向指定 URL 发送 HTTP 请求]
B --> C[处理程序接收消息]
C --> D{处理是否成功?}
D -- 是 --> E[返回 204 状态码]
D -- 否 --> F[返回其他状态码]
E --> G[Pub/Sub 认为消息处理成功]
F --> H[Pub/Sub 认为消息处理失败]
5. 了解定价
与许多 Google Cloud API 一样,云发布/订阅仅根据你实际使用的资源和计算量收费。发布/订阅根据你通过系统广播的数据量进行计费,最高费率为每千兆字节数据 0.06 美元。虽然这大致与消息数量相关,但具体费用还取决于你发送的消息大小。例如,与其通过消息发送整个视频文件的内容,不如发送视频的链接,这样不仅因为发布/订阅并非专门设计用于发送大视频文件,而且发送链接的成本要低得多,从其他地方(如 Google Cloud Storage)下载视频文件可能会便宜得多。
5.1 具体示例分析
假设你的系统每秒发送五条消息,有 100 个消费者对这些消息感兴趣,且这些消息非常小。下面来计算一下一个月的费用:
-
计算消息总数
:
- 每天有 86400 秒,为了简化计算,假设一个月平均有 30 天,那么一个月共有 2592000 秒。
- 由于每秒发送五条消息,所以一个月总共发送的消息数为 12960000 条。
-
计算请求总数
:
- 每条消息需要进行一次发布请求,这是发送消息的必要操作。
- 每个消费者需要对每条消息进行一次拉取请求(或通过推送订阅接收消息),即每个消息对应 100 个额外请求。
- 一个月发送 12960000 条消息,100 个消费者总共会进行 1296000000 次拉取(或推送)请求。
5.2 费用总结
虽然这里没有给出具体的费用数值,但可以看出,消息的大小和请求的数量都会影响最终的费用。在使用云发布/订阅时,需要根据实际情况合理设计消息内容和消费方式,以控制成本。
| 项目 | 数量 |
|---|---|
| 每秒发送消息数 | 5 条 |
| 一个月的秒数 | 2592000 秒 |
| 一个月发送的消息总数 | 12960000 条 |
| 消费者数量 | 100 个 |
| 一个月的拉取(或推送)请求总数 | 1296000000 次 |
通过以上内容,你应该对云发布/订阅的使用方式、推送订阅的处理以及定价有了较为全面的了解,可以根据实际需求合理运用云发布/订阅服务。
超级会员免费看
932

被折叠的 条评论
为什么被折叠?



