2017 gitlab宕机事件回顾

今天大家都在热议AWS down掉的事情,突然想起来了2017年gitlab.com的宕机事件,所以又去回顾了一下当时究竟发生了什么,顺便也根据当时事件的记录整理一个中文版本,其中还是有很多东西值得我们学习的。

事件回顾

这次事件发生在2017年的1月31号,当时gitlab.com整个不能访问,持续时间从17:20 UTC到第二天17:00 UTC。而且更严重的是这个事件最终造成了production数据的丢失,粗略估计有约5000个project,5000个comments以及700个新用户账户丢失了(6个小时左右的数据丢失)。好消息是Gitlab商业版本并没有受到任何影响。

数据库的建立

这次宕机事件其实是发生在数据库层面的一次灾难,所以在详细分析之前,我们来看看gitlab.com当时的数据库是什么样的架构。当时的gitlab.com使用的是一个主数据库加一个热备份数据库的架构,和我很早之前在的一个内部tool组使用的数据库架构类似,而且几乎所有的负载都是直接到主数据库那边的(也因此出过好几次负载相关的事故)。

时间线

事情的起因很简单,就是gitlab.com有人说AWS使用了Pgpool-2来做负载均衡,我们现在使用的是一个Azure的LB,要不我们也来试试Pgpool-2,所以他们就开始在staging环境中进行测试。没想到吧,原来这次宕机的起始也和AWS有关(当然根源和他没关系,相反这个feature的开发还多拯救了一些数据)。

17:20 UTC: 为了在Staging环境测试这个功能,他们的工程师就从production上拉了一个LVM的snapshot下来了,这样做主要还是想让staging的环境和production的环境数据类似,测试的结果更准确,一般来说LVM的snapshot每天也会自动备份一份,只是当时的程序员想要一个最新的进行测试,就去production上拉了一个最新的。注意就是这份拷贝最后起到了大用处。

19:00 UTC:这个时候gitlab.com的人发现他们的数据库的负载突然加大了,后来发现主要的原因是一个后台程序试图删除一个被abuse的员工账号导致的(当然还有别的负载,而且这段时间本来就会出现负载峰值,但从来没有出现过这么严重)。花了几个小时才把整个load降到正常水准。

23:00 UTC:由于这个负载很大,上面提到的备份数据库的replication跟不上了,而且lag越来越大,直到备份数据库的WAL部分都被删除了,也就是说这个时候唯一能让备份数据库和主数据同步的方法就是把备份数据库手动删除了,然后再同步一次。所以就有一个员工去真的删除了备份数据库(传说的删备份库),然后再次运行了同步的命令,没想到这个命令运行了两次都没有啥反应,这个员工就以为这个备份命令出问题了。虽然他尝试就做了一些debug的操作,但是没有发现原因。

23:30 UTC:后来有员工说这个命令开始没反应是正常的,毕竟需要一段时间才能开始真正的同步,但可惜的是这些没有被写在文档里面,前面操作的员工根本不知道这件事情(文档是多么重要啊)。在上面命令不工作的时候,又有员工来帮忙一起看,准备重试上面的操作,上面的操作是什么大家还记得吗?就是先把数据库(备份)删了,然后再重启同步。这次来帮忙的员工也准备重试一下这个操作,很多时候你那边运行不行,我这边试试说不定就好了,哈哈。可惜的是这个员工在做删除的操作的时候不小心操作在主数据库上!!!(真的传说中的删主数据库发生了),虽然他几秒钟的时间就意识到了这个问题,赶快各种ctrl+z,还是很不幸有近300GB的数据被删除了(说好的同事情谊啊)。

这就是整个事件发生的过程,没有太多的surprise,这种事情在我们日常工作中很容易就发生,下面要做的就是怎么恢复数据了。

尝试恢复

下面就是开始尝试恢复,要想恢复总得找到数据啊,现在主库的数据没了,备份数据库的数据也没了,但是gitlab.com还是有一些别的数据,这些数据保存下来是因为一些别的原因:

  1. 每24小时备份一次数据库,并且上传到Amazon的S3。每次上传都会覆盖旧的数据。
  2. 每24小时备份一次LVM snapshot,这个snapshot是针对数据库所在磁盘进行备份的。同时这个snapshot被用来作为staging环境的测试数据,这样开发的时候不会影响真实数据。
  3. 有些服务器(NTFS server)还会每24小时做一个Azure磁盘snapshot。
  4. PostgreSQL host之间的replication,主要用来做failover的。(就是我们上面说的备份数据库)

显然现在第4点的备份数据库已经没了,那我们就只能尝试从另外3个当中来进行恢复了。我们再来详细看看当时这三个备份的情况是怎么样的:

Amazon S3

首先我们来看看那个24小时备份到S3的数据库怎么样了,当去看的时候才发现这个备份的文件夹竟然是空的,对是空的!!!难以相信他们没有任何monitor和alert来监控这个。原因也很简单,就是PostgreSQL的版本不兼容,使用的备份程序是pg_dump 9.2,而他们当时运行的数据库已经升级到了PostgreSQL 9.6,两者不兼容。当时gitlab.com支持9.2和9.6两个版本,有一套机制来向前兼容,但是这套机制是在数据库层面,而gp_dump则是在应用层面,这套机制在这个层面不work。哎,一个备份丢失,虽然在也不一定用得上。

Azure Disk Snapshots

Azure Disk snapshot主要是用来防止磁盘出问题的,从它上面恢复数据是可以的,但是比较复杂。这个snapshot当时是存在Azure storage上的,每个storage account有一个30TB的限制,就说同一个storage account的恢复速度很快,但是不同storage account的host进行数据比较慢,所以在最初的时候他们就没有想用这个进行数据恢复,因此这个feature也只是在支持NTFS的服务器上使能了,其它的服务器没并有支持这个功能。

LVM Snapshot

如我们是上面所说,这个snapshot是用来拷贝production数据,然后放到staging环境中的,在当时有两个可用的拷贝:

  1. 正常的每24小时同步一次的数据,当时这个snapshot也差不多就是24小时之前的了。
  2. 上面提到的程序员自己通过同样的程序拷贝的一份用于测试pgpool-2的数据,这个数据大概是六小时前的拷贝的。

正式恢复

在有了上面这些分析之后,gitlab.com最终决定使用那个六小时前的LVM版本来恢复(功臣啊),所以大概的就是把这个snapshot从staging拷贝到了production,然后再re-enable gitlab.com。然而staging的环境使用的是Azure的标准环境,没有使用premium storage,当然主要还是从cost的角度考虑,毕竟只是一个开发环境,标准环境也够了,然而标准环境要拷贝数据的速度就不那么快了,大概只有60Mbps(瓶颈主要在磁盘),而且没法从标准环境立即改到premium的环境,所以最终这个拷贝花费了近18个小时。所以整个拷贝完成并使得数据库重新运行的时候已经是第二天的18:00UTC了。

总结

这个就是整个事件发生的全部过程,很显然这里有很多需要值得注意的地方。Gitlab.com他们自己当时也列出了多达15个work item来进行改进,我们也可以发现这件事情的背后有很多偶然,但也存在着很多必然,就如他们CEO在总结博客中所说,我们的系统不应该是一个不能犯错的系统,而应该是一个允许犯错,但能够快速恢复的系统,这句话真的很不错,值得与君共勉。

You may also like...

Leave a Reply

Your email address will not be published.