redis 失效的key造成的问题
是这样得
//这里面执行判断是否存在缓存
$res = redis -> get("xxx");
if($res != null){
//返回缓存结果
return $res;//缓存返回
}
$res = db -> query("select * ...")//假设这句要3秒
redis -> setex("xxx",3600,$res)//保存到缓存,3600时间
//返回查询结果
return $res;
大概意思是这样的,就是我先从缓存取,没有就从数据库取,且存到缓存中,方便下次再去取。
但是问题就来了,假设我有千万并发,xxx 这个key存在3600,3600时间后自动销毁,必须得重新从数据库获取,而这句sql要3秒,3秒钟并发了几千万,就是查了几千万次数据库,必须得第一条成功缓存下来,后续的才不会跳过缓存返回那句,但这期间3秒却足以使服务器垮了,我想问的是怎样才能只访问一次数据库,其他那几千万访问都是从缓存取。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
可以尝试Gearman
3600秒自动销毁,你可以在3500秒的时候重新生成缓存,在缓存失效前刷新缓存。
其实是两个方案吧!
1.确定这个接口获取的热点数据并发会很高,就需要做预缓存策略,即使用定时任务去更新这个key,并设置失效时间,定时任务的时间间隔小于失效时间。
2.加锁操作,当发现没有缓存的时候,去load db的时候先判断一下是否有锁,有锁就等待。没有锁,就加锁在去load db操作。
并发导致的问题,首先考虑锁的机制来解决问题,可以使用redis 的setnx实现锁的,保证每次只有一个请求load数据,数据更新完,进行解锁
我看了下楼上几个人的回答。我感觉吧,可以定义两个缓存键值,用定时任务更新缓存。
key1没值就去取key2
key1隔3600秒更新
key2隔3590秒更新
可以看看这篇博文:缓存更新的套路
补充:
缓存被“击穿”问题(以前看过一篇文章的做法,你可以借鉴一下):
业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。类似下面的代码:
你这个问题就是比较经典的缓存穿透问题了,可以考虑两个方法
1.该key永不过期,写个定时脚本定期刷新结果,写入该key
2.或者加个访问锁。缓存更新期间的时候,set(lock, 1),然后其他请求发现lock=1,给个友好提示什么的,更新成功后,lock置为0。大原则上,宁愿用户体验差一些,也不能因为缓存穿透雪崩导致宕机。
脚本离线去刷缓存