在2022年10月4日早晨10:00 - 12:00,Aiursoft Nextcloud发生了一次重大事故。我们的服务中断了两个小时,并且损失了一些数据。当天的可用性也严重降级。

incident

我们大约花费了两个小时来恢复这些业务和数据。下面是详细流程。

背景

Aiursoft Nextcloud是由Aiursoft运营的一个Nas存储;基于会员邀请制,受邀请的会员可以获得200GB存储空间,并享受To do、Deck、Talk、Notes、Passwords等功能。

Aiursoft Nextcloud运行在Ubuntu系统中。其系统是一个VMware虚拟机,运行于一台VMware ESXI主机上。

Aiursoft Nextcloud本身由Apache承载。并又加了一层Caddy进行反代。Caddy在另一台虚拟机上。

为了能够向公网暴露服务,Aiursoft Nextcloud还使用了FRP服务。

这台主机最近刚刚完成了存储与计算分离的迁移。

Aiursoft Nextcloud会在每日凌晨2点(UTC)定时进行自动备份。备份的目标是另一台NFS服务器。使用rsync将用户的文件复制到NFS远程。


事故初步调查

我是在早晨10点的时候,发现Nextcloud上不去了。服务器超时。同时也收到了Incident。当时我正好刚醒,立马就去修了。

首先我尝试了在内网访问,发现也上不去。确认不是代理或网络的问题。Caddy汇报502,Apache汇报500。

计划用ssh去调查服务器,发现服务器没有响应。SSH服务也挂了。

计划用cockpit去管理,发现服务也没有响应。感觉服务器好像是个死服务器了一样。

考虑到这两者都已经彻底失去管理能力了。最终降级采用VNC管理。使用Vsphere的VNC功能。

但是VNC在登陆页面卡死。初步结论就是服务器已经彻底死住了。怀疑是不是宇宙射线照到了内存上这种离谱事情发生了。。。


重启

考虑到我对这个虚拟机没有任何办法。完全无法解决,所以只能把虚拟机断电重启。重启前进行了内存快照。

断电重启后,服务器仍然无法正常开机。会在启动时大量服务无法正确加载而且会极其缓慢。

这种现象让我百思不得其解,尤其是卡住的位置每次都还不一样……非常具有迷惑性且令人困扰。


怀疑存储

最近刚刚做的变更就是做了存储与计算分离。于是开始怀疑物理服务器本身到存储设备的连接发生了诡异的变化。怀疑是ESXI到NFS的光纤出了问题。

但是感觉其它虚拟机也不太对劲,尚又没有明确范围和证据。

之前测试的时候,发现如果ESXI到NFS的连接如果不稳,其实不会立刻体现出来。ESXI有激进的双向缓存。


回滚

此时已经调研了许久,没有任何明确的结论。拿这台虚拟机也没有什么好办法。

此时比较着急想先恢复nextcloud,基本上能想到的方法都想到了。最终无奈,回滚了虚拟机备份。

比较离奇的事情是,回滚后一切正常。新开的虚拟机一切正常。与最近变更的存储和计算分离应该没有关系。


将硬盘挂载到其它机器上

此时既然无法开机,就采用了另一个方法,就是把坏了的服务器硬盘拿了出来,挂载到了一台好多服务器上,然后去观测这个硬盘。

这里发现硬盘是满的。

这里我前解释一下。这个Nextcloud服务器一共有三块盘。64GB的系统盘,1TB的数据盘,1TB的备份盘。数据盘和系统盘都是远程挂载的NFS路径。

数据盘和备份盘都是正常的,使用了大概30%。只有那个系统盘,是64GB/64GB。

所以问题就是硬盘满了。但是为什么系统盘硬盘会满呢?Nextcloud的数据都没放在系统盘里呀。明明昨天这个系统盘使用了只有19GB,为什么今天突然就64GB了呢。


硬盘为什么会满?

自然是先运行了:

du / -d 1 -h

跑了以后的结果更加令人费解。结果显示 / 下面一共只占用了19GB,不考虑 /mnt 的话。和昨天的使用量数据没错。

那么难道是虚空把64GB硬盘填满了?

到处du,du了各个目录,都一切正常。并没有离谱的大文件出现。但硬盘却满了。

想了想到底服务器上有什么会大规模写入文件的可能,唯一可能就是备份服务。


备份服务

背景:Nextcloud是在UTC的凌晨2点备份。备份的方式是:把数据盘复制到备份盘。

  • 数据盘在 /mnt/data
  • 备份盘在 /mnt/backup

有一件事情很有趣就是:如果在备份的时候,/mnt/backup没有被正确挂载,那么/mnt/backup就是系统盘下的一个文件夹了。此时如果运行备份程序,就会把300GB的数据复制到系统盘里,系统盘就满了。

仔细一看确实是这个原因。

必须把备份盘umount后,就会看到40GB的数据塞满了备份盘所在的路径 /mnt/backup

sudo umount /mnt/backup

立刻清空,重新mount,系统盘就恢复了19GB。


事故场景重现

平时 /mnt/backup 是备份盘。因为是备份,往往疏于监控,炸了也没人知道。

最近搞了存储和计算分离。将存储设备挪走了。

挪动期间可能让连接产生了瞬间中断,导致 /mnt/backup 的挂载丢失了。

此时 /mnt/backup 变成了一个普通的目录,而且在系统盘下。

这件事一直没有人注意到它,直到今天早上备份的时候。nextcloud试图将数据全部拷到 /mnt/backup 下,导致塞满了系统盘。

系统盘满了以后,对业务的影响是灾难性的。所有进程无法正常写入文件,也无法正确重启或开关机。

此时重启反而还会丢失内存缓存里面的数据,导致了巨大的灾难。尤其是大量数据挤在内存里来不及写入硬盘。


从这次事故中学习

  1. 备份这件事看似安全,实则非常危险。因为备份意味着大量的磁盘写入。配置有误会导致写入错误的磁盘。
  2. 必须建立对磁盘剩余空间的监控告警系统。磁盘满了的危险性不亚于磁盘损坏。
  3. Linux里/mnt挂载的盘,如果发生了临时性的连接性问题,可能会中断挂载。此时 /mnt/backup 会变成 / 下面的一个普通文件夹,从而被错误处理。

从这次事故中改进

  • 在运行定时备份前,都会先判断 /mnt 下面到底是不是真的磁盘
  • 建立监控报警,检查磁盘是否正确挂载正确,以及剩余容量是否健康。在剩余容量不足10%时报警。

新的备份脚本参考

set -e

if sudo df -Th | grep -q "/mnt/Backup"
then
        echo "Mounted!"
        # Backup
        sudo rm "/mnt/Backup/backups/$(ls /mnt/backup/backups/ | grep nextcloud-dirbkp | head -n 1)" -rvf
        sudo rsync -Aavx /var/www/html/nextcloud/ /mnt/backup/backups/nextcloud-dirbkp_`date +"%Y%m%d"`/
        sudo rsync -Aavx /mnt/datastorage /mnt/backup/dir/
        sudo mysqldump --single-transaction -h localhost -u root nextcloud > /home/anduin/temp.bak
        sudo mv /home/anduin/temp.bak /mnt/backup/database/nextcloud-sqlbkp_`date +"%Y%m%d"`.bak
else
        echo "Not mounted!"
        # Alert.
        echo "Backup failed! `date +"%Y-%m-%d %H:%M:%S"`" | sudo tee -a /etc/motd
        exit;
fi