Redis過濾器的實現方式(布隆過濾器 布穀鳥過濾器)

前言

昨天聊到了 Redis 的位圖, 那今天就順帶聊聊位圖的最常見場景之一: 大數據下去重過濾功能.

正文

最常見的例子: 十億郵箱去重. 無論用Redis哪種格式, 內存的消耗都是極大的. HyperLogLog 的 0.81%的錯誤率, 在這種場景又顯得太高.

所以就有了布隆過濾器.
布隆過濾器原理是通過多個 hash 函數, 將結果對應的位設爲1, 所以它能做到 100%的去重. 雖然會誤判, 但是在合理的設計的前提下, 誤判率是可以接受的.
但布隆過濾器也不是完美無缺的.
首先它的查詢性能相對較弱, 它是用 hash 函數在位圖上不同的點跳躍探測, 很難利用 cpu 緩存.
第二它不支持刪除, 假如郵箱a 的 hash 結果分別是 1 3 7, 郵箱 b 的結果是 2 6 7. 那麼在刪除郵箱a 的結果之後, 郵箱 b 也會被重新認爲是不存在, 因爲第 7 位的值是 0. 這一點布隆過濾器也很無奈.當位圖擁擠到一定程度, 只能選擇重建整個位圖.

聊這麼多, 還是得說下, redis 原生並不支持布隆過濾器, 需要自己編譯加載
https://oss.redislabs.com/redisbloom/
喜歡摸索技術的也可以用自己喜歡的語言實現, 或者使用 lua 腳本.

雖然布隆過濾器不支持刪除, 但是有升級版的布隆過濾器: Counting Bloom Filter. 它的原理就是把位圖的位 升級爲計數器(Counter). 添加元素, 就給對應的Counter分別+1; 刪除元素, 就給對應的Counter分別減一. 用多出幾倍存儲空間的代價, 來實現刪除功能. 雖然實現了功能, 但是不夠完美.

於是布穀鳥過濾器(Cuckoo filter)華麗降世了.
首先要說明布穀鳥過濾器並不是使用位圖實現的, 而是一維數組. 它所存儲的是數據的指紋(fingerprint).
布穀鳥過濾器使用兩個 hash 算法將新來的元素映射到數組的兩個位置. 如果兩個位置中有一個位置位空, 那麼就可以將元素直接放進去. 但是如果這兩個位置都滿了, 它就會隨機踢走一個, 然後自己霸佔了這個位置.
正如布穀鳥那樣, 把蛋下到其它鳥的窩裏. 這也是得名的由來. 但它並不是像布穀鳥那樣, 管殺不管埋, 還會爲這個被踢走的數據, 找一個新家.
這裏看一下它的公式, Cuckoo filter中只採用兩個哈希映射函數 H1 和 H2,H3用於計算數據的 fingerprint. 他們的關係如下

H3(key) = key’s fingerprint = hash(key)
H1(key) = hash1(key)
H2(key) = H1(key) ^ H1(key’s fingerprint) // 異或

從上面的公式中可以看出,當我們知道 fingerprint 和 H1(key),就可以直接算出 H2(key)。同樣如果我們知道 H2(key) 和 fpfingerprint 也可以直接算出H1(key) ---- 對偶性.
通過 fingerprint 和當前位置, 算出對應的另一個巢, 然後安放這個可憐的數據. 如果另一個巢仍然有數據, 那就爲受害者繼續尋找下一個巢.
但也有問題, 假如數組太過擁擠, 踢了幾十次仍然沒有找到空缺的巢, 那就需要爲數組擴容了.
不過原生的布穀鳥過濾器空間利用率並不高, 大約 50%. 改良的方案之一是增加 hash 函數, 讓每個元素不止有兩個巢, 這樣可以大大降低碰撞的概率, 將空間利用率提高到 95% 左右.
還有個方案是給每個位置上掛多個巢, 這樣不會馬上就擠來擠去. 也能大大降低碰撞概率, 空間利用率雖然比第一種改良方案稍低(約爲 85%), 但cpu 緩存的利用率會提高不少.
甚至還可以將兩種方案結合, 據說空間利用率高達99%. 了不起的數字.
要刪除也很簡單, 找到對應位置的指紋信息刪除即可.
但布穀鳥過濾器有一個明顯的弱點, 無法對同一個數據連續插入!
剛纔也說到了, 假如數組太擁擠, 碰撞多次仍然未找到空缺的巢, 那就需要擴容了. 那麼連續插入同一個數據, 馬上就觸發了擴容.
而且因爲存儲的只是一個字節的指紋信息, 也很難判斷插入的數據和位置上的數據, 是不是同一個數據. 算法論文上也有說明, 支持刪除, 不支持同一個數據多次插入. 要確保每一個元素不會被插入多次(kb+1). k 是指 hash 函數的個數 2,b是指單個位置上的座位數. 也就是說原生布穀鳥過濾器, 不能超過 3.

附上 Redis 模塊地址:
https://github.com/kristoff-it/redis-cuckoofilter
布穀鳥過濾器論文:
https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf

end.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章