谈谈农历新年首次质量大事故:GitLab丢失数据

农历大年初四(一月最后的一天)GitLab.com的一个数据库发生了灾难性的事故。经过努力,最终丢失了6个小时(5:20pm UTC ~ 11:25pm UTC,Jan 31,2017 )的数据。“这起事件影响了数据库(包括问题和合并请求),但是没有影响git代码库(代码库和维基)。”  所以对用户来说多少有点安慰,因为并非所有数据全部丢失。所幸GitLab运气不错,损失不是太大,而且公开事故过程,没有躲猫猫,获得大家的好评。但问题还是比想象的严重,值得分析。

 

1. 让我们简单回顾一下事情的经过

第一次事故

  • 2017/01/31 6pm UTC:发现黑客不断往数据库灌数据(hammering the database by creating snippets)导致数据库不稳定,Gitlab开始进行troubleshooting,想确定究竟是什么问题、以及如何处理:
  • 2017/01/31 9pm UTC: 问题进一步加重,导致数据无法写入DB中,引起系统不能正常工作(downtime).


采取的措施:

  • 阻止黑客的IP地址
  • 删除这个用户(用同一个账号从47 000 IP 登录进来,著名的DDoS攻击)和其它制造垃圾数据的用户。

 

第二次事故

  • 2017/01/31 10pm UTC: 由于写DB出现一个峰值,导致DB复制严重滞后。(按照PostgreSQL专业服务公司2ndQuadrant的CTO SimonRiggs 观点,4GB的同步滞后是正常的,PostgreSQL 9.6的数据同步可能存在Bug)

采取的措施:

  • 值班的Gitlab员工(YP)调整max_wal_senders to 32 on db1(注:db2.cluster拒绝连接db1,由于max_wal_senders太低,max_wal_senders限制复制客户端的数目,按照Simon Riggs观点,不应该设这么大的值——32,一般为2~4即可),然后PostgreSQL,结果由于太多的信号量(semaphores)无法启动。
  • 将max_connections的值从8000调到2000(尽管此前8000用了差不多一年,按照Simon Riggs观点,8000的确太高,调整为2000是合理的)。重新启动PostgreSQL,db2.cluster仍然拒绝复制。
    更大的灾难性事故悄悄来临,因为这位YP同学一直在troubleshooting到现在(晚上11点),太累了,本来他早该下班了,该死的黑客带来麻烦!

 

第三次事故

  • 2017/01/3111pm-ish UTC:这位YP想可能是pg_basebackup拒绝工作,决定删除目录(directory),执行操作后几秒钟后发现,删除对象搞错了,本来应该删除db2.cluster.gitlab.com的目录,结果删除了db1.cluster.gitlab.com的目录.

2017/01/3111:27pm UTC:这位YP终止删除,但已经太迟了, 300 GB的数据只剩下4.5 GB

 

2. 问题分析

正如Simon Riggs说,手工删除数据库目录是非常危险的,恢复备份这样操作也很关键。这样的事情应该交给工具去做,所以他顺便为自己的公司2ndQuadrant做了广告(repmgr 3.3,Barman 2.1)。也如左耳朵耗子特别对“人肉运维”吐槽一番“直接到生产线上敲命令是一种非常不好的习惯”,说了一句名言“人管代码,代码管机器,而不是人管机器”。

相对“rm -rf”这样的命令,工具会好多了。即使用工具,也不能解决问题,人在昏头的时候,用工具也会干错事情。所以有人说,这样重要的工作,需要两个人干,一个人操作,另一个人在旁边看着,这样对企业会增大成本,特别是在紧急情况下,不一定能找到人。在本案中,这位同学因为troubleshooting没下班,另外一位值班同学这时是不是该来了?两个人一起商量着解决问题会好多了,灾难就可能不出现了。难道YP童鞋一直埋头干活,没有及时和其他人沟通?

或者像银行那样,遇到高风险的操作,需要上一层主管授权。在troubleshooting时,似乎不现实。重要的操作,还是可以电话请示一下。即使不请示,在技术上可以咨询一下同事,确认一下问题的症结所在,是不是会更好些?而不是自己猜测“可能是pg_basebackup拒绝工作”而盲目操作。即使单独行动,碰到这样关键的问题,这位同学是不是也应该自行检查一遍再提交?对于新型公司,估计平时的培训也不到位,缺少风险意识,维护人员的素质有待提高。

从人、流程看,问题是明显的。但技术问题就更多了,除了上面说的操作和max_wal_senders设置、以及max_connections原来的值,正如Gitlab官在Google DOC描述所碰到的问题,有9项之多,加上max_connections的错误设置正好十项:

  • 在默认情况下每24小时做一次LVM快照。在故障发生前大约6小时,YP幸好手动运行了一次。
  • 常规备份似乎也是每24小时做一次,不过YP还未能查清楚它们存储在何处。而且根据NJ,这些备份工作无效,只生成了几个字节大小的文件。
  • SH:pg_dump似乎失效了,原因是运行的是PostgreSQL 9.2二进制代码,而不是9.6二进制代码。之所以会这样,是因为:如果data/PG_VERSION被设成9.6,omnibus只使用Pg 9.6,但是在工作节点(workers)上,该文件根本不存在。因而在默认情况下运行9.2,悄然失效。因而没有SQL转储出现。
  • Fog gem可能清除掉了早些时候的备份。
  •  NFS服务器启用了Azure的磁盘快照,但是DB服务器没有。
  •  一旦将数据同步到试运行(staging)环境,同步过程就消除Web勾子(webhook)。除非我们能从常规备份中获取过去24小时的数据,否则它们将丢失殆尽。
  • 复制程序超级不可靠,容易出错,依赖手工的、随机性的shell脚本,而且几乎没有说明文档。
  • SH:后来我们才知道试运行的DB通过gitlab replicator目录的快照来更新,删去复制配置,重新启动单独的PostgreSQL服务器
  • 我们备份到S3的内容显然也没有奏效:存储桶(bucket)空空如也。
  • 针对备份失败,没有良好的警告或呈现(alerting/paging)机制,这在开发环境也是如此

可见环境配置、备份、快照等漏洞百出,最终没有损失24小时或更长时间的数据,或多或少有运气的成分,否则更糟糕。本质上看,也还是人的问题,说明Gitlab管理层只关注用户数增长、业务的发展,而对系统的容错性、可用性/可靠性重视明显不够。许多时候,管理层也是不见棺材不落泪,需要吃一堑长一智,平时对质量不重视,出了问题以后才会重视质量。这次出了问题,倒是好事情,Gitlab会吸取教训,对系统的安全、可靠性会重视起来,完善系统的架构和复制、备份机制等。

当然,最彻底解决问题是通过技术手段来解决,正如左耳朵耗子一再说的“不得不用更好的技术去设计出一个高可用的系统!别无它法。” 如多节点复制的分布式如多节点复制的分布式系统、区块链技术等。对于Gitlab 这样的公司,应该有高端人才加盟帮它构建高可用的系统,可以构建良好的发布、运维基础设施。如果缺乏人才,还是可以通过流程、管理等解决。解决一个问题,主要还是从三个方面:

  • 人-People,包括团队成员责任定义、个人素质;
  • 流程-Process,操作的规范性,合适的复审/评审等机制;
  • 技术-Technology,包括开发和运维平台、工具等。

为了方便记忆,三个方面记为PPT多从这三个方面找原因,多问为什么,采用5 Whys 方法,找出根本原因,加以解决。本问题的深层次原因可能就在思想深处,管理层缺少“可靠性”的质量意识,即使是技术方案的改善,也需要人力、物力的大投入,需要决心去改变系统的架构,这也需要“质量”去驱动。

参考文章:

  • 事情经过:https://about.gitlab.com/2017/02/01/gitlab-dot-com-database-incident/
  • 官方分析:https://docs.google.com/document/d/1GCK53YDcBWQveod9kfzW-VCxIABGiryG7_z_6jHdVik/pub
  • Simon Riggs,Dataloss at GitLab:http://blog.2ndquadrant.com/dataloss-at-gitlab/
  • 左耳朵耗子:我对GitLab误删除数据库事件的几点思考

 

 

Save

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我
  • 上海市嘉定区曹安公路4800号同济大学软件学院
  • kerryzhu@vip.163.com