Redis 缓存设计与一致性
· 阅读需 2 分钟
Redis 到了 2021 年,已经不是“可选优化”了。很多 Node.js 服务一旦扛到真实流量,列表读取、热点详情、配置查询这些地方,很自然就会想到把 Redis 接进来。
但真正难的地方,不是怎么把数据塞进缓存,而是缓存和数据库怎么长期保持在一个可控边界里。
缓存最容易做成什么样
很多项目一开始都会这样:
- 先查 Redis
- 没有就查数据库
- 查到后再回填 Redis
这套模式没有错,它就是最常见的 cache aside。但真正上线后麻烦会出在写路径。
写路径为什么决定缓存是否靠谱
如果文章更新后只写数据库,不删缓存,那旧数据就会一直在。
如果先删缓存再写数据库,读请求一拥而上,又可能把旧值重新写回缓存。
所以对大多数内容系统,我更常用的思路是:
- 先更新数据库
- 再删除缓存
async function updatePost(postId, payload) {
await PostModel.update(payload, {
where: { id: postId },
});
await redis.del(`post:${postId}`);
}
这不意味着它完美无缺,但在内容系统这类读多写少场景里,通常已经足够稳。
一致性不等于绝对实时
缓存设计最常见的误区,是追求“任何时刻都必须完全一致”。实际上,多数内容系统更在意的是:
- 大部分时间读得快
- 写后能尽快收敛
- 错误成本可控
只要这三点成立,缓存就是有效的。
哪些数据适合缓存
我一般会优先缓存这些内容:
- 文章详情
- 首页推荐列表
- 站点配置
- 热点标签榜单
而一些强实时、强事务的管理动作,就不适合轻易缓存。
TTL 不是万能药
给缓存统一加 5 分钟过期时间很方便,但不能指望 TTL 解决所有一致性问题。TTL 更像兜底,不是主策略。真正重要的还是写路径怎么处理。
小结
Redis 在 2021 年已经是 Node.js 服务里非常基础的一环,但缓存设计真正考验的不是“会不会用”,而是有没有能力把一致性边界说清楚。边界清楚了,Redis 才会真正帮到系统,而不是制造更多隐患。
