Redis 中 BitMap 的使用場景
BitMap
BitMap 原本的含義是用一個比特位來映射某個元素的狀態。由於一個比特位只能表示 0 和 1 兩種狀態,所以 BitMap 能映射的狀態有限,但是使用比特位的優勢是能大量的節省記憶體空間。
在 Redis 中,可以把 Bitmaps 想像成一個以比特位為單位的數組,數組的每個單元只能存儲0和1,數組的下標在 Bitmaps 中叫做偏移量。
需要注意的是:BitMap 在 Redis 中並不是一個新的數據類型,其底層是 Redis 實現。
BitMap 相關命令
# 設置值,其中value只能是 0 和 1
setbit key offset value
# 獲取值
getbit key offset
# 獲取指定範圍內值為 1 的個數
# start 和 end 以位元組為單位
bitcount key start end
# BitMap間的運算
# operations 位移操作符,枚舉值
AND 與運算 &
OR 或運算 |
XOR 異或 ^
NOT 取反 ~
# result 計算的結果,會存儲在該key中
# key1 … keyn 參與運算的key,可以有多個,空格分割,not運算只能一個key
# 當 BITOP 處理不同長度的字元串時,較短的那個字元串所缺少的部分會被看作 0。返回值是保存到 destkey 的字元串的長度(以位元組byte為單位),和輸入 key 中最長的字元串長度相等。
bitop [operations] [result] [key1] [keyn…]
# 返回指定key中第一次出現指定value(0/1)的位置
bitpos [key] [value]
BitMap 佔用的空間
在弄清 BitMap 到底佔用多大的空間之前,我們再來重申下:Redis 其實只支援 5 種數據類型,並沒有 BitMap 這種類型,BitMap 底層是基於 Redis 的字元串類型實現的。
我們通過下面的命令來看下 BitMap 佔用的空間大小:
# 首先將偏移量是0的位置設為1
127.0.0.1:6379> setbit csx:key:1 0 1
(integer) 0
# 通過STRLEN命令,我們可以看到字元串的長度是1
127.0.0.1:6379> STRLEN csx:key:1
(integer) 1
# 將偏移量是1的位置設置為1
127.0.0.1:6379> setbit csx:key:1 1 1
(integer) 0
# 此時字元串的長度還是為1,以為一個字元串有8個比特位,不需要再開闢新的記憶體空間
127.0.0.1:6379> STRLEN csx:key:1
(integer) 1
# 將偏移量是8的位置設置成1
127.0.0.1:6379> setbit csx:key:1 8 1
(integer) 0
# 此時字元串的長度編程2,因為一個位元組存不下9個比特位,需要再開闢一個位元組的空間
127.0.0.1:6379> STRLEN csx:key:1
(integer) 2
通過上面的實驗我們可以看出,BitMap 佔用的空間,就是底層字元串佔用的空間。假如 BitMap 偏移量的最大值是 OFFSET_MAX,那麼它底層佔用的空間就是:
(OFFSET_MAX/8)+1 = 佔用位元組數
因為字元串記憶體只能以位元組分配,所以上面的單位是位元組。
但是需要注意,Redis 中字元串的最大長度是 512M,所以 BitMap 的 offset 值也是有上限的,其最大值是:
8 * 1024 * 1024 * 512 = 2^32
由於 C語言中字元串的末尾都要存儲一位分隔符,所以實際上 BitMap 的 offset 值上限是:
(8 * 1024 * 1024 * 512) -1 = 2^32 - 1
使用場景
1. 用戶簽到
很多網站都提供了簽到功能,並且需要展示最近一個月的簽到情況,這種情況可以使用 BitMap 來實現。
根據日期 offset = (今天是一年中的第幾天) % (今年的天數),key = 年份:用戶id。
如果需要將用戶的詳細簽到資訊入庫的話,可以考慮使用一個一步執行緒來完成。
2. 統計活躍用戶(用戶登陸情況)
使用日期作為 key,然後用戶 id 為 offset,如果當日活躍過就設置為1。具體怎麼樣才算活躍這個標準大家可以自己指定。
假如 20201009 活躍用戶情況是: [1,0,1,1,0]
20201010 活躍用戶情況是 :[ 1,1,0,1,0 ]
統計連續兩天活躍的用戶總數:
bitop and dest1 20201009 20201010
# dest1 中值為1的offset,就是連續兩天活躍用戶的ID
bitcount dest1
統計20201009 ~ 20201010 活躍過的用戶:
bitop or dest2 20201009 20201010
3. 統計用戶是否在線
如果需要提供一個查詢當前用戶是否在線的介面,也可以考慮使用 BitMap 。即節約空間效率又高,只需要一個 key,然後用戶 id 為 offset,如果在線就設置為 1,不在線就設置為 0。
4. 實現布隆過濾器
參考
- //cloud.tencent.com/developer/news/387248
- //springboot.io/t/topic/272
- //blog.csdn.net/u011489043/article/details/78990162
- //www.cnblogs.com/wuhaidong/articles/10389484.html
- //segmentfault.com/a/1190000008188655