目录
1、缓存穿透
2、缓存击穿
3、缓存雪崩
4、Redis的并发竞争key问题
1、缓存穿透
大量请求缓存中和数据库不存在的数据。
大量用户请求缓存中和数据库中不存在的数据,导致所有请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
- 布隆过滤器(增加一个原理图)
布隆过滤器的底层是一个位数组,数组的每个元素只能是0和1。
添加数据时,将数据通过多个hash算法,映射到位数组中的不同位置,并将该位置为1。
查询数据时,通过多个hash算法,找出查询数据在位数组中占据的位置,若所占位置全部为1,则说明该数据存在。
优点:不存储完整的数据,所以占用内存小,查询速度快;
缺点:hash算法映射的地址可能会重复,只能判断数据一定不存在,无法判断数据一定存在,有一定的误判率。且只支持新增和查询,不支持删除操作。
- 缓存空对象
当持久层不命中时,即使返回的空对象也存储在缓存中,并设置一个过期时间,之后再访问这个空数据就不用再去请求数据库。(防止用户反复用同一个id进行暴力攻击)
会存储很多无用的空键,占用缓存空间。
2、缓存击穿
大量请求缓存中同一个失效的热点key数据。
大量用户并发对缓存中的同一个热点key进行请求,当该热点key失效的时候,持续的大并发请求就击穿缓存,直接请求数据库,导致数据库短时间承受大量请求而崩溃。
解决方案:
- 设置热点key永不过期
- 互斥锁
多个线程同时请求同一个数据时,为第一个请求数据库的线程操作加锁,其他请求等待;等到第一个请求完成后,刷新缓存,其他请求就可以直接通过缓存获取数据。
3、缓存雪崩
大量请求缓存中大面积失效的缓存数据。
缓存同一时间大面积失效(缓存过期,缓存服务宕机),大量用户并发访问缓存时,会将请求落到数据库上,导致数据库短时间承受大量请求而崩溃。
解决方案:
- 缓存数据设置随机的过期时间,防止同一时间大量数据集合失效
- 集群,将数据分布在不同的缓存数据库中
- 限流,通过加锁或队列来控制读数据库写缓存的线程数量
4、Redis的并发竞争key问题
多个Redis的客户端同时set key引起的并发问题。
比如客户端1和客户端2需要对Redis中key为price的值+10,并发执行顺序如下:
- 客户端1读取price1 = 0;
- 客户端2读取price2 = 0;
- 客户端1写入price = price1+10 = 10;
- 客户端2写入price = price2+10 = 10。
- 最终Redis结果为10,而不是预期的20。
解决方案:
- 分布式锁
在redis的服务端用一个状态值表示锁,对锁的占用和释放通过状态值来标识
- 消息队列
把redis.set操作放在队列中,串行化处理。
- 乐观锁
假设不会冲突,使用redis命令watch进行构造。
watch:监控一个或多个键,一旦其中有一个键被修改/删除,之后的事务就不会执行。
multi:标记事务块的开始。Redis会将后续的命令逐个放入队列中。
exec:在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。
watch price
get price $price
$price = $price + 10
multi
set price $price
exec
以上内容为个人学习理解,如有问题,欢迎在评论区指出。
部分内容截取自网络,如有侵权,联系作者删除。