Poketto

GitLab 误删生产数据库:备份机制逐个哑火,最后靠 6 小时前的快照直播抢救

目录

文章主题概念插画

配图:AI 生成的概念示意图,非论文原图、真实现场或实验数据。

TL;DR:2017 年 1 月 31 日,GitLab.com 的一名工程师在排查数据库复制故障时,把清空数据目录的操作做在了主库上,约 300 GB 数据被删。GitLab 事后发现,几套备份与复制手段要么没有生效,要么并非为灾难恢复设计,最终只能靠约 6 小时前的一份手动快照恢复。网站停摆约 18 小时,丢失了约 6 小时的数据,恢复过程还在 YouTube 上直播。

这是一起发生在 2017 年的老事故,不是今天的新闻,但它至今仍是“备份到底能不能恢复”的经典教材。

起因:垃圾账号与复制中断

事故当天,GitLab.com 数据库负载升高,团队怀疑是垃圾账号造成的,处理了好几个小时。接近 23:00(UTC)时,从库的复制落后,随后彻底中断:主库已清理掉从库还需要的 WAL 日志,而 WAL 归档当时并未开启,从库只能手动重建。

重建过程磨人:pg_basebackup 卡住,团队调整参数后 PostgreSQL 又拒绝重启。夜深、疲惫、反复试错,这是事故最典型的前奏。

一刀删在了主库上

约 23:30,工程师本想清空从库的数据目录,结果命令执行在了主库。进程在一两秒内被叫停,但已有约 300 GB 数据被删除。

备份为什么都没用

GitLab 复盘时发现,能指望的手段几乎都有问题:

  • 每日 pg_dump 上传 S3:备份用的是 PostgreSQL 9.2 的程序,而数据库是 9.6,导致备份失败,S3 桶里是空的。失败通知邮件又因为没有启用 DMARC 被拒收,没人察觉。
  • 每日 LVM 快照:本是为同步数据到预发布环境做的,不是为灾难恢复设计的。
  • Azure 磁盘快照:只给 NFS 服务器开了,数据库服务器没开。
  • 流复制的从库:用途是故障切换,而且恰好是当晚被重建、被误操作的那台。
  • WAL 归档:根本没有,所以无法做时间点恢复。

GitLab 当时的总结是几套备份/复制手段都不可靠或根本没配置好。这里按其复盘原文的分类概括,具体数目各方转述略有出入。

救命稻草与直播

唯一可用的,是工程师在事故前约 6 小时、为测试 pgpool-II 手动做的一份 LVM 快照,它让数据库回到 1 月 31 日 17:20(UTC)的状态。因为生产磁盘限速,数据从预发布环境拷回生产花了约 18 小时。

整个过程在 YouTube 公开直播,峰值约 5000 人观看,一度是当时 YouTube 直播榜第二;进度还记录在一份公开的 Google 文档里。2 月 1 日 17:00(UTC)网站恢复,Webhook 随后补齐。

损失与后续

丢失的是 17:20 到约 00:00 之间的变更:至少约 5000 个项目、5000 条评论、约 700 个用户账号,议题和代码片段也受影响。Git 仓库和 Wiki 单独存储,自托管和企业版用户不受影响。

GitLab 随后公开了 15 项整改,包括数据库每小时快照、自动化验证备份可恢复、持续归档与时间点恢复,并指定专人负责数据持久性。公开事故文档里点了当事工程师的名,GitLab 表示今后会隐去姓名。

教训很朴素:没有演练过恢复的备份,只能算一厢情愿的备份。

来源:Postmortem of Database Outage of January 31(GitLab 官方博客,2017-02-10)

关注这个空间,它的新文章会出现在你的关注动态里。