BitMap算法应用:Redis队列滤重优化

工做中有用到Redis滤重队列。redis

原来的方法以下:算法

方法一数组

  • 为了保证操做原子性,使用Redis执行Lua脚本。
  • 在脚本中的逻辑是,若是队列不超过某个数值,进行一次lrem操做(队列使用list结构),而后将新元素入列。

优势:
简单,直观。性能

缺陷:编码

  1. lrem的时间复杂度为O(N),N为队列中的元素个数;因此,性能通常。
  2. 由于防止队列内容过多,防止发生N级别的删除操做,限制了一个滤重的阀值,若是超过这个阀值就不能使用滤重功能。

方法二
为了解决以上痛点,新玩法为:code

  • 为了保证操做原子性,使用Redis执行Lua脚本。
  • 一样使用Lua脚本,排重分为两步,使用了Redis自带的二进制数组进行维护是否存在重复的状态:
    1. 在入队以前,先从二进制数组中查询下这个key是否存在,即getbit key offset。若是存在说明队列中存在一个这个offset的值,就不须要进行入队操做,直接中断执行就好。
    2. 在出队的时候,将出队的元素在二进制数组中设置为不存在,即,setbit key offset 0。

优势:队列

  1. 由于是bitmap算法,在查询是否存在执行的offset的时候,时间复杂度是O(1),而且与队列中元素个数无关。
  2. 优雅,若是算是优势的话,哈哈。

缺点:ip

  1. 最重要的一点是redis bitmap的offset必须是int,好比,long范围的offset是不存在的,这是一个很重要的点,必定要注意(都是血泪史)。
  2. 由于入队和出队都进行了bitmap的数据维护,因此须要确保在编码的时候必定谨慎,足够健壮。

总结
从上面的分析来看,感受方法二完胜方法一。其实不尽然,只能说各有不一样的场景。
方法一比较通用,不论入队的内容是什么,均可能滤重,方法二依赖与Bitmap算法,意味key只能是数值型的元素。
在实际应用中,以上两种滤重方式通常是能够联合使用的。若是key是数值类型,没有超出int的取值范围,那么就直接使用方法二,若是超出了int的取值范围的数值就使用方法一。rem

扩展
还有一种滤重的算法叫:布隆过滤器,感兴趣的同窗能够了解下:Bloom filter。若是不须要删除,不在意误判率的话那应该是很合适的一个算法,空间和时间都很高效。get


另外若是有人遇到过其余的一些坑或者有更好的建议,欢迎指点。

相关文章
相关标签/搜索