十六、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 |
---|---|---|
0 | 1 | 1 |
如果要統計現在班上有幾位女生,就可以看到兩個1就是兩位女生
在計算機裡,一個位元組裡有8個二進位制位,即1byte=8bit, 一個int型別是4bytes
比如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 1Tuesday
8987129 0
8298191 0
8892198 1Wednesday
8987129 0
8298191 1
8892198 1Thursday
8987129 0
8298191 0
8892198 0Friday
8987129 0
8298191 1
8892198 1Saturday
8987129 0
8298191 1
8892198 0Sunday
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是否有效。如果布隆過濾器認為商品不存在,就拒絕訪問,這樣就可以保護儲存層。