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


另外若是有人遇到過其餘的一些坑或者有更好的建議,歡迎指點。

相關文章
相關標籤/搜索