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

提出問題

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

分析問題

考慮了一下是否能夠用redis的bitmap的方式來作一個統計周活躍的功能數組

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

小明 1 小明 2 小明 3

若是有三間房,0是男,女是1,網站

房1 房2 房2
0 1 1

若是要統計如今班上有幾位女生,就能夠看到兩個1就是兩位女生ui

在計算機裏,一個字節裏有8個二進制位,即1byte=8bit 假設有7個數字,咱們能夠按照編號放進一段連續內存裏,對應位置中存在就顯示1,其它默認都顯示0 好比 3,5,1,7,11,15,4,1 那對應的位置爲:spa

byte0  0 1 0 1 0 1 0 1
byte1  0 0 0 1 0 0 0 1
複製代碼

很明顯咱們已經方便的對這些數字作了排序了,甚至還作了排重 若是咱們要找7是否存在這個數組中,日誌

只須要7/8 對應到第一個字節byte0中
7%8對應到第7位上,若是是1就存在,0就不存在。
複製代碼

若是兩億的數字作排序排重,咱們大概要佔用好幾G的空間,若是用bitmap方式,最少只須要200000000/8/1024/1024 = 24M的空間就夠了code

接下來咱們看看bitmap在redis上的應用:

假設這是咱們uid的登陸狀況 0表明未登陸,1表明登陸對象

Monday
8987129 0
8298191 1
8892198 1

Tuesday
8987129 0
8298191 0
8892198 1

Wednesday
8987129 1
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
複製代碼
127.0.0.1:6379> setbit Monday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Monday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Monday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Tuesday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Tuesday 8298191 0
(integer) 0
127.0.0.1:6379> setbit Tuesday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Wednesday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Wednesday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Wednesday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Thursday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Thursday 8298191 0
(integer) 0
127.0.0.1:6379> setbit Thursday 8892198 0
(integer) 0
127.0.0.1:6379> setbit Friday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Friday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Friday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Saturday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Saturday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Saturday 8892198 0
(integer) 0
127.0.0.1:6379> setbit Sunday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Sunday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Sunday 8892198 0
(integer) 0
複製代碼

接下來要計算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天內登陸過的活躍用戶:

127.0.0.1:6379> bitop OR result Monday Tuesday Wednesday Thursday Friday Saturday Sunday
複製代碼
bitop operation rs key1 [key2..]    
對key1 key2作opecation並將結果保存在rs上
opecation能夠是AND(與) OR(或) NOT(非) XOR(異或)
複製代碼

                                                     

這裏計算的結果假設3個uid都是連續的話就是 110,其實多是 ...1.....1....0...... 也就是本週有兩個活躍用戶登陸過。

就這樣,一個上億訪問量的日誌統計,在redis的bitmap方式輕鬆解決。

相關文章
相關標籤/搜索