關(guān)于Redis中bitmap的原理和使用詳解
一、原理
先聲明一下:Redis 有5種數(shù)據(jù)類型,而 BitMap 在 Redis 中并不是一個新的數(shù)據(jù)類型,其底層是 Redis 實現(xiàn)。
通常情況下,我們在 redis 中存儲一個字符串,如:“big”,它的位圖如下:
0.001kb = 1b = 8bit
所以,字符串“big”占3個字符,也就是24個bit位。
Redis 從 2.2.0 版本開始新增了 setbit,getbit,bitcount 等幾個 bitmap 相關(guān)命令。雖然是新命令,但是并沒有新增新的數(shù)據(jù)類型,因為 setbit 等命令只不過是在 set 上的擴(kuò)展。
利用上述命令,Redis 可以操作二進(jìn)制的位,可以取/改每一個位對應(yīng)的值,簡單寫幾個:
127.0.0.1:6379 > set hello big "OK" 127.0.0.1:6379 > getbit hello 0 "0" 127.0.0.1:6379 > getbit hello 1 "1" 127.0.0.1:6379 > setbit hello 7 1 "0" 127.0.0.1:6379 > get hello "cig"
通過上面的例子,我們可以發(fā)現(xiàn):
- getbit,setbit 可以對字符串進(jìn)行位操作,可以獲取/修改某位上的值;
- 字符串的位修改以后,字符串本身也發(fā)生了根本變化,big -> cig。
BitMap 原本的含義是用一個 bit 位來進(jìn)行0或者1的設(shè)置,映射某個元素的狀態(tài)。
由于一個比特位只能表示 0 和 1 兩種狀態(tài),也就是說一個 bit 能存儲的最多信息量是 2,所以 BitMap 能映射的狀態(tài)有限,但是使用比特位的優(yōu)勢是能大量的節(jié)省內(nèi)存空間。
二、BitMap 相關(guān)命令
在 Redis 中,Bitmap 是一串連續(xù)的2進(jìn)制數(shù)字(0或1),所以,可以把 Bitmaps 想象成一個以比特位為單位的數(shù)組,數(shù)組的每一位所在的位置為偏移(offset),數(shù)組的下標(biāo)在 Bitmaps 中叫做偏移量,在 bitmap 上可執(zhí)行AND,OR,XOR以及其它位操作。
# 設(shè)置值,其中value只能是 0 和 1 setbit key offset value # 獲取值 getbit key offset # 獲取指定范圍內(nèi)值為 1 的個數(shù) # start 和 end 以字節(jié)為單位 bitcount key start end # BitMap間的運算 # operations 位移操作符,枚舉值 AND 與運算 & OR 或運算 | XOR 異或 ^ NOT 取反 ~ # result 計算的結(jié)果,會存儲在該key中 # key1 … keyn 參與運算的key,可以有多個,空格分割,not運算只能一個key # 當(dāng) BITOP 處理不同長度的字符串時,較短的那個字符串所缺少的部分會被看作 0。返回值是保存到 destkey 的字符串的長度(以字節(jié)byte為單位),和輸入 key 中最長的字符串長度相等。 bitop [operations] [result] [key1] [keyn…] # 返回指定key中第一次出現(xiàn)指定value(0/1)的位置 bitpos [key] [value]
三、BitMap 空間計算
因為 BitMap 中的 bit 位 是 字符串的映射,字符串在 value 中的存儲是有上限的,所以 BitMap 的valu額存儲空間可以用相同的方式計算。
Redis 中字符串的最大長度是 512M,所以 BitMap 的 offset (偏移量)最大值為:
512 * 1024 * 1024 * 8 = 2^32
四、使用場景
1. 用戶簽到
很多網(wǎng)站都提供了簽到功能,并且需要展示最近一個月的簽到情況,這種情況可以使用 BitMap 來實現(xiàn)。 根據(jù)日期 offset = (今天是一年中的第幾天) % (今年的天數(shù)),key = 年份:用戶id。
如果需要將用戶的詳細(xì)簽到信息入庫的話,可以考慮使用一個一步線程來完成。
# 2021年第一天,用戶Id = userId 的用戶簽到 setbit 2021:userId 1 1
2. 統(tǒng)計活躍用戶(用戶登陸情況)
使用日期作為 key,然后用戶 id 為 offset,如果當(dāng)日活躍過就設(shè)置為1。具體怎么樣才算活躍這個標(biāo)準(zhǔn)大家可以自己指定。
假如:
- 20220101 活躍用戶情況是: [1,0,1,1,0]
- 20220102 活躍用戶情況是 :[ 1,1,0,1,0 ]
統(tǒng)計連續(xù)兩天活躍的用戶總數(shù):
bitop and dest1 20220101 20220102 # dest1 中值為1的offset,就是連續(xù)兩天活躍用戶的ID bitcount dest1
統(tǒng)計20220101 ~ 20220102 活躍過的用戶總數(shù):
bitop or dest2 20220101 20220102 # dest2 中值為1的offset,就是兩天都活躍的用戶的ID bitcount dest2
3. 統(tǒng)計用戶在線狀態(tài)
如果需要提供一個查詢當(dāng)前用戶是否在線的接口,也可以考慮使用 BitMap ,即節(jié)約空間效率又高,只需要一個 key,然后用戶 id 為 offset,如果在線就設(shè)置為 1,不在線就設(shè)置為 0。
# userId 登錄,設(shè)置狀態(tài)為1 setbit key userId 1 # 獲取 userId 的狀態(tài):1 - 在線;0 - 不在線 getbit key userId
4. 實現(xiàn)布隆過濾器
布隆過濾器解決緩存穿透。
五、總結(jié)
- bigmap 基于最小的單位bit進(jìn)行存儲,最大優(yōu)勢是非常省空間;
- 設(shè)置時候時間復(fù)雜度O(1)、讀取時候時間復(fù)雜度O(n),操作是非??斓?;
- 二進(jìn)制數(shù)據(jù)的存儲,進(jìn)行相關(guān)計算的時候非常快,也能方便擴(kuò)容;
- 不要給一個很短的 bigmap 設(shè)置很長位的偏移量的值,這樣有可能堵塞。
到此這篇關(guān)于關(guān)于Redis中bitmap的原理和使用詳解的文章就介紹到這了,更多相關(guān)Redis的bitmap原理和使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用RediSearch實現(xiàn)在Redis中全文檢索
RediSearch?是?Redis?的一個插件,它為?Redis?數(shù)據(jù)庫添加了全文搜索和查詢功能,使開發(fā)人員能夠在?Redis?中高效地執(zhí)行全文檢索操作,下面我們就來看看是具體如何使用的吧2023-08-08如何利用Redis?List實現(xiàn)Java數(shù)據(jù)庫分頁快速查詢
這篇文章主要給大家介紹了關(guān)于如何利用Redis?List實現(xiàn)Java數(shù)據(jù)庫分頁快速查詢的相關(guān)資料,Redis是一個高效的內(nèi)存數(shù)據(jù)庫,它支持包括String、List、Set、SortedSet和Hash等數(shù)據(jù)類型的存儲,需要的朋友可以參考下2024-02-02Redis 如何批量設(shè)置過期時間(PIPLINE的使用)
有時候我們并不希望redis的key一直存在。例如緩存,驗證碼等數(shù)據(jù),我們希望它們能在一定時間內(nèi)自動的被銷毀。本文就詳細(xì)的介紹一下Redis 如何批量設(shè)置過期時間,感興趣的可以了解一下2021-11-11