如果迁移失败,如何自动回滚并通知 Slack?
解读
在国内真实面试场景中,这道题考察的是“可观测性 + 自动化运维 + 跨系统通知”的综合能力。面试官想确认:
- 你是否能把 Cloud SQL 的快照/时间点恢复能力与CI/CD 流水线结合;
- 能否用Google Cloud 原生工具(Cloud Build、Workflows、Logging)完成零人工干预的回滚;
- 能否把告警通道对接到国内可访问的 Slack webhook(或企业微信、飞书),并满足合规(数据不出境、密钥不落盘)。
回答时要体现“失败判定 → 回滚触发 → 数据一致性校验 → 通知送达”的闭环,且每一步都给出可落地的配置片段。
知识点
- Cloud SQL 自动备份与时间点恢复(PITR):
- 每日自动备份默认保留 7 天,可按需保留 30 天;
- 通过 gcloud 命令行或 Admin API 可秒级创建恢复任务,恢复后实例 IP 不变,仅底层磁盘回滚。
- Cloud Build + Cloud Workflows 的“双保险”:
- Cloud Build 负责执行迁移脚本(Flyway、Liquibase、Django Migration);
- Cloud Workflows 负责编排重试与回滚,支持声明式语法,可内嵌条件判断与循环,单工作流最长 1 年,适合长事务。
- 失败判定策略:
- 应用健康探针:迁移后 Cloud Build 步骤调用
/health/db,连续 3 次 502/500 即判定失败; - 数据校验 SQL:对核心业务表做
SELECT COUNT(*) <> 预期行数或CHECKSUM TABLE不一致即失败; - 超时熔断:Cloud Build 步骤设置 timeout = 10min,防止脚本假死。
- 应用健康探针:迁移后 Cloud Build 步骤调用
- 回滚原子性:
- 在同一代码库里提前准备好
rollback.dml.sql,版本号与迁移脚本一一对应; - 回滚前自动创建临时实例(克隆当前主实例),先验证回滚脚本无语法错误,再对主实例执行,避免二次故障。
- 在同一代码库里提前准备好
- Slack 通知合规方案:
- 国内 VPC 无法直接访问
hooks.slack.com,需通过Google Cloud 的 Secret Manager + 无服务器连接器(Serverless VPC Connector) 把 webhook URL 当密文存储; - 用Cloud Logging 路由把
severity=ERROR且resource.labels.database_id=project:instance的日志实时推送到 Pub/Sub,再由Cloud Functions 2nd gen 消费并调用 Slack webhook,全程内网出流量,满足等保 2.0 要求。
- 国内 VPC 无法直接访问
- 幂等与重试:
- 整个 Workflows 配置幂等键使用
${build.id},防止重复回滚; - 对 Slack 调用设置指数退避,最大 3 次,避免限流 429。
- 整个 Workflows 配置幂等键使用
答案
-
预置快照:
迁移前 Cloud Build 步骤执行
gcloud sql backups create --async --project=$PROJECT_ID --instance=$INSTANCE_ID --description="pre-mig-$(date +%Y%m%d-%H%M%S)"
拿到 backupId 并写入backup_id.txt作为制品,供回滚步骤使用。 -
迁移与判定:
同一 Cloud Build 的cloudbuild.yaml里顺序执行:
a)flyway migrate脚本;
b) 数据校验python scripts/validate.py(连接 Cloud SQL Auth Proxy 私有 IP,5 秒内重连 3 次);
c) 健康检查curl -f http://internal-lb/health/db。
任一步骤返回非 0,即把exit_code=1写入/workspace/.failed。 -
自动回滚:
Cloud Build 的finally块始终运行:if [ -f /workspace/.failed ]; then gcloud sql backups restore $BACKUP_ID \ --project=$PROJECT_ID --instance=$INSTANCE_ID \ --restore-instance=$INSTANCE_ID \ --quiet --async --format="value(name)" > /workspace/restore_id.txt fi由于恢复操作异步,需把
restore_id.txt传给下一步 Workflows,轮询直到 status=DONE。 -
通知 Slack:
在 Cloud Logging 创建基于日志的指标metric="cloudsql_migration_failure",过滤条件:resource.type="cloud_sql_database" severity=ERROR textPayload:"RESTORE_DONE"配置告警策略:阈值 >0 即触发,通知渠道选 Pub/Sub topic
slack-alerts。
Cloud Functions(Python 3.11)订阅该 topic:- 从 Secret Manager 读取
slack_webhook_url; - 构造 Markdown 消息:
【Cloud SQL 迁移失败】
项目:{instance}
已自动回滚至备份:{restoreId} - POST 到 Slack,超时 5 秒,失败重试 3 次。
- 从 Secret Manager 读取
-
一键闭环:
把整个流程封装成Terraform 模块:cloudbuild_trigger.tf监听 Cloud Source Repositories 的main分支;workflows.tf声明 Workflows YAML,版本锁定;secret_manager.tf把 Slack webhook 存为 SECRET,IAM 仅授予 Cloud Functions SA;
交付给开发团队时,只需terraform apply,即可5 分钟内在新环境复现完整的“失败即回滚+Slack 通知”能力。
拓展思考
- 双云容灾场景:如果客户要求阿里云 RDS 与 Cloud SQL 互为主备,可在Cloud Workflows 里再调用阿里云 API 做反向回滚,同一套失败判定逻辑复用,实现跨云一致性。
- 灰度迁移:把**影子实例(Cloud SQL 只读副本提升后的独立实例)**作为灰度目标,迁移成功后再切换 DNS,失败直接释放影子实例,零回滚时间。
- 成本优化:对非核心库关闭自动备份,改用每日导出 SQL 到 Cloud Storage Nearline,失败时通过导入恢复,节省 30% 存储成本,但 RPO 从 5 分钟降到 1 小时,需在SLA 文档里明确告知业务方。