本次故障及恢复的极简回顾 · Gitlab 被攻击,连锁反应导致PostgreSQL复制出现问题; · 极度疲劳的运维操作人员A做了一个误操作:本来应该在出问题的数据库服务器执行 rm -rf / ,结果在正常的数据库服务器上执行(2秒钟后他回过神来,但300GB的数据已然只剩下4.5GB); · 万幸的事,故障发生前,做了一次手工的LVM快照,否则只能恢复到24小时前了。。。 以下为本次故障处理的全过程,由高效运维社区金牌编辑@龙井编译自故障官方地址: https://about.gitlab.com/2017/02/01/gitlab-dot-com-database-incident/此次事件影响的是下图中的PostgreSQL(影响内容为项目、用户、问题、合并请求等存储在数据库中的信息,代码和wiki存储是单独存储在文件系统中,不受影响。 第一阶段
2017/01/31 18:00 UTC,我们发现垃圾邮件发送者通过创建snippet(笔者:snippet是Gitlab中的代码片断,Gitlab可以将代码文件的片断共享给其他人查看和协作)造成数据库的不稳定。我们立即开始分析问题原因和考虑解决办法。 2017/01/31 21:00 UTC,事件引发数据库无法执行写操作,造成宕机。 采取的措施:· 我们屏蔽了垃圾邮件发送者的IP地址; · 我们移除了一个用户,不允许该用户以某种CDN的形式使用仓库。因为有47000个IP地址使用这个账户登录(引发数据库高负载); · 我们移除了通过创建snippets发送垃圾邮件的用户。 第二阶段
2017/01/31 22:00 UTC,我们收到消息,数据库复制严重滞后。原因是从数据库有一个高峰写操作没有及时处理。 采取的措施:· 试图修复db2,它滞后大概4GB数据; · db2.cluster 拒绝复制,擦除/var/opt/gitlab/postgresql/data目录,以便进行干净的复制; · db2.cluster 拒绝连接db1,提示max_wal_senders太低。这项参数是为了限制WAL(复制)客户端的数量; · 运维工程师A调整了db1的max_wal_senders为32.重启了PostgreSQL; · PostgreSQL提示信号太多被打开,启动失败; · 运维工程师A将max_connections从8000调整到了2000。PostgreSQL重新启动(虽然8000已经使用了近一年); · db2.cluster依然拒绝复制,但是已经不提示连接信息,而是死在那儿了; · 这个时候大家都很沮丧,晚上的早些时候运维工程师A明确提出他要下班了,因为已经很晚了。但是因为复制问题突然放大,不得不继续。 第三阶段
2017/01/31 23:00,运维工程师A认为造成pg_basebackup拒绝工作的可能原因是PostgreSQL数据目录存在(虽然目录是空的)。他觉得删除目录是管用的。 一两秒之后,他突然意识到,他在正常的db1.cluster.gitlab.com执行了删除数据库目录的命令,而不是有问题的db2.cluster.gitlab.com(天了噜)。 2017/01/31 23:27,运维工程师A停止了删除操作,但是一切都为时晚矣。原本300GB的数据只剩下4.5GB。 我们只好将Gitlab.com暂时关闭,并在Twitter上公布: 我们正在进行数据库紧急维护 ... — GitLab.com Status(@gitlabstatus)2017年1月31日 遇到的问题
· LVM快照默认24小时执行一次,运维工程师A碰巧服务中断的6小时前手动执行过一次。因为他负责数据负载均衡。 · 日常备份也是24小时执行一次,然而运维工程师A并没有找到日常备份存储位置。根据运维工程师B的说法,日常备份并没有生效,因为生产数据只有几个字节大小。 笔者:这里的日常备份应该指的是Gitlab官方提供的gitlab-rake gitlab:backup:create。使用crontab,每天只需一次,会将数据库、代码库、文件打包备份。 · 运维工程师C:看起来pg_dump也失败了,运维运行的是PostgreSQL 9.2二进制代码,而不是9.6二进制代码。 之所以会出现这种情况,是因为Gitlab omnibus(Gitlab提供omnibus和源码安装两种方式)只在data/PG_VERSION文件被设成9.6时使用Pg 9.6,但是在worker节点上,该文件不存在。所以默认情况下运行9.2,悄然失效。因此没有SQL dumps。 Fog gem(Ruby on Rails的包)可能清除掉了早些时候的备份。 · Azure上只对NFS服务器启用了磁盘快照,没有在DB服务器启用磁盘快照 · 往预发布环境同步数据的同步程序一旦同步会自动删除webhooks(笔者:Gitlab提供webhook以支持调用、事件触发等功能),除非我们可以在过去的24小时内的常规备份中找回这些数据,否则webhooks将会丢失。 · 复制过程很脆弱,容易出错,需要依靠一些手工编写的shell脚本,而且没有完备的文档说明。 · 往S3的备份显然也没有成功。 · 这就是说,我们的5级备份/复制技术没有毛用,我们最终只能恢复6小时以前的备份数据(笔者:这还是上帝可怜运维工程师A,给的一次偶然机会,如果他没有手工进行一次LVM快照,只能恢复24小时以前的) · pg_basebackup只能等待主数据库以初始化复制过程。根据另一位生产环境工程师的说法,这需要花10分钟。这引发我们思考流程一定是在某处卡住了。使用跟踪程序没能提供有用的信息。 恢复
我们正在使用预发布环境的数据库备份恢复数据。 — GitLab.com Status(@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-meltodwn-backup.tar.gz 下图显示删除以及之后复制数据需要的时间: 到北京时间 2月2日凌晨时,Gitlab.com的工程师还在YouTube上直播问题修复过程,回答网友的问题。受限于磁盘读写速度,恢复过程非常慢,在直播过程中也在寻求大家的帮助,提供加速办法。 以上就是Gitlab.com公布的问题修复过程介绍。 我想今天一定有很多外国程序猿们被迫放假了,因为他们无法下载和上传代码、也无法进行持续集成验证,更别提部署上线了。五级备份都失败,网友们纷纷表示应该将2月1日定为“世界备份日”以纪念此次事件和警示后人。 这次事件给我们的警示: 1. 不要疲劳驾驶,喝酒不上机,上机不喝酒,尤其别动数据库; 2. 建议要对rm命令设置alias,常见做法是设置别名为mv到指定目录; 3. 备份和恢复验证同在,定期从备份数据进行恢复演练,既验证备份数据是否完整有效,也验证恢复方案是否靠谱; 4. 践行DevOps的无指责文化,尤其是在做事故分析时。事故分析重在定位原因,制定改进措施; 5. 在处理事故时,一定要考虑处理措施是否会引发连锁故障,重要操作三思而行; 6. 应急预案还是要做的,此次事故响应和修复周期非常长,备用硬件不给力,且丢失数据,对用户而言是难以接受的; 7. 千万不要在改进措施中增加线上操作的领导审批环节,不仅于事无补,还会影响效率;(龙井、萧田国原创)
|