一个缓存击穿的实验

一个缓存击穿的实验

何为缓存击穿

所谓的缓存击穿是指,一些大量的并发请求持续查询服务器的热点数据,由于热点数据通常都要事先预热保存在缓存服务器中,典型的例子是网站当前登录账号,促销商品库存等等,而一些不怀好意的人可能会向服务器发送一些参数合法但结果不存在的高并发请求,于是这些请求全都绕过了缓存服务器来到服务器的心脏持久层(这里只是一个模型,生产环境中当然要通过各种手段限制这些恶意请求,如限制短时间的请求次数,加设验证码等等),最终导致连接池达到上限,影响正常用户的访问,甚至服务器宕机.

怎样解决

设想一下这样一个场景:你家小区的看门大爷保存着一份小区所有住户的名单,他保证每次有住户搬进来或搬出去他都及时更新这份名单.有一天你的一个朋友来找你,他向看门大爷报告他要找谁,看门大爷对照它的小本子一看,嗯有这个人,你进去吧,但我不保证他现在一定在家.他去敲你家门,你可能在家,也可能出去了;又来了一个人,他告诉大爷我要找狗蛋儿,大爷一看没这个人,“我们小区没这号人,我100%肯定,你走吧”.
看吧,有个看门大爷这效率就高了,他保证了1:只要他说小区没有的人物,他肯定是对的;2:他说小区里有的,很大可能有,也可能出去了,或者刚搬走还没来得及交接.

50年前就有个叫布隆的人思考了这个问题,他设计了一个过滤器,作用是从高数量级的数据中快速判断某个给定输入是否存在其中.
这个东西的本质就是一个 BitMap,每个位非0即1的一段二进制序列
初始状态
现在有一个输入,我们需要在它存入持久层之前先映射到这个位图上,怎么做呢,没错 hash,通过某种 hash算法将得出的值模序列的位长度,并将对应的位置为1.
hash算法也无法避免 hash碰撞,因为数据无论在长度上还是内容上都是没有上限的,而 hash算法只是输入的固定长度摘要,无论如何都不能以有限的摘要完全映射所有可能的输入.
解决的办法就是通过多次不同的hash算法使一个输入映射到位图的三个位置上,对一个固定输入而言,我们要求这个 hash算法得出的’'插槽’使不同的.
这样有什么好处呢 在这里插入图片描述
上图是一个输入经过三次 hash后的状态,假设有另一个输入经过过滤器,经过三次 hash后,对应的位置不是全1,那么我可以断定,在这之前,这个数据一定没有存入持久层,因为我们要求在存入数据库前要先将这个输入映射到位图中.
那么全返回1就一定存在么?不一定,因为有 hash碰撞的存在,可能一个输入的三个’坑’在这之前都被别人占了,这很好理解吧,但我们可以通过扩大序列长度和使用散列性能更好的算法来尽量使这种"误报率"尽量的低

上代码

了解了原理后我们来感受下它的强大!
demo 使用 springboot+mybatisPlus+redisTemplate

@SpringBootTest
public class CacheBreakDownTest {
    private static final long MAX_SIZE = 10000000L;//实体数量
    private static final int THREAD_COUNT = 2000;//并发数
    private static AtomicInteger count;//线程计数器
    private static AtomicInteger hit;//报告缓存命中
    private static AtomicInteger breakDown;//报告缓存击穿
    private static AtomicInteger bfReportNotExist;//布隆过滤器报告的不存在输入的个数
    private static BloomFilter<String>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值