zoukankan      html  css  js  c++  java
  • BitMap算法应用:Redis队列滤重优化

    工作中有用到Redis滤重队列。

    原来的方法如下:

    方法一

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

    优点:
    简单,直观。

    缺陷:

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

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

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

    优点:

    1. 因为是bitmap算法,在查询是否存在执行的offset的时候,时间复杂度是O(1),并且与队列中元素个数无关。
    2. 优雅,如果算是优点的话,哈哈。

    缺点:

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

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

    扩展
    还有一种滤重的算法叫:布隆过滤器,感兴趣的同学可以了解下:Bloom filter。如果不需要删除,不在乎误判率的话那应该是很合适的一个算法,空间和时间都很高效。


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

  • 相关阅读:
    定义类或对象
    CSS 超出的文字显示省略号(单行、多行)
    获取Json对象的长度以及判断json对象是否为空
    第三次作业附加
    八皇后问题解题报告(dfs
    STL学习笔记(不定期更新)
    寒假作业之三
    寒假作业之二(2)
    寒假作业之二(1)
    第一篇随笔居然是总结耶
  • 原文地址:https://www.cnblogs.com/liushijie/p/5450859.html
Copyright © 2011-2022 走看看