连载中 12/20

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

2026-05-31 · 5487 阅读 · 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)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 4 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞