OpenResty 从入门到实战
温铭
OpenResty 软件基金会第一任主席,Apache APISIX 项目 VP
20903 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 52 讲
结束语 (1讲)
OpenResty 从入门到实战
15
15
1.0x
00:00/00:00
登录|注册

40 | 缓存与风暴并存,谁说缓存风暴不可避免?

封装共享字典和外部存储
源码实现
示例
非阻塞lock API
proxy_cache_use_stale
proxy_cache_lock
lua-resty-shcache
lua-resty-lock
获取最新数据放入共享字典
定时任务
隐患
逻辑正常
长时间压力测试
缓存失效时查询数据库
大量并发请求
作业题
提升编码水平或使用封装类库
缓存风暴难以发现
Nginx配置指令
加锁
主动更新缓存
伪代码示例
问题发现
定义
lru缓存
共享字典
总结
避免缓存风暴
缓存风暴
缓存
缓存与缓存风暴

该思维导图由 AI 生成,仅供参考

你好,我是温铭。
在前面缓存的那节课中,我为你介绍了,共享字典和 lru 缓存在高性能方面的一些优化技巧。其实,我们还遗留了一个非常重要的问题,也值得我们今天用单独的一节课来介绍,那就是“缓存风暴”。

什么是缓存风暴?

什么是缓存风暴呢?让我们先来设想下面这么一个场景。
数据源在 MySQL 数据库中,缓存的数据放在共享字典中,超时时间为 60 秒。在这 60 秒内的时间里,所有的请求都从缓存中获取数据,MySQL 没有任何的压力。但是,一旦到达 60 秒,也就是缓存数据失效的那一刻,如果正好有大量的并发请求进来,在缓存中没有查询到结果,就要触发查询数据源的函数,那么这些请求全部都将去查询 MySQL 数据库,直接造成数据库服务器卡顿,甚至卡死。
这种现象就叫做“缓存风暴”,它也有一个对应的英文名字Dog-Pile。很明显,我们之前出现的缓存相关的代码,都没有做过对应的处理。比如下面这段代码,就是有缓存风暴隐患的伪代码:
local value = get_from_cache(key)
if not value then
value = query_db(sql)
set_to_cache(value, timeout = 60)
end
return value
这段伪代码看上去逻辑都是正常的,你使用单元测试或者端对端测试,都不会触发缓存风暴。只有长时间的压力测试才会发现这个问题,每隔 60 秒的时间,数据库就会出现一次查询的峰值,非常有规律。不过,如果你这里的缓存失效时间设置得比较长,那么缓存风暴问题被发现的几率就会降低。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

缓存风暴是指在缓存失效后,大量并发请求同时触发数据库查询,导致数据库服务器压力剧增的现象。文章介绍了缓存风暴的概念及解决方法。首先,通过主动更新缓存来避免缓存风暴,使用OpenResty中的ngx.timer.every创建定时任务,定期更新缓存数据。其次,介绍了使用lua-resty-lock库进行加锁处理,避免并发请求同时查询数据库,以及使用lua-resty-shcache库进行缓存封装。此外,还提到了Nginx配置指令proxy_cache_lock和proxy_cache_use_stale,但并不推荐使用。最后,鼓励读者在熟悉的语言和平台中探索更好的解决思路和方法,并欢迎分享讨论。整体而言,文章深入浅出地介绍了缓存风暴问题及解决方案,对于需要解决类似问题的读者具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《OpenResty 从入门到实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(9)

  • 最新
  • 精选
  • helloworld
    老师,有没有写restful api的后端框架推荐?

    作者回复: 这里有很多 https://github.com/bungle/awesome-resty#web-frameworks,但都不流行😢

    2019-08-27
    1
  • helloworld
    老师,为什么很多or的web框架只利用content_by_lua阶段?

    作者回复: 因为这样最简单直接,但并不推荐。一般我们把鉴权的放在 access 阶段,改写的放在 rewrite 阶段,这样逻辑上更清晰,后面也容易做拆分。

    2019-08-27
    1
  • manatee
    想请问下老师,定时更新缓存,和缓存失效时被动查询数据库有什么区别呢

    作者回复: 定时更新需要处理各种异常,如果失败了是否要重试,重试多少次,逻辑会比较复杂;而被动更新就很简单了,失败了就使用过期数据,等着下一个请求再去更新就行了。

    2019-08-26
    2
  • 许童童
    如果不能接受过期数据,一个请求去查询数据库,其它请求没获取到锁,则持续等待,此时这个查询请求很耗时,会不会因为大流量把openResty压垮?

    作者回复: 终端用户的等待时间就变边长,服务端会维护很多并发连接,压垮 OpenResty 倒不至于。 不能接受过期数据,这个其实是个伪命题,本来就是缓存,是允许和数据库的数据不同的。

    2019-08-26
    2
  • Geek_30e248
    解决缓存风暴:给ttl加一个随机的范围值,这样可以极大降低缓存集中失效的概率,从而避免缓存风暴
    2020-12-16
    1
  • Charles
    项目比较小,一般碰不到老师说的缓存风暴问题,但是能想到的就是主动缓存更新和前端取到缓存空值就加一个队列排队取
    2019-08-26
    1
  • 向文超
    缓存风暴 说的就是缓存血崩,血崩的经典解决方法好像还挺多的,除了加锁,还有比如设置缓存过期时间的随机抖动、对db请求限流等
    2022-09-07归属地:上海
  • Witt
    接触到两种处理缓存的方式 1. ehcache中有参数可以设置缓存最后一次访问后失效的时间,也就是说如果这个缓存一直在被访问就不会失效,直到这个缓存闲置时间超过设置的值,才会失效 2. 设置二级缓存,读取数据首先从一级缓存读取,一级缓存不存在再用二级缓存里读取,二级缓存比一级缓存失效时间有个30s的延迟,也就是说一级缓存失效后30s二级缓存才失效,更新数据也是先更新一级缓存再更新二级缓存,但更新是没有30s这么长的延迟 当然,这两种缓存都可以主动清理,第二种清理缓存的方式是先清理二级缓存再清理一级缓存
    2019-09-13
  • 李春恒
    2019-09-06
收起评论
显示
设置
留言
9
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部