type
status
date
slug
summary
tags
category
icon
password
缓存穿透、击穿、雪崩
是什么
- 缓存击穿(Cache Breakdown):缓存击穿是指热点数据的缓存 失效 ,大量并发请求同时查询该数据,导致请求直接冲击数据库,增加数据库压力。
黑板上的答案(缓存)被擦掉后,一百个小学生(请求)举手问老师(数据库)同一个问题,老师回答不过来了。
- 缓存雪崩 (Cache Avalanche):缓存雪崩就是大量的缓存击穿共同发生,大量的缓存在同一时间失效,此时近乎于失去缓存,所有请求都会直接冲击数据库,可能会导致数据库当场宕机。
此时不是一百个了,是一万个小学生举手问老师一万个不同的问题,老师被吓到当场宕机。
- 缓存穿透(Cache Penetration):缓存穿透是指查询的数据既不在缓存中,也不在数据库中,但用户仍然频繁请求该 非法 数据,导致请求直接穿透到数据库,增加数据库压力。
" 你有没有上帝?" " 没有 " " 你有没有下帝?" " 没有 " " 你有没有左帝?" " 没有 " " 你有没有右帝?" " 没有 " ……
缓存穿透包含缓存击穿,只是多了一个处理。
怎么处理
缓存击穿
重点是解决 重建热点数据 时避免数据库被多次查询的问题,其中就需要使用到 双重检查机制(Double Check)。我们可以在获取锁后 再次检查缓存,如果缓存已经被前一个请求填充,则直接返回缓存数据,而不需要查询数据库。
具体实现步骤:
- 请求查询缓存:
- 若命中缓存,则直接返回数据;
- 若缓存未命中,则尝试获取分布式锁。
- 获取锁失败的请求:
- 进入等待状态,直到获取到锁。
- 获取锁成功的请求:
- 在查询数据库前,再次检查缓存是否已经填充:
- 如果缓存已有值(说明前一个请求已经填充),直接返回缓存数据;
- 如果缓存仍然为空,则查询数据库,并将数据回填到缓存。
- 释放锁,后续请求可直接读取缓存。
示例:
缓存雪崩
缓存雪崩好解决,重点是让缓存的失效时间不一致,让缓存不会同一时间大批量的集体失效。因此缓存的失效时间要给一个随机数,之后的处理和缓存击穿一样。
缓存穿透
缓存穿透的问题是数据本身不存在,缓存永远无法命中,因此想要抵挡这种攻击,重点是过滤这种数据不存在的无效请求。而对于数据的存在性问题,布隆过滤器能够很好地实现。
布隆过滤器的基本原理:
首先我们有一堆数据:
然后使用一个二进制的数组,数组中元素的值都为 0:
然后设计一个算法,比如现有的 Hash 函数,取得数据的 key 的 Hash 值,将其作为数组的下标,将该下标的值修改为 1,如此就可以通过数组中元素的 0 或 1 来判断该数据是否存在了。
问题:
但是 Hash 值可能会重复,尤其是数据量大的情况下,这个问题其实也好解决,之前是用一个下标来判断数据的存在与否,那么现在用两个不同的 Hash 函数,得到两个不同的 Hash 值,只有两个下标的元素值都为 1 才放行,这样就能增加精确度,以此类推。
但是同时也要增加数组长度,否则数组中几乎所有元素都为 1,此时请求任意的数据都很可能会通过,这就叫布隆过滤器的 假阳性。解决这个问题就需要大力出奇迹了,只要数组长度够大,并且 Hash 函数的数量不会增加 CPU 压力即可。(一般都选择增加数组长度,因为占用空间也不会大的离谱,而且内存不值钱)
示例:
- 取得一组数据的 key 的两个 Hash 值。
- 将该下标的元素值修改为 1。
- 作者:林明菁
- 链接:https://blog.lxuan.fun/article/Cache_Breakdown_Avalanche_Penetration
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。