当前位置:首页 > 问答 > 正文

Redis集群 重启恢复 Redis集群从挂掉到重启的完整恢复实录

Redis集群从挂掉到重启的完整恢复实录:一场惊心动魄的数据保卫战

凌晨三点的紧急呼叫

"叮铃铃——"刺耳的电话铃声在凌晨三点十五分响起,我迷迷糊糊抓起手机,屏幕上显示着运维同事小王的名字,一种不祥的预感涌上心头。

"老大,出大事了!线上Redis集群挂了,所有业务都在报缓存异常!"

我瞬间清醒,从床上弹起来,作为公司核心缓存系统,Redis集群承载着每秒数万次的请求,一旦长时间不可用,整个电商平台将陷入瘫痪,我一边套上衣服一边在电话里吼道:"先别慌,我马上到公司,你现在立刻..."

这就是我们团队在那个不眠之夜的开场,接下来12个小时的经历,让我对Redis集群的故障恢复有了刻骨铭心的认识,我把这次完整的恢复过程记录下来,希望能帮到可能遇到类似情况的你。

第一阶段:灾情评估

03:45 公司机房

当我冲进机房时,小王和另外两名运维同事已经围在监控大屏前,从监控数据看,整个Redis集群6个节点全部显示"无法连接",而业务系统的错误日志已经堆积如山。

"什么时候开始的?"我问道。

"大约03:10左右,先是收到几个节点响应变慢的告警,不到5分钟所有节点都失联了。"小王快速回答,"我们尝试过重启单个节点,但马上就又挂掉了。"

我迅速检查了系统日志,发现大量这样的错误:

[ERROR] Redis Cluster: Connection timed out
[CRITICAL] Node 172.16.0.3:6379 failed - CLUSTERDOWN The cluster is down

初步判断,这不是简单的网络问题,而是整个集群出现了某种系统性故障。

第二阶段:故障定位

04:20 故障诊断

我们决定分头行动:

Redis集群 重启恢复 Redis集群从挂掉到重启的完整恢复实录

  1. 小王负责检查服务器硬件和系统资源
  2. 小李检查网络连接和防火墙规则
  3. 我专注分析Redis日志和持久化文件

半小时后,我们发现了几条关键线索:

  1. 服务器内存使用在故障前突然飙升到95%以上
  2. Redis日志中有大量"OOM command not allowed when used memory > 'maxmemory'"错误
  3. AOF重写操作在故障发生时正在进行

"明白了!"我拍了下桌子,"是内存爆了导致集群雪崩!"

原来,我们集群配置了maxmemory为16G,而实际物理内存是32G,但近期业务量激增,缓存数据量已经接近上限,更糟的是,AOF重写操作需要额外内存,直接触发了OOM(内存不足),Redis开始随机杀死自己的进程以释放内存,最终导致整个集群崩溃。

第三阶段:紧急恢复方案

05:10 制定恢复计划

面对这种情况,我们有几个选择:

  1. 直接重启集群:风险最高,可能因数据不一致导致更严重问题
  2. 逐个节点恢复:耗时但相对安全
  3. 从备份恢复:最安全但业务停机时间最长

考虑到业务已经中断2小时,我们决定采用折中方案:

  • 先尝试逐个节点恢复
  • 准备备份恢复作为备选方案
  • 同时联系业务方准备降级方案

第四阶段:集群重启实操

05:30 开始恢复操作

第一步:准备环境

我们首先确保有足够的磁盘空间存放持久化文件,并备份了当前的AOF和RDB文件:

mkdir /backup/redis_emergency
cp /var/lib/redis/*.aof /backup/redis_emergency
cp /var/lib/redis/*.rdb /backup/redis_emergency

第二步:调整内存配置

为了避免再次OOM,我们临时调整了系统配置:

Redis集群 重启恢复 Redis集群从挂掉到重启的完整恢复实录

# 设置overcommit_memory为1
echo 1 > /proc/sys/vm/overcommit_memory
# 调整swappiness
echo 10 > /proc/sys/vm/swappiness

第三步:逐个节点恢复

我们从集群中最早的主节点开始恢复:

# 停止Redis服务
redis-cli -h 172.16.0.1 -p 6379 shutdown
# 检查数据文件
redis-check-aof --fix appendonly.aof
redis-check-rdb dump.rdb
# 启动Redis单机模式
redis-server /etc/redis/redis.conf --port 6379 --cluster-enabled no

启动后,我们立即检查数据完整性:

redis-cli -h 172.16.0.1 -p 6379 info memory
redis-cli -h 172.16.0.1 -p 6379 dbsize

确认第一个节点数据完整后,我们按照相同步骤恢复了其他5个节点。

第四步:重建集群

所有节点都恢复后,我们需要重新建立集群关系:

redis-cli --cluster create 172.16.0.1:6379 172.16.0.2:6379 \
172.16.0.3:6379 172.16.0.4:6379 172.16.0.5:6379 172.16.0.6:6379 \
--cluster-replicas 1

注意:这里我们使用了原始节点的IP和端口,但集群会认为这是一个新集群,所以需要重新分配slot。

第五步:数据验证

集群重建后,我们进行了全面验证:

# 检查集群状态
redis-cli --cluster check 172.16.0.1:6379
# 测试数据读写
redis-cli -c -h 172.16.0.1 -p 6379 set test_key "hello"
redis-cli -c -h 172.16.0.3 -p 6379 get test_key

第五阶段:善后与优化

08:30 恢复完成

经过近3小时的紧张操作,Redis集群终于重新上线,业务系统逐渐恢复正常,但我们知道工作还没结束。

长期解决方案

  1. 内存优化

    Redis集群 重启恢复 Redis集群从挂掉到重启的完整恢复实录

    • 将maxmemory调整为物理内存的70%
    • 实现缓存的LRU淘汰策略
    • 增加内存监控告警阈值
  2. 持久化调整

    # 修改redis.conf
    appendfsync everysec
    no-appendfsync-on-rewrite yes
    aof-rewrite-incremental-fsync yes
  3. 集群架构优化

    • 增加两个节点分散负载
    • 设置合理的迁移阈值
    • 配置适当的超时参数
  4. 备份策略强化

    # 每天全量备份
    0 3 * * * /usr/bin/redis-cli bgsave && cp /var/lib/redis/dump.rdb /backup/redis/dump_$(date +\%Y\%m\%d).rdb

经验教训

这次事故给我们上了宝贵的一课:

  1. 监控不能只看服务状态:内存、持久化进程等指标同样重要
  2. 容量规划要前瞻:业务增长曲线必须纳入技术规划
  3. 演练不能走过场:故障恢复流程需要定期真实演练
  4. 文档要随手更新:集群拓扑变更后文档没及时更新,增加了恢复难度

写在最后

当太阳升起时,我们的Redis集群已经稳定运行了2小时,虽然疲惫不堪,但团队每个人都收获了难得的实战经验。

Redis集群作为关键基础设施,其稳定性直接影响业务,通过这次事件,我们不仅解决了眼前的问题,更重要的是建立了一套完整的预防-监控-恢复体系,我可以自信地说,即使再次面对类似故障,我们也能从容应对。

在运维的世界里,没有永远不坏的系统,只有准备不足的团队,希望我们的这次经历,能帮助你少走一些弯路。

发表评论