缓存问题
-
缓存穿透:访问不存在的key,缓存不起作用
- 查询一个缓存和数据库都不存在的数据,缓存命中不到,再去数据库中查询也查不到,故也无法写入缓存。所以每次对该数据的请求都要到数据库中查询,造成缓存穿透。在该访问量大时,可能就会导致数据库gg。
- 解决方式:使用布隆过滤器过滤大部分不存在的key。
-
缓存雪崩:设置缓存时采用了相同的过期时间,导致缓存在某一时刻大量同时失效,大量查询同时落在了数据库上,造成缓存雪崩。
- 解决方式:可以设置过期时间+一个随机值 使得每个key的过期时间分开。
-
缓存击穿:相对于雪崩,缓存击穿是指某一key过期了,恰好此时针对该key有大量的请求,这种key在缓存中没有而数据库中有的情况,其请求全都从数据库中查询,这种大量并发请求将数据库压垮。
- 解决方式:
- 设置热点数据永不过期-可能会带来一定的数据一致性问题。
- 加锁:访问key之前 采用SETNX(set if not exists) 如果在缓存中不存在,数据库中存在则设置一个短期key锁来锁住对该key的访问,结束后再删除该短期key锁。
- 数据预热:将热门数据预先加载到缓存中。
- 使用布隆过滤器:其可以快速判断某个键是否可能存在缓存中,不存在则直接返回缓存未命中。
- 解决方式:
布隆过滤器
- 初始化:将所有的key通过哈希函数映射到数组上,映射到了的点值为1。添加新数据时也继续向里映射。
- 判断:如果请求的key映射不到为1的点,则一定不存在。
- 不足之处:
- 有可能会造成不存在的key当成存在的误判,尤其是数据量越大,误判率越高,因为查询的key的几个点可能正好落在别的很多个key所置1的点位上,但是实际上这些点位不是由该key所置1的。
- 布隆过滤器不能删除某个key,因为如果按照插入时的点位去删除的话,可能会有别的key所映射的在这同一个点,因此是不能去删除的
- 其优点也很明显:
- 只维护了一个位数组,不会随着数据量增加而导致内存增加
- 插入和查询都只是一些hash映射的操作,也不会随着数据量增大而导致时间复杂度增加