一、背景
生产环境某个处理高并发的服务出现大量Redis超时告警
二、排查步骤
1. 查看超时机器的CPU使用情况,内存和CPU没有达到瓶颈;
2. 使用view日志查看应用程序日志,确认出现大量Redis服务端返回超时错误;
3. 登录程序日志显示超时的Redis节点,使用slowlog get 命令查看 Redis 慢查询日志,通过日志发现在超时所属时间段,Redis服务端并没有发生慢查询
4. 继续查询Redis服务端日志,发现超时节点,Redis发生了AOF重写——破案
三、原因分析
1. 简单了解AOF:
AOF(Append-Only File)重写是 Redis 的一种数据持久化策略,用于解决 AOF 文件体积膨胀的问题。AOF 通过保存执行过的写命令来记录数据库状态,随着时间推移, AOF 文件中的命令数量会不断增加,导致文件体积逐渐增大。当文件体积过大时,Redis 会使用 AOF 文件重写功能来创建一个新的 AOF 文件,这个新文件会包含恢复当前数据集所需的最小命令集合,从而减小文件的体积。
2. AOF重写的过程涉及以下步骤
1> 主进程 fork 出一个子进程。
2> 子进程负责读取内存中的Redis数据库数据,并重新写入到一个临时文件中。
3> 主进程继续处理客户端的命令请求,并将这些命令追加到现有的 AOF 文件中,同时也会追加到 AOF 重写缓存中。
4> 当临时文件的内容足够丰富,能够完整恢复数据库状态时,子进程会将临时文件替换原有的 AOF 文件。
3. AOF重写触发方式:
A> 手动执行 bgrewriteaof 命令
B> 当AOF文件的大小超过配置所设定的阈值时自动在后台执行
四、原因总结
综上所述,得出故障原因为:Redis主进程AOF重写开始的时候,会 fork 一个子进程来执行重写操作,子进程会复制父进程的内存页表,而我们的 Redis 单节点内存占用很大,内存页表也很大,所以子进程会复制父进程的内存页表这个操作,耗时很长,会阻塞父进程的命令。Redis客户端配置的超时时间为 300ms,服务端AOF重写的fork操作所耗费时间为 421ms,所以导致客户端出现响应超时问题。
五、解决方案
1. 修改Redis服务端配置
auto-aof-rewrite-percentage=100
auto-aof-rewrite-min-size=5120mb
表示当 AOF 文件大小超过5gb,且当前文件大小比上次AOF重写大小增长超过100%时,进行 AOF 重写,以此减少 AOF 重写频率(具体数值可根据项目实际场景设置)。
2. 在Redis客户端每天业务低峰期,通过代码定时任务执行bgrewriteaof 命令来触发 Redis 服务端的AOF重写,保证 AOF 文件体积不会过大。
参考博客:
https://blog.csdn.net/qq_45422703/article/details/10958860
https://blog.csdn.net/github_32521685/article/details/106354737