首頁  >  文章  >  資料庫  >  如何使用redis的bit位操作

如何使用redis的bit位操作

WBOY
WBOY轉載
2023-05-26 14:14:562253瀏覽

本文redis試驗程式碼基於以下環境:

作業系統:Mac OS 64位元

#版本:Redis 5.0.7 64 bit

運行模式:standalone mode

redis位元運算

reids位元運算也叫位元組運算、bitmap,它提供了SETBIT、GETBIT、BITCOUNT、BITTOP四個指令用來操作二進位位元組。

先來看看一波基本運算範例

如何使用redis的bit位操作

SETBIT

語法:SETBIT key offset value

即:指令key 偏移量0/1

#setbit指令用於寫入位元組指定偏移量的二進位位元設定值,偏移量從0開始計數,且只允許寫入1或0,如果寫入非0和1的值則寫入失敗:

如何使用redis的bit位操作

##GETBIT

語法:

GETBIT key offset

即:

指令key 偏移量

gitbit指令用於取得位元組指定偏移量上的二進位值:

如何使用redis的bit位操作

BITCOUNT

語法:

BITCOUNT key

#即:

指令key

bitcount指令用來取得指定key的位元組中值為1的二進位位元的數量,之前我們寫入了偏移量0的值為1,偏移量10 的值為1,偏移量8的值為0:

如何使用redis的bit位操作

BITOP

語法:

BITOP operation destkey key [key...]

即:

指令操作結果目標key key1 key2 ...

bitop指令可以對多個位元組的key進行and(位元與)、or(位元或)、xor(位元異或)運算,並將運算結果設定到destkey:

如何使用redis的bit位操作

底層資料結構分析

SDS是redis中的一種資料結構,稱為簡單動態字串(Simple Dynamic String),並且它是一種二元安全的,在大多數的情況下redis中的字串都用SDS來儲存。

SDS的資料結構:

struct sdshdr {   #记录buff数组中已使用字节的数量   #也是SDS所保存字符串的长度   int len;   #记录buff数组中未使用字节的数量   int free;   #字节数组,字符串就存储在这个数组里   char buff[];  }
資料儲存範例:

如何使用redis的bit位操作

圖片來源《redis設計與實作》

SDS的優點:

  1. 鴻蒙官方策略合作共建-HarmonyOS技術社群

  2.  時間複雜度為O(1)

  3.  杜絕緩衝區溢位

  4.  減少修改字串長度時候所需的記憶體重新分配次數

  5.  二進位安全的API作業

  6.  相容部分C字串函數

關於SDS的詳細介紹請大家參閱《redis設計與實現》一文。

redis中的位數組採用的是String字串資料格式來存儲,而字串物件使用的正是上文說的SDS簡單動態字串資料結構。

如何使用redis的bit位操作

圖片來源《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中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除