数据库突然变成空白一片?还好有备份,不然就出大事了…
发现故障
某天下午,服务器突然出现大量错误报警,应用大部分功能无法正常使用,后端服务基本处于不可用状态。得知这个情况后,第一时间查看后端日志,发现大量数据库连接错误,初步分析是 MongoDB 挂了。
初因定位
尝试重启后端,手动连接 MongoDB,都出现了错误。重新启动 MongoDB,依然没有解决,此时报错提示认证失败。
于是使用初始化的账号连接,连接成功但是发现此时数据库中所有数据都已消失不见。
难道是有人删库跑路了?查看 MongoDB 挂载的/data/db
目录,发现一个文件都没有,数据文件似乎真的消失了。
故障止损
在经过一系列找回文件的操作以后,我们最终遗憾的宣布,数据大概率是找不回来了。幸运的是服务器上还保留了数天前的备份文件,虽然有点久远,但也比没有的强。重新导入数据后,服务恢复正常。
根因定位
查看 containerd 日志,发现故障发生的时候 MongoDB 容器出现了 OOM(Out Of Memory)。
难道是 k8s 帮我删库了?继续分析,发现 MongoDB 正常运行时,挂载的目录在宿主机上依然是一个数据文件也没有。推测可能是文件挂载出了问题,下面是当时的配置文件(部分):
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongo
namespace: db
spec:
selector:
matchLabels:
app: mongo
template:
metadata:
labels:
app: mongo
spec:
containers:
- name: mongo
image: mongo:5.0
ports:
- name: db
containerPort: 27017
protocol: TCP
volumeMounts:
- mountPath: /data
name: mongodb
livenessProbe:
initialDelaySeconds: 10
tcpSocket:
port: 27017
volumes:
- name: mongodb
persistentVolumeClaim:
claimName: mongo
MongoDB 官方文档中挂载的是/data/db
,而我们挂载了/data
,乍一看似乎也没什么问题,毕竟/data/db
也包含在/data
里,但就是这一个小小的不同,导致了数据的丢失。
查看 MongoDB Docker 镜像的构建过程,我们会发现有这样一行:VOLUME [/data/db /data/configdb]
。也就是说,尽管我们挂载了/data
,但对于/data/db
和/data/configdb
,容器运行时会为它们挂载新的 Volume。
但是,对于这两个 Volume,他们的生命周期是跟随 Pod 的。因此,当容器出现 OOM 或是其他原因导致 Pod 重建时,这些资源都会被释放掉,也就出现了本文最开始提到的故障。
优化改进
- 挂载正确的目录,
/data/db
而不是/data
。定期检查目录内容,看看文件是否真的存到了正确的位置 - 定期进行数据备份,定期进行数据备份,定期进行数据备份!
总结
数据千万条,备份第一条
数据不备份,亲人两行泪
附:使用 mongodump 备份
mongodump -u $MONGO_USERNAME -p $MONGO_PASSWORD --gzip --archive=/data/db/backups/mongo-backup.gz -h $MONGO_HOST