一、缓存穿透
当客户端查询某个key时,先查询redis,如果不存在出于容错考虑会再查询数据库。如果有大量不存在的key请求时,大量请求会被映射到底层存储层,造成数据库压力过大,这就是缓存穿透。
要解决缓存穿透问题,可以有两种方案
缓存穿透方案一:布隆过滤器
首先了解一下布隆过滤器的原理
布隆过滤器是由位图(bitmap)和哈希函数组成。如下图所示,不同key在经过多个hash函数后,映射到位图的一定位置(哈希值对数组长度取模),则该位的数值设置为1,这样就完成了一次add操作(bf.add
)。
判断元素是否存在时,跟add操作一样,计算hash值,如果所有位置的值都为1,则认为元素存在。
误判的场景
假如key1和key2存在于缓存中,key3不存在于缓存中,但是当key3经过hash计算后,发现数组中值恰好被key1和key2设置为1,则会被误判为key3也存在于缓存中,所以布隆过滤器是存在一定概率误判的情况的。
所以布隆过滤器中如果存在,那么可能存在,也可能不存在,如果布隆过滤器中不存在,那一定不存在。需要根据业务及经验,设置合理的参数,以平衡准确率和内存空间。
布隆过滤器的创建提供了三个参数:
key:键值
error_rate:期望错误率,错误率越小,需要的存储空间越大
capacity:容量,元素数量超过容量时,误判率会上升
默认错误率为0.01,容量为100
bf.add
:会创建默认的布隆过滤器(即错误率为0.01,容量为100)
bf.reserve
:可以指定错误率和容量
布隆过滤器用于解决缓存穿透
把已经存在的数据存储到布隆过滤器中,如果有请求查询时,发现布隆过滤器中不存在,则直接返回,不继续查询缓存和数据库。如果存在,则查询缓存(因为有误判的情况,缓存也可能不存在,不存在时继续查询数据库)
布隆过滤器的基本操作命令
#添加单个元素 bf.add {key} {item} #添加多个元素 bf.add {key} {item} [item ...] #判断某个元素是否存在 bf.exists {key} {item} #判断多个元素是否存在 bf.mexists {key} {item} [item ...] #指定错误率和容量 bf.reserve {key} {error_rate} {capacity} [EXPANSION expansion]
缓存穿透方案二:缓存空对象
当redis不存在时,查询数据库,如果数据库也不存在,将该key存储到redis,value存储为空值,当下次有相同key请求时不会继续查询数据库,这样就需要由大量的空间来存储这些不存在的key。
二、缓存击穿
缓存击穿是指当某个key因为热点问题被超高并发访问时导致缓存失效而加载数据库的一种现象。
通常的做法时加锁-setnx
,当缓存失效时尝试获取锁,获取锁成功则访问数据库,否则就重试get缓存。
关于redis的分布式锁参考另一篇博客:Redis学习笔记(二)分布式锁