1.缓存为什么可能会穿透
定义:请求去一条压根儿数据库中就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去,可能会导致你的数据库由于压力过大而宕掉。这种查询不存在数据的现象我们称为缓存穿透。
解决办法:
- 设置空值:
当数据查不到,查数据库,数据库也没有时,缓存设置为null,并设置过期时间(毕竟null无意义还浪费存储空间)。
当数据写入库时,同时替换缓存的null。
缺点:如恶意攻击,则会浪费缓存空间,如果这种null值过量的话,还会淘汰掉本身缓存存在的数据,这就会使我们的缓存命中率下降
- 布隆过滤器
- 首先我们初始化一个bit数组,比如长度为 20 亿。
- 选用一个 hash 算法,将现有产品比如上面场景的product_id 进行hash计算,最终映射到bit数组中。
- 映射到的数组值设为 1 ,其他的均为 0 。
- 对于新增的产品在写数据库之外,还要依照同样hash算法映射数组,更新对应位置的值。
- 当查询一个产品的时候,先查询这个产品是否在布隆过滤器里面,如果不在,则直接返回空给客户端,不直接穿透到数据库和缓存中。
注意:性能:bit数组性能是很快的,因为数组操作基本都是O(1)。
存储性能:20 亿的数组仅需要 2000000000/8/1024/1024 = 238M 的空间。远比直接用int数组小32倍。
布隆过滤器缺点?
- hash算法就有hash碰撞的发生,所以就有可能将并不在集合中的元素判断在里面。
- 布隆过滤器不支持删除元素
拓展:怎么优化缺点?
针对1:采用多个hash算法,只要hash结果都为1则确定在里面。
针对2:当碰撞时,就存碰撞的值得个数。
首先维护一个bit数组,长度如20亿,
其次将key按照算法计算hash值,然后将hash 值对定义的数据长度取模,得到的值即为存在数组的索引。并将该索引位置值从 0 改为 1,表示存在。
布隆过滤器核心思想,我们把一个集合的每一个元素按照某种 hash 算法计算 hash 值,然后将hash 值对定义的数据长度取模,得到的值即为存在数组的索引。并将该索引位置值从 0 改为 1 。然后我们判断一个元素是否在这个集合的时候,只需要对这个元素计算出数组的索引值,如果这个索引位置的值为 1 则证明该元素在集合内,反之则知道不在这个集合中。
下面我们通过画个图来具体的看看布隆过滤器的工作模式,帮助大家更好的理解和应用
如上图所示,A, B, C三个元素在一个集合里面,拿到一个 D 元素,然后计算它的hash值对应于数组的位置值为 1 则表示这个 D 元素也在ABC的集合里面;接着拿到元素E 同样的计算,发现对应于数组中值为 0 则表示元素 E不在集合中。