从库不主动删除过期键,仅通过主库同步DEL指令实现最终一致;主库负责所有过期判断与删除,并将DEL等命令传播至从库执行。

从库不主动删过期键,只靠主库同步 DEL 指令
Redis 主从架构中,从库(slave/replica)**完全不执行任何过期判断或删除逻辑**——它既不会触发惰性删除,也不会参与定期删除。所有过期键的清理动作,只发生在主库(master),且主库在真正删除一个过期键时,会把 DEL key 命令当作普通写命令,通过复制流(replication stream)原样发给从库执行。
这意味着:如果一个 key 在主库上因定期扫描或惰性访问而过期被删,从库收到 DEL 后才真正移除;但如果主库还没来得及删,从库就一直保留着这个“逻辑上已过期但物理上还存在”的 key。
- 主库上
ttl key返回-2(已删) → 从库很快也会返回-2(收到DEL后) - 主库上
ttl key返回正数 → 从库返回值可能相同,也可能更大(因为从库系统时间可能略快/慢,但 Redis 不校验时间戳) - 从库上执行
get key,即使该 key 在主库早已过期,只要没收到DEL,仍可能返回旧值
EXPIRE 和 DEL 都是传播到从库的写命令
Redis 的复制是「命令传播」而非「状态同步」。所以像 EXPIRE、PEXPIRE、PERSIST 这类修改键元数据的命令,以及最终触发的 DEL,都会被记录进主库的复制缓冲区,并重放至从库。
关键点在于:这些命令的执行时机,取决于主库自身策略,从库只是忠实复现。
-
EXPIRE key 60在主库执行 → 从库也执行一遍,更新自己的expires字典 - 主库因定期删除扫描到该 key 已过期 → 执行
DEL key→ 从库收到并执行,key 彻底消失 - 若主库因负载高、
hz设置低或 key 从未被访问,迟迟未删 → 从库就一直“滞后”存着它
网络中断或全量同步时,从库可能残留大量过期键
当从库断连后重连,若错过部分增量复制(如 repl-backlog 不够大),或触发了全量同步(RDB 快照重载),就会出现明显不一致:从库加载的 RDB 文件里,所有带过期时间的 key 都按快照时刻的 expires 字典重建 —— 但此时其中很多 key 在主库上早已过期被删。
这种“脏残留”不会自动清理,直到:① 该 key 被访问触发从库端的惰性检查(但注意:从库的惰性检查**不删除**,只返回 nil);② 主库后续再次删它并同步 DEL;③ 或者你手动执行 FLUSHDB 等操作。
- 从库的惰性检查仅用于读响应(
GET返回nil),不会触发物理删除 —— 这是和主库最根本的区别 - 没有配置
replica-serve-stale-data no时,从库甚至会继续响应这些“幻影过期键”,造成业务误判 - 监控时发现从库
used_memory明显高于主库?先查dbSize和keyspace_hits/keyspace_misses,很可能是过期键堆积
如何验证和缓解主从过期不一致
不能依赖从库的 TTL 或 GET 结果做业务判断,尤其在读写分离或故障切换场景下。真实一致性必须以主库为准,或引入额外机制兜底。
- 用
redis-cli -h 主库 --scan --pattern "*"+ttl批量采样,对比主从的过期分布差异 - 避免在从库上做“是否存在过期键”的逻辑判断;如需强一致读,应直连主库或使用
WAIT 1等待至少一个从库确认 - 若业务允许,可在写入时加一层本地缓存 TTL(如应用层维护过期时间),绕过 Redis 从库的时间偏差问题
- 升级到 Redis 7.0+ 可启用
replica-ignore-maxmemory yes,让从库在内存满时不触发淘汰(避免因策略不同导致意外删错)
主从过期不一致不是 bug,是设计使然。真正危险的不是“从库多存了一会儿”,而是业务代码默认它和主库一样及时 —— 这个假设,在跨机房、高延迟、或主库长期低负载的场景下,大概率会出问题。










