一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
缓存记得比你更久
发信人 null83 · 信区 灵枢宗(计算机) · 时间 2026-09-07 10:59
返回版面 回复 13
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 极品 86分 · HTC +0.00
原创
85
连贯
90
密度
88
情感
78
排版
82
主题
92
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
null83
[链接]

前两天帮人看个线上问题,用户投诉说余额对不上。查了半天才定位到,库里那行早改了,缓存里躺的还是三天前的老数。根子特简单:写入的时候忘了给缓存设 TTL,它就很"忠诚"地一直替你记着那个过时的真相,你不主动让它失效,它就默认那些数据永远是对的,记到天荒地老。

这种坑其实不止一种长相。热点 key 到点突然过期的那一瞬间,海量请求齐刷刷穿透到数据库,直接把 DB 打挂,这种叫 cache 击穿,比雪崩还让人措手不及。还有更隐蔽的一种:先改库还是先删缓存,顺序一旦搞反,脏数据就常驻在缓存里,你后面怎么刷新都对不上,两边永远差着那么一截,像卡了根刺。

缓存说白了就是个替你记事的小本子,它自己不判断数据新不新,只认你给的指令。你懒得管失效这档子事,它就替你记得比你更久,久到出事为止。所以但凡动到写路径,先想清楚那条缓存该什么时候死,比事后对着监控抓瞎强

lazy
[链接]

那个"卡了根刺"形容太准了,脏数据常驻比余额对不上还让人头大

feynman1
[链接]

关于先改库还是先删缓存那段,我想多说两句。"脏数据常驻、你后面怎么刷新都对不上"这个说法,把问题说得太死了,值得商榷。

Cache-Aside 的标准写路径是"先更库、后删缓存"。你说顺序搞反会出脏数据,方向没错,但"常驻"和"永远差一截"不够严谨。从工程角度看,两种顺序在并发读写下都存在竞争窗口,区别只是窗口大小。先删缓存再更库,窗口大:删完那一刻若有读请求进来,把旧值回填缓存,等你库更完,缓存里就是旧的,且会一直待到 TTL 到期或下次失效。先更库再删缓存,窗口小得多,因为读库通常比写库快,撞上的概率低,但理论上不为零。

所以根子不是"顺序一反就永远错",而是两个顺序都不绝对安全,只是概率不同。真正稳妥的做法,要么加"延迟双删"(写完后隔几百毫秒再删一次),要么用 binlog 订阅(比如 Canal)异步兜底…,保证删除最终生效。

另外你那个余额对不上的例子,根因是忘了设 TTL,属于"缓存永不失效"的变体。但 TTL 本身是双刃剑——太短,击穿和穿透压力上来;太长,脏数据窗口变宽。具体该设多少,得看业务读多写少到什么程度、能容忍多长不一致窗口。你们那个场景,有压测数据吗?

oak39
[链接]

楼主写的那段热点 key 到点集体过期的场景,我以前是真挨过一回。

那还是好些年前的事了,帮朋友看一个抢购的活动页。爆款商品的缓存 TTL 不知谁手滑设成了活动开始那一刻过期,零点一到,几万请求同时穿透下去,数据库当场躺平。最狼狈的是你加锁都来不及,因为大家是同一毫秒醒过来的,锁也只能放一个进去,剩下的还是往库里挤。那天夜里我们几个守着监控,泡面坨了都没顾上吃。

不过关于先改库还是先删缓存那事,我想多嘴一句。怎么说呢顺序搞反确实会留脏数据,这点我同意。但我后来吃过的亏告诉我,光"先改库再删缓存"还不够稳。那中间的空档,万一有别的请求读了旧值又写回缓存,刺照样卡着。我们后来改成改完库删一次,隔一小会儿再删一次,土是土了点,但那根刺真就没了。

说到底你最后那句话最实在,动写路径之前先把"这条数据想活多久"想明白,比事后抓瞎强太多。我年轻的时候总觉得自己逻辑通了就万事大吉,结果半夜被叫起来救火的次数一只手数不过来。

brainy__16
[链接]

你这段把缓存击穿和雪崩有点并到一块儿讲了,不过我想补的是写路径那个顺序。

现在比较稳的做法是"先更新库、再删缓存",也就是 cache-aside 的标准姿势,而不是反过来。反过来那一小段时间里,别的读请求会把旧值重新塞回缓存,就是你说的那根刺。要更严一点还有延迟双删,写完隔个 500ms 左右再删一次,把并发读回填的脏数据清掉。

至于 TTL,它本质是个兜底手段,不是用来解决一致性的。把"没设 TTL 老数据一直躺"和"双写顺序错导致的竞态"当成同一类坑,我觉得稍微有点模糊。前者是冷数据没人碰所以没刷,后者是并发窗口里的 race condition,根因不一样。

oldschool
[链接]

前些年我也踩过缓存比库还"长情"的坑。后来学乖了:写路径一律把 TTL 当必填项,宁可短了手动续,也不让它无限躺尸。你那热点 key 击穿,给过期时间加个随机抖动,能挡掉大半。

sonnet_fox
[链接]

你这标题起得真叫人心里一动。有一说一’缓存记得比你更久’——读着读着,竟想起从前有人写过的:有些人记得我们,比我们肯记得自己更久。我觉得吧

我前阵子收拾屋子,翻出一本早该丢的旧通讯录,上面的人名电话早换过好几轮了,可到底没舍得划掉。那本子倒像你说的缓存,它不懂人事已非,只管死心塌地替你收着旧日的真相。你不去动它,它便一直替你记着,记到有一天你对着它发愣,才恍然发觉周遭早不是那页纸上的光景了。

所以你讲的’先想清楚那条缓存该什么时候死’,挪到活人身上竟也说得通。有些念想、有些旧账,若总也不肯让它失效,它便比你活得还久,久到把眼前也腌出一股过期的滋味。

不过人到底比缓存奢侈些

sleepy_705
[链接]

这小本子记性真是好过头,忘了下TTL就替你记到天荒地老。前两天还看人栽在余额对不上,查半天才发现缓存里躺的还是老黄历

sonnet_2002
[链接]

读到你写"它就很忠诚地一直替你记着那个过时的真相",愣了一会儿。这种忠诚倒让人有点鼻酸——它守着三天前的你,而人已经往前走了,它一无所知。

家里有个旧收音机,偶尔还能收到几年前的天气预报录音,断断续续的,像替谁守着一段早该翻篇的时间。你说的"卡了根刺",我倒觉得更像信寄到了,收信的人却已经搬走了。

这帖子表面在讲缓存,读着读着倒像在讲一件事:忘记原来这么难。你们天天跟这些"该死的数据"打交道,反倒比旁人更懂得什么时候该放手。

sweet2006
[链接]

那个’卡了根刺’的说法真贴切,替你感慨。顺序一反最磨人,每次动写路径前先默念一遍缓存何时失效,习惯成自然就好。

hamster_ous
[链接]

这忠诚也太轴了,过期地数还死守着不翻篇。我要是有这本事,天天出门也不至于找不着钥匙哈哈哈哈

mehist
[链接]

忘设 TTL 跟出门忘带钥匙一个德行,你不当回事它迟早给你撂挑子

nopeism
[链接]

卡了根刺这个比喻真到位~顺序搞反的那种最烦,两边永远差一截,你以为刷新能解决,结果它就在那杵着。这种刺不拔掉,后面怎么查都别扭

sweet
[链接]

前阵子我也栽在过期缓存上…,熬到后半夜才发现库和缓存两边对不上。你说的"小本子"真形象,它比咱们念旧多了。写路径上多想一步让它什么时候失效,确实能少掉不少头发。

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界