1. 程式人生 > 實用技巧 >十六、Redis三種特殊型別之三Bitmap

十六、Redis三種特殊型別之三Bitmap

一、BitMap是什麼

通過一個bit位來表示某個元素對應的值或者狀態,其中的key就是對應元素本身,value對應0或1,我們知道8個bit可以組成一個Byte,所以bitmap本身會極大的節省儲存空間

二、Redis中的BitMap

Redis從2.2.0版本開始新增了setbit、getbit、bitcount等幾個bitmap相關命令。雖然是新命令,但是並沒有新增新的資料型別,因為setbit等命令只不過是在set上的擴充套件。

Redis的bitmap讓我們可以實時的進行統計,並且極其節省空間。在模擬1億2千8百萬使用者的模擬環境下,在一臺MacBookPro上,典型的統計如“日使用者數”(dailyunique users) 的時間消耗小於50ms, 佔用16MB記憶體。

三、Redis中的命令

常用命令作用
1、getbit key offset用於獲取Redis中指定key對應的值,中對應offset的bit
2、setbit key key offset value用於修改指定key對應的值,中對應offset的bit
3、 bitcount key [start end]用於統計字串被設定為1的bit數
4、bitop and/or/xor/not destkey key [key …]用於對多個key求邏輯與/邏輯或/邏輯異或/邏輯非

四、bitmap的應用場景

bitmap優勢很多,用一個例子詳細說明下。

-------------------------------------------------------------------------------------------

用redis的bitmap方式統計上億訪問量的周活躍使用者

(1)提出問題

網站每天有1億的訪問量,產品提出要統計每個uid的周活躍,目前是日誌分析解決的,每天有20G的日誌,公司有dip平臺會用日誌去計算,每次要計算兩小時才能處理完。

(2)分析問題

考慮了一下是否可以用redis的bitmap的方式來做一個統計周活躍的功能

先簡單說下bitmap的原理:
假設有3個同學:

張三李四王五

如果有三間房,0是男,女是1,

房1房2房2
011

如果要統計現在班上有幾位女生,就可以看到兩個1就是兩位女生

在計算機裡,一個位元組裡有8個二進位制位,即1byte=8bit, 一個int型別是4bytes

假設有7個數字,我們可以按照編號放進一段連續記憶體裡,對應位置中存在就顯示1,其它預設都顯示0
比如6 ,3 ,8 ,32 ,36
那對應的位置為:

如何判斷int數字在tmp陣列的那個位置?
  例:
  1) 8 / 32 = 0 整數8除以32得整數部分為0,那麼整數8在tmp[0]的陣列上;
  2) 8%32 = 8 整數8模32得8,那麼整數8在tmp[0]陣列 從右向左的 第八個位置上(位置計算從0開始計數,數到8的位置)

如果兩億的數字做排序排重,我們大概要佔用好幾G的空間,如果用bitmap方式,最少只需要200000000/8/1024/1024 = 24M的空間就夠了。

(3)接下來我們看看bitmap在redis上的應用

假設這是我們uid的登入情況
898xxx代表uid ,0代表未登入,1代表登入

Monday
8987129 0
8298191 1
8892198 1

Tuesday
8987129 0
8298191 0
8892198 1

Wednesday
8987129 0
8298191 1
8892198 1

Thursday
8987129 0
8298191 0
8892198 0

Friday
8987129 0
8298191 1
8892198 1

Saturday
8987129 0
8298191 1
8892198 0

Sunday
8987129 1
8298191 1
8892198 0

用setbit方法,將這些資料錄入到redis中:

setbit key offset value
設定offset對應二進位制上的值,返回該位上的舊值

注意:如果offset過大,則會在中間填充0
   offset最大到2^32-1,即可推出最大的字串為512M

接下來要計算7天內有登入行為的使用者,只需要將週一到周天的值做位或運算就可以了。

位運算子

按位與運算子(&)
參加運算的兩個資料,按二進位制位進行“與”運算。
運算規則:0&0=0; 0&1=0; 1&0=0; 1&1=1;
即:兩位同時為“1”,結果才為“1”,否則為0

按位或運算子(|)
參加運算的兩個物件,按二進位制位進行“或”運算。
運算規則:0|0=0; 0|1=1; 1|0=1; 1|1=1;
即 :參加運算的兩個物件只要有一個為1,其值為1。

異或運算子(^)
參加運算的兩個資料,按二進位制位進行“異或”運算。
運算規則:0^0=0; 0^1=1; 1^0=1; 1^1=0;
即:參加運算的兩個物件,如果兩個相應位為“異”(值不同),則該位結果為1,否則為0。

最後計算7天內登入過的活躍使用者為2:

-------------------------------------------------------------------------------------------

還有很多優勢,比如通過 bitcount可以很快速的統計,比傳統的關係型資料庫效率高很多。

1、比如統計年活躍使用者數量

2、比如統計三天內活躍使用者數量

3、連續三天訪問的使用者數量

4、三天內沒有訪問的使用者數量

5、統計線上人數

6、bitmap的優勢,以統計活躍使用者為例

每個使用者id佔用空間為1bit,消耗記憶體非常少,儲存1億使用者量只需要12.5M

7、bitmap - Redis布隆過濾器 (應對快取穿透問題)

舉例:比如爬蟲伺服器在爬取電商網站的商品資訊時,首先經過快取,如果快取查不到,再去資料庫獲取資訊,因為爬蟲的效率很高,且sku很有可能是不存在或者已下架的,就會造成快取穿透,大量請求被髮送到資料庫,導致伺服器受到影響。

此時,可以在快取層之前,新增一個布隆過濾器,布隆 過濾器看作是一個bitmap,sku作為offset值,如果商品真實存在,bit值設為1。首先將商品資料初始化,當有請求時,通過getbit判斷sku是否有效。如果布隆過濾器認為商品不存在,就拒絕訪問,這樣就可以保護儲存層。