本文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的優點:
關於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÷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÷8÷1024÷1024≈119.21MB
也就是儲存10億的資料只需要119MB左右的記憶體空間,這對於現在動輒16G、32G集群版的redis,完全沒有問題。
要注意的是,如果你的數據量不大,那就不要把起始偏移量搞的很大,這樣也是佔空間的,比如我們只需要存儲幾百條數據,但是其中的偏移量卻很大,這就會造成了很大的記憶體空間浪費。
應用程式場景
實際專案開發中有很多業務都適合採用redis的bit來實作。
使用者簽到場景
每天的日期字串作為一個key,使用者Id作為offset,統計每天使用者的簽到情況,總的使用者簽到數
活躍用戶數統計
用戶日活、月活、留存率等均可以用redis位數組來存儲,還是以每天的日期作為key,用戶活躍了就寫入offset為用戶id的位值1。
同理月活也是如此。
使用者是否在線以及總在線人數統計
使用相同的位數組,將使用者ID映射的位元偏移量設定為1表示在線,設定為0表示離線。即可實現用戶上線查詢和總在線人數的統計
APP內用戶的全域訊息提示小紅點
現在大多數的APP裡都有站內信的功能,當有訊息的時候,則提示一個小紅點,代表使用者有新的訊息。
以上是如何使用redis的bit位操作的詳細內容。更多資訊請關注PHP中文網其他相關文章!