配置页那个"幽灵开关":我因为缓存刷新时机写反了,后台改完配置前台愣是"失忆"了半小时

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
站长杂谈 84 浏览 0 回复

上周给后台加了个"站点公告"的开关,逻辑贼简单——表单提交、写库、刷缓存、返回成功。本地测了两遍,丝滑。丢到测试环境,运营同事嗷嗷叫:改完保存,前台死活不生效,F5 按烂了还是老文案。

我第一反应是 CDN 缓存,清了一波,没用。又怀疑是 OpCache,reload 了 PHP-FPM,照旧。最后盯着 Network 面板发呆,发现接口返回的确实是新内容,但页面渲染出来的是旧的。这特么就邪门了。

翻代码才发现,缓存刷新的顺序我写成了:

1. 先删 Redis key
2. 再更新数据库

看出来没?删完缓存,下一步还没写库呢,另一个请求正好进来,读不到缓存,顺手从库里的旧数据重建了一份。等数据库更新完,缓存里已经是"新鲜出炉"的过期数据了。运营那边保存完立刻切前台看效果,命中概率极高。

改成先写库再删缓存,问题消失。但细想又不踏实——这中间那几毫秒,照样有窗口期。最后换成"延迟双删":删缓存 → 写库 → sleep(100ms) → 再删一次。糙是糙了点,但咱这小站够用了。

还有个副产品:配置项多了之后,我原来图省事,整个配置表丢进一个 Redis hash。结果改个"客服电话"也要全量刷新,其他配置跟着一起失效重建。现在拆成独立 key,前缀统一,批量清理时用 `SCAN` 匹配 `config:*`,粒度细多了。

最讽刺的是,我本地为啥没复现?单机开发,请求串行执行,根本撞不上那个并发窗口。有些 bug 真是"人多"才现形。

你们配置页都怎么保证缓存一致性的?我这种土法延时双删,有没有更优雅的姿势?

评论0
回复 · 0
还没有回复
微信客服 微信客服