3. Pub/Sub主题与订阅工程

在事件驱动架构中,Pub/Sub 承担的是“事件总线”的角色:生产者把消息发布到主题(Topic),消费者通过订阅(Subscription)接收消息。主题与订阅的工程化配置,直接决定了消息能否被可靠投递、失败后能否重试、异常消息如何隔离,以及谁能发布、谁能消费。本节围绕主题创建、订阅类型、消息保留、死信队列、重试策略与 IAM 权限六个关键点展开。

一、主题创建:命名、区域与发布入口

主题是消息的发布入口,本身不保存消息,消息的持久化由订阅承担。创建主题时通常关注三件事:命名规范、消息保留策略、以及是否启用消息存储策略。命名建议采用“业务域-事件类型-环境”的形式,例如 order-created-prod,便于权限与监控按前缀管理。

gcloud pubsub topics create order-created-prod \
  --message-retention-duration=7d \
  --project=my-event-project

其中 --message-retention-duration 控制主题在无订阅时对消息的保留时长,默认 7 天,最长 31 天。若主题下没有任何订阅,消息会在保留期后丢弃,因此生产环境应确保主题创建后立即绑定订阅。

二、订阅类型:拉取、推送与 BigQuery 订阅

订阅决定消息如何被消费。常见类型包括:

  • 拉取订阅(Pull):消费者主动调用 Pull 或 StreamingPull 拉取消息,适合自建服务、需要精确控制消费速率的场景。
  • 推送订阅(Push):Pub/Sub 主动将消息 POST 到 HTTPS 端点,适合 Cloud Run、Cloud Functions 等无服务器服务,端点需返回 2xx 表示成功。
  • BigQuery 订阅:消息直接写入 BigQuery 表,适合日志、审计类事件的无代码落库。

选择订阅类型时,核心判断是“谁发起请求”。拉取由消费者发起,推送由 Pub/Sub 发起。推送订阅必须配置端点 URL 与认证方式,通常使用 OIDC Token 让端点验证请求来源。

三、消息保留与确认截止时间

订阅上的 消息保留时长(message retention duration) 决定消息在确认前可被重新投递的时间窗口,默认 7 天,最长 31 天。与之相关的是 确认截止时间(ack deadline),默认 10 秒,最长 600 秒。消费者必须在截止时间前调用 ack,否则消息会被重新投递。

如果处理逻辑耗时较长,应适当延长 ack deadline,或使用 modifyAckDeadline 动态续期。保留时长与 ack deadline 的关系是:ack deadline 控制单次投递的确认窗口,保留时长控制消息在订阅中可被重投的总时长。

四、死信队列与重试策略

当消息反复处理失败时,若无限重试会阻塞订阅、消耗资源。死信队列(Dead Letter Queue, DLQ)用于隔离这些“毒消息”。配置 DLQ 需要:一个死信主题、一个死信订阅,以及在原订阅上设置 --dead-letter-topic 和 --max-delivery-attempts。

gcloud pubsub subscriptions create order-created-sub \
  --topic=order-created-prod \
  --ack-deadline=60 \
  --message-retention-duration=7d \
  --dead-letter-topic=order-created-dlq \
  --max-delivery-attempts=5 \
  --min-retry-delay=10s \
  --max-retry-delay=600s

上述配置表示:消息最多投递 5 次,重试间隔从 10 秒指数退避到最长 600 秒,超过 5 次后进入死信主题。重试策略还包括 --retry-policy,可选择 exponential-backoff 或 immediate。指数退避适合下游临时故障,立即重试适合快速失败场景。

注意:死信主题本身也需要一个订阅来接收死信消息,否则死信消息会因无订阅而丢失。同时,Pub/Sub 服务账号需要对死信主题有发布权限,对原订阅有订阅权限。

五、IAM 权限配置

Pub/Sub 的权限模型围绕主题与订阅分别授权。常见角色包括:

角色作用范围典型用途
roles/pubsub.publisher主题生产者发布消息
roles/pubsub.subscriber订阅消费者拉取/确认消息
roles/pubsub.viewer项目/主题查看主题与订阅元数据
roles/pubsub.editor项目管理主题与订阅

最小权限原则要求:生产者只授予 publisher,消费者只授予 subscriber,避免直接使用 editor。推送订阅还需为 Pub/Sub 服务账号授予 iam.serviceAccountTokenCreator,以便生成 OIDC Token。

gcloud pubsub topics add-iam-policy-binding order-created-prod \
  --member="serviceAccount:producer@my-event-project.iam.gserviceaccount.com" \
  --role="roles/pubsub.publisher"

gcloud pubsub subscriptions add-iam-policy-binding order-created-sub \
  --member="serviceAccount:consumer@my-event-project.iam.gserviceaccount.com" \
  --role="roles/pubsub.subscriber"

六、整体关系与配置检查

下图把主题、订阅、死信队列、重试策略与 IAM 权限放在同一张关系图中,帮助理解各组件之间的连接方向与权限边界。

Pub/Sub 主题—订阅—死信队列关系图 生产者服务 roles/pubsub.publisher 主题 Topic order-created-prod 订阅 Subscription ack=60s / 保留=7d max-delivery=5 消费者服务 roles/pubsub.subscriber 死信主题 DLQ order-created-dlq 死信订阅 人工排查 / 告警 发布 绑定 投递 超过5次 转发 重试 10s→600s IAM 权限边界 • 生产者 → 主题:roles/pubsub.publisher(仅发布) • 消费者 → 订阅:roles/pubsub.subscriber(拉取与确认) • Pub/Sub 服务账号 → 死信主题:roles/pubsub.publisher(转发死信) • 推送订阅 → 服务账号:roles/iam.serviceAccountTokenCreator(生成 OIDC Token)

配置完成后,建议按以下顺序验证:先用 gcloud pubsub topics list 确认主题存在;再用 gcloud pubsub subscriptions describe 检查 ack deadline、保留时长、死信主题与最大投递次数;最后用一条测试消息走通“发布→消费→确认”链路,并故意让消费者返回失败,观察消息是否在 5 次后进入死信订阅。只有这条链路完整跑通,主题与订阅的工程配置才算真正落地。