有這樣的一個場景需求:有上億的使用者,要統計這批使用者的登陸情況,例如一週連續登陸,連續三天是是否登陸,一週活躍天數等使用者
存在的挑戰
- 資料如何儘可能用小的空間儲存
- 如何能快速獲取指定的資料
如果使用檔案儲存
會有如下問題:
-
檔案分割變得十分麻煩
-
資料檢索非常不方便
-
使用者關聯操作複雜
如果使用資料庫表
會有如下問題:
- 佔用空間增長速度快,表急劇增大
- 使用索引,易產生碎片,每次插入資料還要維護索引,影響效能
- 要用group ,sum等運算,計算較慢
使用redis點陣圖進行儲存(setbit/getbit)
優點:
- 由於我的業務中只需要根據某個使用者id查詢是否是活躍使用者,不存在複雜的查詢條件,所以用redis很合適。
- redis中所有資料都是二進位制形式儲存的。redis支援一個setbit和getbit操作,它支援在某個key的value上直接對某個二進位制位操作,每個二進位制位都只有0和1兩種狀態,正好可以表示使用者是否活躍兩種狀態。
- 存取速度非常快
思路
- 記錄使用者登陸:每天按日期生成一個點陣圖, 使用者登陸後,把user_id位上的bit值置為1
- 把1周的點陣圖用 and 計算, 是否連續登陸用and計算,得到1即為連續登陸的使用者,簡單來說,能快速的拿到使用者是否登陸的0/1狀態,就能快速的計算出某段日期內登陸了幾天
- 如果每次執行redis比較繁瑣,可以簡單的生成追加檔案的方式,追加redis命令,例setbit到檔案中,隔一段時間統一利用pipe mode通過管道的方式直接快速存入redis
命令
redis 127.0.0.1:6379> setbit mon 3 1
(integer) 0
redis 127.0.0.1:6379> setbit mon 5 1
(integer) 0
redis 127.0.0.1:6379> setbit mon 7 1
(integer) 0
redis 127.0.0.1:6379> setbit thur 100000000 0
(integer) 0
redis 127.0.0.1:6379> setbit thur 3 1
(integer) 0
redis 127.0.0.1:6379> setbit thur 5 1
(integer) 0
redis 127.0.0.1:6379> setbit thur 8 1
(integer) 0
127.0.0.1:6379> getbit thur 8
(integer) 1
高效插入舉例
- 新建一個文字檔案,包含redis命令
*4 # 表示下面的命令有四個引數
$6 #第一個引數的長度
setbit # 引數值
$3 #第二個引數的長度
mon # 引數值
$1 #第三個引數的長度
3 # 引數值
$1 #第四個引數的長度
1 # 引數值
存於data.txt
2. 利用管道插入
cat data.txt | redis-cli –pipe
可參考學習:http://blog.csdn.net/lglgsy456/article/details/39394961