如果事件总线出现积压,如何横向扩展消费者?
解读
在国内真实面试场景中,面试官问“事件总线出现积压,如何横向扩展消费者”时,并不是单纯让你回答“加机器”,而是想验证你对 Google Cloud 生态里事件驱动链路(Cloud SQL → Pub/Sub → Cloud Run/GKE/Cloud Functions)的整体掌控力,以及能否在零停机、数据一致性、成本可控的前提下完成扩容。
核心考点有三层:
- 快速定位积压根因(是 Cloud SQL 写入慢?Pub/Sub 订阅积压?还是消费者代码瓶颈?)。
- 选择正确的横向扩容对象(是扩容 Pub/Sub 订阅端的消费者副本数,还是扩容 Cloud SQL 只读实例来卸读压)。
- 保证扩容动作可灰度、可回滚、可观测,符合国内金融级合规要求。
知识点
- Pub/Sub 背压机制:unacked 消息数 / oldest_unacked_message_age 是判断积压的黄金指标。
- Cloud Run 并发模型:默认 80 并发,一个实例可并行拉多条消息;通过设置
--concurrency=1可让实例数与消息数 1:1 对齐,实现“按消息粒度横向扩容”。 - GKE HPA 基于 Pub/Sub 自定义指标:使用
external.metrics.k8s.io/pubsub.googleapis.com|subscription|num_undelivered_messages,阈值建议设为“单副本最大处理能力的 70%”,既留 Buffer 又避免过度扩容。 - Cloud SQL 读扩展:若积压原因是下游消费者需要回查主库导致主库 CPU 飙高,可一分钟内弹出只读实例,通过
read-pool标签把只读 SQL 路由到只读节点,降低主库 RT。 - Exactly-once 语义:Cloud SQL 与 Pub/Sub 的事务性提交需借助 Pub/Sub 的“二阶段提交事务”特性,在扩容后仍保证幂等。
- 国内合规:横向扩容必须走堡垒机+工单系统,Terraform 模板需提前在等保三级预检流水线里跑通,避免临时手写命令。
答案
当监控发现 subscription/my-app-sub 的 num_undelivered_messages 连续 2 个采样周期超过阈值(例如 10 k),按以下步骤横向扩展消费者:
- 30 秒定位:先看 Cloud SQL 实例的
CPU 利用率与数据库连接数,若主库 CPU<50% 且连接池未满,则排除数据库瓶颈,确认是消费者吞吐量不足。 - 选择扩容目标:
- 若消费者部署在 Cloud Run,执行
gcloud run services update my-consumer --max-instances=1000 --concurrency=1
利用 Pub/Sub push 触发,让 Cloud Run 在 15 秒内弹出数百实例,每个实例一次只处理一条消息,保证水平线性扩展。 - 若消费者部署在 GKE,通过 HPA 配置
averageValue: "500"(即每个副本负责 500 条未 ack 消息),系统会在 30 秒内把副本数从 10 扩到 200。
- 若消费者部署在 Cloud Run,执行
- 防止重复消费:在消费者代码里使用 Pub/Sub 的
ackId + Cloud SQL 唯一索引做幂等校验,即使扩容后并发度翻倍,也不会出现重复写。 - 灰度观察:扩容后 3 分钟,检查
oldest_unacked_message_age是否降到 10 s 以内;若已低于阈值,则逐步调低max-instances或 HPA 副本数,实现弹性回缩,节省费用。 - 合规记录:通过 Terraform 把上述 HPA/Cloud Run 参数固化进
modules/consumer-auto-scale,合并 MR 后走蓝鲸工单系统留痕,满足国内审计要求。
拓展思考
- 跨区域双活:如果积压是因为华东区 Pub/Sub 到 Cloud SQL 华北主库网络延迟导致 ack 慢,可考虑在华东区再建一套 Cloud SQL 只读实例,通过
Private Service Connect把读流量就近消化,网络 RT 从 35 ms 降到 5 ms,整体吞吐提升 40%。 - Serverless 成本优化:国内客户对“空转 0 收费”非常敏感,可设置 Cloud Run 最小实例数为 0,并打开
cpu-throttling,在流量洪峰结束 15 分钟后自动缩容到 0,相比常驻节点节省 60% 费用。 - 灰度扩容与回滚:利用 Google Cloud 的标签+流量百分比能力,先对 5% 的订阅消息启用新扩容的消费者版本,验证 10 分钟无异常后再全量切流,实现金丝雀发布,这是国内金融客户上线必过的一道关。