缓存穿透、缓存雪崩、缓存击穿

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010473656/article/details/81207438

为了减轻 DB 高并发量查询时的压力,我们常常会在 DB 层上添加 Cache 层,将一些不常变动的、需经常查询的数据放入Cache中。这样请求会先查询Cache,查询没有命中,再将查询转到 DB 层。

这种设计能提升查询效率,减轻数据库服务器的压力,但是也会带来一定的问题,下面进行说明:

正常的请求处理流程是这样的:

  • 缓存穿透

    【起因】
    当请求查询的 key 在缓存没有命中时,会进行数据库查询。如果数据库没有查询结果,则不会写入缓存,那么如果后续大批量的请求查询在缓存和数据库都不存在的数据时,查询将穿透缓存,产生大量的数据库查询,缓存将失去其作用。

    【案例】
    例如:配置了一个定时任务,定时任务查询到的大量数据在进行下一步操作时,都需要去查询某个字典项,而这个字典项如果没有配置,则查询缓存和数据库都不会命中。如果定时任务再执行的频繁些,简直就是disaster!

    【解决方案】

    1、如果是非常重要的缓存数据,且会一直使用,则当查询返回空时,增加预警机制,例如可以发送邮件、短信、钉钉消息等。

    2、如果查询结果为空是正常的情况,则可以将空数据缓存起来,设置一个较短的超时时间,这样之后的查询可直接返回结果,不必再查询数据库。要注意当数据库该值发生变化时,一定要更新缓存,保证数据一致性。

  • 缓存雪崩

    【起因】
    缓存服务器重启,或者大量缓存数据集中在某一个时间段失效,当客户端发起大量查询请求时,缓存都不能命中,需全部查询数据库,而后写入缓存。这种情况下,数据库服务器的压力剧增,且这段期间内的查询性能也显著降低。

    【案例】
    例如:缓存服务器因 运维升级 或 故障重启。
    大批量缓存数据同时产生,且设置了相同的超时时间。

    【解决方案】

    1、运维升级 只能选择系统访问量小的时间段,故障重启由于时间不能调整,只能看天意了。

    2、当缓存失效时,通过锁或者队列来保证以单线程的方式对缓存的读写,当大批量请求时,只会有一个线程可以读写数据成功,其他线程阻塞,等待缓存被写入。

    3、不同的key,设置超时时间时,不要使用固定时长,可以在固定时长上加上一个随机值,使超时时间分散开。

  • 缓存击穿

    【起因】
    与缓存雪崩相似,由于缓存数据超时失效,导致高并发请求数据库。唯一的不同是:缓存雪崩是多个 key 失效,而缓存击穿是某个 key 失效,大量查询该 key 值的请求全部都请求了数据库。

    【案例】
    例如:商品页是缓存起来的,当这个商品参与秒杀时,如果这个页在秒杀时间刚好失效,则用户发来的大批量访问将全部查询数据库,给服务器造成巨大压力,击穿缓存。

    【解决方案】

    1、一些一直使用的缓存数据不设置超时时间,只有数据库更新时,刷新缓存;

    2、当缓存失效时,通过锁或者队列来保证以单线程的方式对缓存的读写,当大批量请求时,只会有一个线程可以读写数据成功,其他线程阻塞,等待缓存被写入。

猜你喜欢

转载自blog.csdn.net/u010473656/article/details/81207438