请问布隆过滤器(Bloom Filter)是如何解决缓存穿透(cache penetration)问题的?
缓存穿透应该是 当数据库中没有某个key对应的value时,缓存中也不会有该value的缓存。所以大量的对该value的查询该的请求会绕过缓存,直接查询数据库。
缓存中一般存的是 key+value ,但是布隆过滤器却可以告诉你 key 对应的value在数据库中存不存在,如果不存在就不用查询数据库了。
拿redis为例子:
请注意,用 redis 也可以做到判断 key 对应的value 在数据库中存不在,那就是把数据库里的所有value对应的key都储存在redis 中,而value可以为空,然后判断下key.IsExists()
就可以了,但是这无疑会浪费大量空间,因为存储了数据库中所有的key。而且这也不符合缓存的初衷:咱不能暴力的把所有key都存下来,而是查询了啥key,我们缓存啥key。
而布隆过滤器是一种非常高效的数据结构,把所有数据库的value对应的key 存储到布隆过滤器里,几乎不消耗什么空间,而且查询也是相当的快!但是请注意,它只能判断 key 是否存在(而且会有一定的误差)。
所以一个查询先通过布隆顾虑器判断key是否存在(key 对应的value是否存在数据库中),如果不存在直接返回空就好了。
那么布隆过滤器是怎么做到几乎不消耗空间来储存所有的key,并快速判断特定的key是否存在呢?
其实原理很简单,布隆过滤器 只是一个 byte数组,再加上几个映射函数。
每个key 都通过一系列映射函数,得到一系列的的值k,然后在这个byte数组上的把k下标的值变成1。
当要判断key是否存在时,通过映射函数映射得到的一系列k,查看byte数组相应下标k对应的值是否为1,如果有一个不为1,那么一定不存在。如果都是1 ,那么可能存在。为什么可能而不是一定呢?因为这是一个误差问题,有可能别的key把某个k的位置变成了1,key越多时,误差越大。但是放心不会很大的,这是可以控制的,byte数组越长,误差越小。
布隆过滤器是放在查询缓存之前还是放在查询数据库之前?
@dudu: 放在查询缓存之前。
如果只是对少数不存在的 key 进行大量请求,只要针对不存在的 key 进行空值缓存就行了,不一定要用布隆过滤器。如果是对大量不同的不存在的 key 进行大量请求,布隆过滤器发威的时候就到了。