原文地址: https://about.gitlab.com/blog/2017/02/01/gitlab-dot-com-database-incident/
原文标题: GitLab.com database incident
原文作者: GitLab Team
原文写于: 2017/02/01
译者:驱蚊器喵#ΦωΦ
翻译水平有限,有不通顺的语句,请见谅。
阅读时间:大约 5 分钟
更新:请看我们对这一事件的事后总结
昨天我们的一个数据库发生了严重事故。我们丢失了 GitLab.com 六个小时的数据库数据(问题、合并请求、用户、评论、代码片段等)。Git/wiki 存储库,以及私有搭建的 GitLab 没有受到影响。丢失生产数据是不可接受的,几天后我们会发表一篇文章,说明为什么会发生这种情况,并列出我们将采取的措施,以防止事故再次发生。
UTC时间 下午 6:14 更新。GitLab.com 已恢复上线
截至发稿时,我们正在从六小时前的数据库备份恢复数据。这意味着,当 GitLab.com 恢复上线时,数据库中 5:20pm UTC 到 11:25pm UTC 之间的所有数据(项目、问题、合并请求、用户、评论、代码片段等)都会丢失。
Git 数据(存储库和 wiki)和 GitLab 的私有搭建实例不受影响。
请阅读下文,了解事件的简要概述。也欢迎你查看我们的事后总结文档(译者注:文件已经被删除)。
第一次事件
在 2017/01/31 下午6点(UTC时间),我们检测到垃圾邮件发送者通过创建片段来攻击数据库,导致数据库运行不稳定。然后我们开始排除故障,了解问题以及如何防御。
在 2017/01/31 晚上9点(UTC),这个问题升级了,导致数据库的写入被加锁,这造成了一段时间的宕机。
采取的行动
- 我们封禁了垃圾邮件发送者的 IP 地址。
- 我们删除了一个将代码库作为类似 CDN 使用的用户,这导致了用户账号有 47000 个 IP 登录(导致数据库高负荷)。
- 我们删除了发送垃圾邮件的用户(通过代码片段)。
第二次事件
在 2017/01/31 10pm UTC,我们被叫起来了,因为 DB Replication 滞后太多,几乎要停止了。发生这种情况的原因是因为有一个写入的高峰,而且辅助数据库没有及时处理。
采取的行动
- 试图修复
db2
,此时已经滞后了大约 4GB。 db2.cluster
拒绝进行副本的复制,删除了/var/opt/gitlab/postgresql/data
目录,以确保能够进行干净的复制。db2.cluster
拒绝连接到db1
,报错显示max_wal_senders
太低。这个设置是用来限制WAL (= replication)
客户端的数量- Team-member-1 将
db1
的max_wal_senders
调整为32
,重新启动 PostgreSQL - PostgreSQL 报错显示,too many semaphores being open,拒绝启动
- Team-member-1 将
max_connections
从8000
调整到2000
,PostgreSQL 再次启动(尽管8000
已经被使用了将近一年)。 db2.cluster
仍然拒绝复制,但是没有报错连接问题;然而,它只是挂在那里不做任何事情。- 这个时候,team-member-1 感到有些沮丧。今天晚上的早些时候,team-member-1 明确表示他要下班打卡了,因为当时已经很晚了(当地时间23:00左右),但由于复制问题突然出现而导致加班。
第三次事件
在 2017/01/31 11pm-ish UTC,team-member-1 认为,也许是因为存在 PostgreSQL 数据目录(尽管是空的)所以 pg_basebackup
拒绝工作,决定删除该目录。一两秒钟后,他才注意到他是在 db1.cluster.gitlab.com
上执行的删除操作,而不是在 db2.cluster.gitlab.com
。
在 2017/01/31 11:27pm UTC,team-member-1 - 终止了删除操作,但已经太晚了。大约 300GB 数据中只剩下了 4.5GB。
我们不得不将 GitLab.com 关闭,并在 Twitter 上分享这一信息。
我们正在进行紧急数据库维护,https://gitlab.com 将被关闭
- GitLab.com Status (@gitlabstatus) January 31, 2017
遇到的问题
- LVM 快照默认是每24小时才运行一次。Team-member-1 碰巧在停电前六小时手动运行了一次,因为他正在为数据库做负载平衡工作。
- 定期备份似乎也是每24小时才进行一次,尽管 team-member-1 还没能弄清楚它们被储存在哪里。根据 team-member-2 的说法,这些备份似乎没有用,产生的文件只有几个字节的大小。
- team-member-3:看起来
pg_dump
可能失败了,因为现在运行的是 PostgreSQL 9.2 版本的二进制文件,而不是 9.6 版本的二进制文件。发生这种情况是因为 omnibus 只在 data/PG_VERSION 设置为 9.6 时才使用 Pg 9.6,但在 workers 上这个文件并不存在。因此,运行失败了,默认启动了 9.2 版本的程序。所以,没有产生 SQL 备份。Fog gem 可能已经清理了旧的备份。 - Azure 中的磁盘快照对 NFS 服务器启用,但对没有对 DB 服务器启用。
- 同步过程中,一旦将数据同步到 staging,就会删除 webhooks。除非我们能从过去24小时的常规备份中提取这些数据,否则它们就会丢失。
- 复制过程是非常脆弱的,容易出错,依赖于一些随机的 shell 脚本,而且这些文档记录得很差。
- 我们备份到 S3 的工作显然也没有成功:存储桶里的数据是空的
- 因此,换句话说,在部署的五种备份/副本复制技术中,没有一种能可靠地工作,也没有第一时间设置好。我们最后恢复了一个六小时前的备份。
- pg_basebackup 会默默地等待主站启动复制进度,据另一位生产工程师说,这可能需要10分钟。这可能导致人们认为这个过程在某种程度上被卡住了。使用 “strace” 来运行该进程,没有提供关于可能发生的事情的有用信息。
恢复
我们现在正在努力通过使用一个暂存数据库的数据库备份来恢复。
我们不小心删除了生产数据,不得不从备份中恢复。这是谷歌文档与现场笔记 https://t.co/EVRbHzYlk8
- GitLab.com 状态(@gitlabstatus) 2017年2月1日
- 2017/02/01 00:36 - 备份
db1.staging.gitlab.com
数据 - 2017/02/01 00:55 - 将
db1.staging.gitlab.com
挂载到db1.cluster.gitlab.com
上 - 将数据从临时环境的
/var/opt/gitlab/postgresql/data/
复制到生产环境的/var/opt/gitlab/postgresql/data/
。 - 2017/02/01 01:05 -
nfs-share01
服务器被征用,作为/var/opt/gitlab/db-meltdown
的临时存储 - 2017/02/01 01:18 - 剩余生产数据的拷贝,包括
pg_xlog
,被压缩成20170131-db-melodwn-backup.tar.gz
。
下面一张图显示了删除的数据和随后复制进来的数据,以及对应的时间。