一 故障现象
应用无法登陆,登陆报500异常。
二 日志情况
1 | Caused by: io.lettuce.core.RedisCommandExecutionException: MISCONF Errors writing to the AOF file: No space left on device |
从日志简单分析,是磁盘满了无磁盘空间写AOF文件了。
三 检查生产redis集群机器情况
生产机器分布(三主三从,主从错开机器做高可用)
机器 | redis节点 | 说明 |
---|---|---|
redis01 | master01 slave03 | 2核8G |
redis02 | master02 slave01 | 2核8G |
redis03 | master03 slave02 | 2核8G |
查看每台机器的磁盘使用情况1
2
3
4
5
6
7
8# df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/vda1 99G 99G 0 100% /
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 49M 3.8G 2% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
tmpfs 783M 0 783M 0% /run/user/1000
查看内存,剩余1G多可用内存。
四 通过redis日志定位分析
1 | # tail -f -n 20 redis-server.log |
从redis日志”Cannot allocate memory“可以看出,已经没有足够的内存用于异步重写aof文件了。
所以并非表面看到的磁盘满了,导致了磁盘挂了,最根本原因是内存不足了,查看了内存,发现机器内存仅剩余了1G多,确实已经不够aof文件重写所需内存了(aof文件重写后的大小大概是2-3G的样子)。
查看aof文件日志,发现一堆分钟级数据大量写入缓存,根据key团队内询问是谁添加的redis缓存,并且进一步了解添加的场景。原来是为了写入分钟级数据用于算5分钟级数据,再写入mongo,写入后会有定时任务去清理redis缓存,但是清理不一定能清理干净,因为缓存数据太大。仅积累了三四天就已经把redis每台机器的内存增加了4-5G。导致最终机器内存不够用于aof文件重写了。
五 解决方法
- 先让相关同学先把分钟级数据应用赶紧停掉
- 清理redis分钟级数据,腾出足够内存
- 进入每一个redis节点 执行以下命令
BGREWRITEAOF
- 如果redis已经挂掉,并且无法再起来,则需要找一下磁盘里哪些日志或文件可以做一些清理,先清理后则能正常起来了,如果还是无法启动,则挂载一个数据盘,把redis的数据迁移到数据盘,指向数据盘再重启(然后再清理redis缓存的分钟级数据)
六 总结
这次生产事故根本原因是研发同学对redis的使用不太规范引起。
另外,我们公司运维这块对生产机器没有告警机制,磁盘爆满都未提前发现。
这次故障,导致生产停了好几个小时。多亏我们的应用目前阶段更多是公司内部在用,还未广泛对外推广使用,否则后果不堪设想。