连载中 12/20

过期与复制:Redis 自身的两套机制

2026-05-31 · 5490 阅读 · 0 评论 · 0 赞

TTL 到了,谁来删

设了 30 分钟 TTL 的 key,到期那一刻真的被删了吗?Redis 的答案是:不一定,而且不立即。给每个 key 配一个精确的定时器到点即删(定时删除)听起来最负责,但成千上万个到期事件会霸占单线程,得不偿失;完全不管、读到时再删(惰性删除)又会让再也不被访问的过期 key 永久霸占内存。Redis 的方案是两班倒:

惰性删除值班处理「被读到的」:每次访问 key 先查过期时间,过期就删掉并返回空——这次访问还顺手贡献了一次穿透风格的回源。定期删除值班处理「没人读的」:后台任务每 100ms 醒一次,从设置了 TTL 的 key 里随机抽样检查,过期比例超过四分之一就继续抽,并守住 25ms 的时间预算,单线程不能被清理工作拖太久。两班倒保证了内存不会无限膨胀,也保证了清理不会拖垮服务——至于从库,还有个特殊设定:从库不主动删过期 key,读到过期 key 返回空但自己不删,删除由主库的 DEL 同步过来。这保证了主从删除动作的一致性,代价是主从延迟窗口内从库可能多返回几次空。

主从复制:两段式同步

主从架构(读写分离、哨兵、Cluster 副本)的地基是复制。从库第一次连接主库时,数据得先「抄一遍家底」——全量同步:主库执行 bgsave 生成 RDB 快照发给从库,从库清空自己、载入 RDB;快照生成到传输完成期间主库新增的写命令,会先积压在复制缓冲区,RDB 载入完成后补发给从库。此后进入常态:命令传播,主库把每条写命令实时推给从库,从库记账记到一个 offset 上。

首次连接:  bgsave 生成RDB ──传输──> 从库载入 ──> 补发缓冲区命令
断线重连:  从库上报 offset ──在 backlog 内──> 只补发缺失段(增量)
                            └─被覆盖─> 退化成全量同步(代价大)

网络抖动断线重连是常态。主库在内存里维护一个 repl_backlog 环形缓冲区(默认 1MB,太小),从库带着 offset 回来,缺失的命令还在 backlog 里就只补发缺失段——增量同步,毫秒级恢复;断线太久 offset 被环形覆盖了,对不起,退化成全量同步,又一次 bgsave 加 RDB 传输。这就是为什么写流量大的实例要把 repl-backlog-size 调大(写 QPS × 预期最长断线秒数),几十 MB 的内存换掉一次全量同步风暴,很划算。

复制与缓存业务的相遇

这两套机制和前面的缓存话题处处呼应:主从延迟让「读从库」的回源可能读到旧值(一致性篇的延迟双删就是冲它去的);从库读过期 key 返回空,让「主库还在、从库已过期」的瞬间多出一次空值路径;而全量同步的 RDB 传输,正是大 Key 最拖速度的环节(大 Key 篇的引信之一)。机制背后的代价,要在业务层提前安排。

复制解决了「数据多副本」,但主库挂了谁来切从库上位?靠人半夜爬起来切?下一讲的主角是哨兵——主从架构的自动值班员。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#过期删除#惰性删除#定期删除#主从复制#repl_backlog

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9872 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9293 阅读 · 21 评论 · 287 赞