共計 2633 個字符,預計需要花費 7 分鐘才能閱讀完成。
這篇文章主要介紹“如何使用 redis 的 bit 位操作”的相關知識,丸趣 TV 小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“如何使用 redis 的 bit 位操作”文章能幫助大家解決問題。
本文 redis 試驗代碼基于如下環境:
操作系統:Mac OS 64 位
版本:Redis 5.0.7 64 bit
運行模式:standalone mode
redis 位操作
reids 位操作也叫位數組操作、bitmap,它提供了 SETBIT、GETBIT、BITCOUNT、BITTOP 四個命令用于操作二進制位數組。
先來看一波基本操作示例
SETBIT
語法:SETBIT key offset value
即:命令 key 偏移量 0/1
setbit 命令用于寫入位數組指定偏移量的二進制位設置值,偏移量從 0 開始計數,且只允許寫入 1 或者 0,如果寫入非 0 和 1 的值則寫入失敗:
GETBIT
語法:GETBIT key offset
即:命令 key 偏移量
gitbit 命令用于獲取位數組指定偏移量上的二進制值:
BITCOUNT
語法:BITCOUNT key
即:命令 key
bitcount 命令用于獲取指定 key 的位數組中值為 1 的二進制位的數量,之前我們寫入了偏移量 0 的值為 1,偏移量 10 的值為 1,偏移量 8 的值為 0:
BITOP
語法:BITOP operation destkey key [key…]
即:命令 操作 結果目標 key key1 key2 …
bitop 命令可以對多個位數組的 key 進行 and(按位與)、or(按位或)、xor(按位異或)運算,并將運算結果設置到 destkey 中:
底層數據結構分析
SDS 是 redis 中的一種數據結構,叫做簡單動態字符串(Simple Dynamic String),并且它是一種二進制安全的,在大多數的情況下 redis 中的字符串都用 SDS 來存儲。
SDS 的數據結構:
struct sdshdr { #記錄 buff 數組中已使用字節的數量 #也是 SDS 所保存字符串的長度 int len; #記錄 buff 數組中未使用字節的數量 int free; # 字節數組,字符串就存儲在這個數組里 char buff[]; }
數據存儲示例:
圖片來源《redis 設計與實現》
SDS 的優點:
鴻蒙官方戰略合作共建——HarmonyOS 技術社區
時間復雜度為 O(1)
杜絕緩沖區溢出
減少修改字符串長度時候所需的內存重分配次數
二進制安全的 API 操作
兼容部分 C 字符串函數
關于 SDS 的詳細介紹請大家參閱《redis 設計與實現》一文。
redis 中的位數組采用的是 String 字符串數據格式來存儲,而字符串對象使用的正是上文說的 SDS 簡單動態字符串數據結構。
圖片來源《redis 設計與實現》
大家都知道的是一個字節用的是 8 個二進制位來存儲的,也就是 8 個 0 或者 1,即一個字節可以存儲十進制 0~127 的數字,也即包含了所有的數字、英文大小寫字母以及標點符號。
1Byte=8bit
1KB=1024Byte
1MB=1024KB
1GB=1024MB
位數組在 redis 存儲世界里,每一個字節也是 8 位,初始都是:
0 0 0 0 0 0 0 0
而位操作就是在對應的 offset 偏移量上設置 0 或者 1,比如將第 3 位設置為 1,即:
0 0 0 0 1 0 0 0 # 對應 redis 操作即: setbit key 3 1
在此基礎上,如果要在偏移量為 13 的位置設置 1,即:
setbit key 13 1 # 對應 redis 中的存儲為: 0 0 1 0 | 0 0 0 0 | 0 0 0 0 | 1 0 0 0
時間復雜度
GETBIT 命令時間復雜度 O(1)
STEBIT 命令時間復雜度 O(1)
BITCOUNT 命令時間復雜度 O(n)
BITOP 命令時間復雜度 O(n)、O(n2)
我們來看 GETBIT 以及 SETBIT 命令的時間復雜度為什么是 O(1),當我們執行一個 SETBIT key 10086 1 的值的時候,reids 的計算方式如下:
獲取到要寫入位數組中的哪個字節:10086 divide;8=1260,需要寫入到位數組的下標 1260 的字節
獲取要寫入到這個字節的第幾位:10086 mod 8 = 6,需要寫入到這個字節的下標為 6 即第 7 位上去。
通過這兩種計算方式大家可以清晰的看到,位操作的 GETBIT 和 SETBIT 都是常量計算,因此它的時間復雜度為 O(1)。
而 BITCOUNT 命令需要對整個位數組的所有元素進行遍歷算出值為 1 的有多少個,當然 redis 對于大數據了的 bit 執行 bitcount 命令會有一整套復雜的優化的算法,但是核心思路還是這個意思,無非是減少部分遍歷查詢次數。比如以 128 位為一次遍歷,那么他的遍歷次數就是所有的位數除以 128。
BITTOP 命令則是根據不同的操作有不同的執行方式。比如 AND 操作,則需要查看位值為 1 的即可。
存儲空間計算
根據上面的介紹,相信大家已經知道了基于 redis 的位數組數據結構存儲的數據占用內存大小是怎么計算的了。比如有 100 億的數據,那么它需要的字節數組:
1000000000 divide;8 divide;1024 divide;1024 asymp;119.21MB
也就是存儲 10 億的數據只需要 119MB 左右的內存空間,這對于現在動輒 16G、32G 集群版的 redis,完全沒有問題。
需要注意的是,如果你的數據量不大,那就不要把起始偏移量搞的很大,這樣也是占空間的,比如我們只需要存儲幾百條數據,但是其中的偏移量卻很大,這就會造成了很大的內存空間浪費。
應用場景
實際項目開發中有很多業務都適合采用 redis 的 bit 來實現。
用戶簽到場景
每天的日期字符串作為一個 key,用戶 Id 作為 offset,統計每天用戶的簽到情況,總的用戶簽到數
活躍用戶數統計
用戶日活、月活、留存率等均可以用 redis 位數組來存儲,還是以每天的日期作為 key,用戶活躍了就寫入 offset 為用戶 id 的位值 1。
同理月活也是如此。
用戶是否在線以及總在線人數統計
同樣是使用一個位數組,用戶的 id 映射偏移量,在線標識為 1,下線標識為 0。即可實現用戶上下線查詢和總在線人數的統計
APP 內用戶的全局消息提示小紅點
現在大多數的 APP 里都有站內信的功能,當有消息的時候,則提示一個小紅點,代表用戶有新的消息。
關于“如何使用 redis 的 bit 位操作”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注丸趣 TV 行業資訊頻道,丸趣 TV 小編每天都會為大家更新不同的知識點。