在平时的项目之中,基本都会用到redis做缓存,但是在面对高并发的系统中使用redis也会产生很多问题;比如缓存穿透,击穿和雪崩。本文将讲解什么是缓存穿透,击穿和雪崩,以及怎么避免这些问题;
假设在系统中,用户请求先去redis查询是否存在,存在则返回,不存在则取DB中查询,返回用户并写入到redis
1.缓存穿透
这种设计存在一个问题,即当用户请求的数据在redis和DB中都不存在的时候,每次请求都会到DB,如果是恶意攻击,有宕机风险,
解决方法:
1.如果发现用户请求的数据在DB和redis中都不存在,也缓存到redis,不过需要将过期时间设置的比较短,否则数据的实效性会产生很大的问题
2.对用户的请求合法性进行校验,拦截恶意重复请求
3. 布隆过滤器
简单来说布隆过滤器的用途就是帮助你判断某个值是否存在。举个例子来看下:假设我们现在有一个长度为 9 的 bit 数组,该数组的每个位置上只能保存 1 或者 0,1 标识该位置被占用,0 标识该位置未被使用。
- 对于 key1,我们借助三个 Hash 函数分别对其哈希运算。
- 再将得到的这三个哈希值对 9 求模。
- 最后将这三个模值落入到 bit 数组上。
- key2、key3 按照同样的方式再处理一遍
2.缓存击穿
缓存击穿则是对同一个热点数据,即同一个Key大并发请求,当这个key到了过期时间了,那所有请求都打到DB了;比如某一个热点事件,海量吃瓜群众同时访问微博去查看该八卦新闻,而微博 Redis 集群中数据在此刻正好过期了,那么无数的请求则直接打到了微博系统的物理 DB 上,DB 瞬间挂了;
解决方案:
1. 热点数据永不过期
比如我们可以将某个 key 的缓存时间设置为 25 小时,然后后台有个 JOB 每隔 24 小时就去批量刷新一下热点数据。就可以解决这个问题了。
2.互斥锁
这是解决缓存穿透比较常用的方法。
互斥锁简单来说就是在Redis中根据key获得的value值为空时,先锁上,然后从数据库加载,加载完毕,释放锁。若其他线程也在请求该key时,发现获取锁失败,则睡眠一段时间(比如100ms)后重试。
3.缓存雪崩
不是指redis宕机了,而是指所有的热点key同一时间都过期了,这个时候所有的请求全部打到DB,DB可能挂机
解决方案:
redis的时效时间改成随机数