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

Redis后台保存和重写AOF时卡住了咋办,有啥解决思路分享

Redis的AOF(Append Only File)功能是个好东西,它能确保你的数据尽可能少丢失,它有时候也会闹脾气,最典型的就是在执行后台保存(BGSAVE)或者重写AOF(BGREWRITEAOF)的时候卡住不动了,这时候,你的Redis服务器可能会响应变慢,甚至完全停止响应,让人非常头疼,下面我就结合一些常见的经验和网络上的讨论(比如来自Redis官方文档的说明、一些技术博客像《Redis设计与实现》中的相关章节,以及像Stack Overflow这样的技术社区里的实际案例),来聊聊遇到这种情况该怎么排查和解决。

Redis后台保存和重写AOF时卡住了咋办,有啥解决思路分享

你得确认是不是真的“卡住”了,只是操作比较慢,你可以通过Redis的命令行工具执行 INFO PERSISTENCE 命令来查看持久化相关的信息,重点看几个字段:如果正在执行BGSAVE,查看rdb_bgsave_in_progress是否为1;如果正在执行BGREWRITEAOF,查看aof_rewrite_in_progress是否为1,如果这些值长时间(比如好几分钟)都是1,并且aof_current_sizerdb_last_bgsave_status等指标一直没变化,那很可能就是卡住了,观察latest_fork_usec这个值,它记录了上一次fork操作的耗时(单位微秒),如果这个值非常大,比如好几秒甚至几十秒,那问题很可能出在fork这一步。

Redis后台保存和重写AOF时卡住了咋办,有啥解决思路分享

为什么fork会这么慢呢?这通常是问题的根源,Redis为了进行后台保存或重写,需要创建一个子进程,创建子进程的核心操作是fork(),这个操作在理论上看起来是很快的,因为它使用了写时复制(Copy-on-Write)技术,当你的Redis实例占用了大量内存时(比如几十个GB),即使只是复制父进程的页表(一种内存映射结构),这个fork操作也可能变得非常耗时,尤其是在虚拟化环境或者物理机内存压力很大的情况下,这会导致Redis主进程在fork期间完全停止服务,感觉就像是“卡住”了,如果fork本身花了十几秒才完成,那么在这十几秒内,Redis是无法处理任何请求的。

Redis后台保存和重写AOF时卡住了咋办,有啥解决思路分享

第一个解决思路就是优化系统以减少fork耗时

  1. 确保有足够的内存:保证机器有充足的可用物理内存,避免系统使用交换分区(swap),一旦开始用swap,速度会急剧下降。
  2. 升级硬件或优化配置:如果可能,使用物理机而非虚拟机,因为虚拟机的fork通常更慢,据说在Linux上使用THP(透明大页)可能会让fork变慢,可以尝试禁用THP试试(命令是 echo never > /sys/kernel/mm/transparent_hugepage/enabled),但这需要根据实际情况测试。
  3. 控制Redis内存使用量:这是最根本的,如果数据量实在太大,可以考虑使用Redis集群方案,将数据分片到多个实例上,从而减少单个实例的内存占用,或者,审视一下业务,是否有些数据可以设置过期时间,或者根本没必要放在Redis里。

如果确认已经卡住了,并且影响了服务,你需要采取手动干预

  1. 谨慎终止后台进程:你可以尝试执行 BGREWRITEAOFBGSAVE 命令,如果Redis返回一个错误说已经有后台任务在运行,那么你可以使用 INFO PERSISTENCE 确认后,强行终止它,方法是找到那个卡住的子进程的PID,然后用操作系统的kill命令杀掉它,但是要非常小心,因为不当的操作可能导致AOF文件损坏,一个相对安全的方法是,在Redis命令行里执行 CONFIG SET appendonly no 临时关闭AOF,这会强制Redis中止正在进行的重写,然后再执行 CONFIG SET appendonly yes 重新开启,这期间可能会丢失一部分数据。
  2. 最后的重启大法:如果上面方法无效,或者Redis已经完全无响应,你可能需要考虑重启Redis服务,在重启之前,务必做好备份,比如把当前的AOF文件和RDB文件都复制一份以防万一,重启后,Redis会加载磁盘上的持久化文件来恢复数据。

为了预防这种情况发生,日常的监控和配置调整也很关键

  1. 监控fork耗时:定期监控 latest_fork_usec 的值,如果发现这个值在持续增长,就要警惕了。
  2. 调整触发AOF重写的条件:通过 auto-aof-rewrite-percentageauto-aof-rewrite-min-size 这两个参数,可以控制AOF重写的触发时机,可以设置一个更大的最小尺寸,避免过于频繁的重写。
  3. 使用RDB作为补充:如果你的业务可以接受几分钟的数据丢失,可以主要依赖RDB快照,或者采用RDB和AOF混合使用的策略,RDB的快照生成过程虽然也会fork,但通常比AOF重写要快一些,而且恢复数据也更快。

AOF重写或BGSAVE卡住的核心往往是内存过大导致的fork瓶颈,解决思路要从优化系统环境、控制数据规模入手,出现问题时要学会用Redis提供的命令和信息工具进行诊断,并谨慎地进行手动干预,平时做好监控和配置,防患于未然才是上策。