从库连接数突增而主库不变是淘汰策略引发连接重置的典型信号,主库因maxmemory+LRU批量淘汰导致DEL/EXPIRE命令激增,从库同步时校验失败或输出缓冲区溢出被强制断连。

redis-cli info replication 显示从库连接数突增但主库没变化
这种不对称现象是淘汰策略引发连接重置的典型信号。主库 connected_clients 稳定,但从库 slave0 到 slaveN 的 client_list 中大量出现 idle=0、flags=S(从节点标识)但连接状态频繁断开的条目,说明从库在反复尝试重连主库——不是网络抖动,而是主库主动踢掉了它。
根本原因常是主库启用了 maxmemory + allkeys-lru(或类似淘汰策略),而从库同步时需要读取被淘汰的 key 对应的过期/删除事件。一旦主库因内存压力触发批量淘汰,会集中产生大量 DEL 或 EXPIRE 命令写入 AOF 和复制缓冲区;从库在重放这些命令时若遇到 key 已不存在(比如主库刚删完,从库还没来得及同步完前一条),就会触发协议错误或校验失败,最终导致连接被主库 reset。
- 用
redis-cli -h master info memory | grep -E "(used_memory|maxmemory|mem_policy)"确认是否启用淘汰且内存接近阈值 - 检查
redis-cli -h master info stats | grep expired_keys是否在故障时段有尖峰(>1000/s) - 对比
redis-cli -h slave info replication | grep "master_link_status",看是否伴随master_link_status:down短暂闪现
slowlog get 10 里出现大量 DEL / UNLINK 命令
DEL 是阻塞式删除,UNLINK 是异步删除,但两者在淘汰场景下都可能成为“导火索”。当慢日志中频繁出现 DEL 且耗时 >5ms(尤其对 bigkey),说明主库正在执行重量级清理操作;而从库同步线程必须等该命令执行完毕才能继续,期间复制积压缓冲区(repl_backlog)可能被撑爆,导致从库无法追上主库,最终触发连接重置。
- 执行
CONFIG SET slowlog-log-slower-than 1000(1ms 级别捕获)再查SLOWLOG GET 20 - 重点过滤:
1) "DEL",1) "UNLINK",1) "EXPIRE"—— 若占比超 30%,基本可锁定 - 注意:Redis 6.0+ 默认
DEL仍为同步行为,除非显式配置lazyfree-lazy-user-del yes
INFO clients 输出中 client_longest_output_list 持续 >1000
这个指标反映客户端输出缓冲区最大长度。从库本质上是一个特殊客户端,它的 output_buffer 存储待同步的命令数据。当主库集中淘汰,产生大量小 key 删除命令(如 DEL user:1001, DEL user:1002…),这些命令虽单条轻量,但高频堆积会导致从库输出缓冲区持续膨胀。一旦超过 client-output-buffer-limit slave 配置(默认 256MB/64MB/60秒),主库会强制关闭该从库连接。
- 运行
redis-cli -h master info clients | grep "client_longest_output_list",观察故障时段是否突破 5000 - 检查主库配置:
CONFIG GET "client-output-buffer-limit",确认 slave 项是否过紧 - 临时缓解:增大限制(如
CONFIG SET client-output-buffer-limit "slave 512mb 128mb 120"),但治标不治本
排查时最容易忽略的点:主从时钟不同步 + 集中过期
如果业务层设置了大量带固定 TTL 的 key(比如统一设为 3600 秒),而主从服务器系统时间偏差 >1 秒,就可能造成“主库认为该 key 还没过期,从库却已判定过期”的状态分裂。主库在淘汰阶段发送 EXPIRE 命令,从库收到时发现 key 已过期,拒绝执行或报错,连接随即中断。这种情况不会在 slowlog 或 expired_keys 中留下明显痕迹,但 redis-cli --latency 在从库侧会显示异常毛刺。
- 分别在主、从机器执行
date +%s.%N,比对毫秒级时间差 - 检查 NTP 服务状态:
systemctl status chronyd或ntpq -p - 避免依赖系统时间做 key 过期逻辑,改用相对时间戳(如
EXPIREAT key $(($(date +%s) + 3600)))











