关于 cache 的 expire 问题

2018-02-19 16:40:26 +08:00
 gouchaoer
给应用设置一个 有 expire 的 cache,此时系统流量很大而且每个请求都用到了这个 cache,那么到了时间在 cache 过期的瞬间就会有许多请求打到 db 层,直到某个请求成功从 db 返回结果从新设置 cache 为止,为什么大家允许这种惊群效应?如果让我来设计 cache,我一定在 cache 过期之后只给某个请求去 db 更新缓存,别的请求继续用旧 cache
3018 次点击
所在节点    PHP
15 条回复
jhdxr
2018-02-19 22:05:28 +08:00
知乎:先问是不是再问为什么

这么设计然后造成 DB 被打爆的架构师早就被拖出去剁了好么。。。
gouchaoer
2018-02-20 00:03:14 +08:00
@jhdxr php 的一堆框架的 cache 组建里都没考虑这种情况好吧
chenxytw
2018-02-20 11:40:23 +08:00
这得分离出一个单独的 cache 服务来处理这个逻辑吧 0 0
有些业务系统对于这种是分出两层来,一层专门做业务逻辑,一层专门做数据服务;
业务逻辑层从数据层取数据,不管数据层是从哪里取的;
而数据层来维护如贴中所说的缓存逻辑。
gouchaoer
2018-02-20 11:50:55 +08:00
@chenxytw 搜到这篇文章讲了这个问题: https://huoding.com/2015/09/14/463
gouchaoer
2018-02-20 11:57:47 +08:00
实际上 apcu 也有原子的设置一个 expire 的缓存的 apcu_add,用这个就可以实现只有一个请求去更新缓存的策略,而这一切完全可以封装到原来的缓存中不用改一行逻辑代码
MeteorCat
2018-02-21 10:20:18 +08:00
这个问题区分看,如果是数据后台这种少数人管理的但是查询量大,过期所引起的 DB 层查询不足以让其崩溃;而大量请求接口级别,也需要区分,如登录接口这种单一用户请求,保存必然是 account:uid:1 这种单独某个用户的缓存信息,除非是这个用户不断恶意请求,否则该用户对于 DB 层面也不过是 where account='user'(一般有索引),基于这种情况对于 DB 层问题都不是太大,因为这是针对唯一性数据的处理;但是多人共享的数据就需要谨慎对待,同理在于抢票和限购这几种情况
mengzhuo
2018-02-21 11:29:00 +08:00
楼主可以参考 redis 的实现,或者直接用 redis
dangyuluo
2018-02-21 12:27:38 +08:00
如果你非得这么想的话,那么换个思路,每次请求都查询一下缓存的 TTL,10s 之内算作一个限。第一个在倒数 10s 内访问这个 cache 的,将另外一个 flag 标记为 1,然后开始从数据库里读并更新缓存,这个操作甚至可以是 block 的。其余的访问先检查下 flag,如果为 1 的话说明有别的程序正在更新缓存,我还是返回这个生命不到 10s 的缓存。
很蹩脚,不错没办法
sagaxu
2018-02-21 13:42:49 +08:00
“系统流量很大而且每个请求都用到了这个 cache ”

这种超热数据,一般量是不会太大的,我们会把它预先读入进程内 cache,用共享内存,然后定时从 db 读取刷新这些 cache,根本不走 redis,也不存在过期失效。
gouchaoer
2018-02-21 15:39:49 +08:00
@sagaxu 用一个命令行程序去刷新可以啊,可是逻辑写在一起比较好吧,而且增加运维复杂度。。
inkedawn
2018-02-21 16:42:55 +08:00
重建过程加锁
or
缓存单独更新
lolizeppelin
2018-02-22 01:01:52 +08:00
可以抄 mysql query cache 实现
msg7086
2018-02-22 01:26:22 +08:00
流量很大还用过期 hit DB 设计?架构师怕不是施乐纸。
难道不是应该有一个第三方服务来监视生命周期然后主动发起数据刷新的吗?

至于你说 PHP 框架的,PHP 程序本来就是设计成非持久运行的,做不到完美更新。
你要是旁路跑一个程序专门监视生命周期,那什么都好说。

就这么裸着撸 PHP 框架里的 cache 层的应用,本来就流量小到不可能惊群。
sagaxu
2018-02-22 02:21:34 +08:00
@gouchaoer php 里是不大好弄,其它语言里随便开个定时器就搞定了。php 碰到这种需求,只能用 swoole 这类方案了,2.0 开始大量借鉴了 Go 的特性。单进程的优越性在这种场景下特别明显。
puritania
2018-02-27 10:19:26 +08:00
换种思路? cache 永不过期,数据变更时你主动更新 cache。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/431234

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX