Redis布谷鸟过滤器

990 阅读3分钟

使用场景

  • 大数据判断是否存在
  • 解决缓存穿透

通常一个请求过来之后我们会先查询缓存,而不用直接读取数据库,这是提升性能最普遍的方法,如果有一个黑客一直请求一个不存在的缓存。此时一定不存在,大量请求直接打到数据库,造成缓存穿透。

  • 邮箱系统的过滤

背景

在实际工作中,我们服务端会对外部流水号进行校验。如果是重复的外部流水号则会返回外部流水号重复的提示。

正常来说,这层的判断会通过查询数据库的日志表来判断,但是如果外部请求者恶意输入一个不存在的流水号会给数据库带来压力,甚至击垮数据库。

所以我们借助布谷鸟过滤器来完成校验。

布谷鸟过滤器存在误判,存在的不一定存在,不存在一定不存在。所以我们的思路是当布谷鸟存在的时候,再进行一次数据库查询,如果日志有这个流水号则返回"流水号重复"的提示。

你可能会说,那把这些key缓存到Redis就可以了。这种方案会浪费内存。使用bitmap才能极大降低内存的使用空间,原来几十GB可能使用bitmap降低到几GB。

原理

这里介绍 布隆过滤器 和 布谷鸟过滤器的原理,布谷鸟过滤器是一种升级版的布隆过滤器,以及为什么我们会选用布谷鸟过滤器。

布隆过滤器

布隆过滤器是一种专门用来解决去重问题的高级数据结构。在空间上能节省90%一。

布隆过滤器本质上是由 bitmap + 几个hash算法组成,添加元素时会使用多个hash函数对key进行运算得到一个索引值, 然后对位数组长度进行取模得到一个位置,再把位置设为1。

缺点:

  • 不支持删除
  • 查询性能不高,不同hash之后的结果,跨度较大,不连续,导致CPU缓存行命中率降低

布谷鸟hash

有两个hash表,两个hash函数组成。

会先根据hash1计算在T1的表位置,如果该位置为空可则放进去,反之根据hash2计算其T2的标位置,如果为空放进去,不为空把当前的位置踢出去,被踢出去的放入自己的另外一个位置,但是总有循环踢出导致放不下去的问题。

当遇到这种情况时候,说明布谷鸟 hash 已经到了极限情况,应该进行扩容,或者 hash 函数的优化。
布谷鸟hash就是一场踢来踢去的游戏。

布谷鸟过滤器

(c) 对数组进行了展开,从一维变成了二维,可以放 4 个元素,空间利用率从 50% 直接到了 98%,到这里,我们明白了布谷鸟过滤器对布谷鸟 hash 的优化点和对应的工作原理。

特点:

  • 支持动态的新增和删除
  • 提供更高的查询性能
  • 占用空间更小
  • 数组的长度限制在2的指数倍数

生产

可以看到 9百多万的数据 占用内存128M,可以推测 1亿的数据,占用内存 1280M ,初始化10亿 约 12.8G。

总结

布谷鸟过滤器能支持删除操作,这个特性也是项目中需要的,当一笔请求失败了,我们便会把该流水号进行删除,只保留成功的流水号在布隆过滤器里,以及他的更高的查询性能和占用空间更小,所以选择了布谷鸟过滤器。

相关博客

* mp.weixin.qq.com/s/qddJKTSXG…