Redis系列8:Bitmap實現億萬級數據計算

【Redis系列8:Bitmap實現億萬級數據計算】Redis系列1:深刻理解高性能Redis的本質Redis系列2:數據持久化提高可用性Redis系列3:高可用之主從架構Redis系列4:高可用之Sentinel(哨兵模式)Redis系列5:深入分析Cluster 集群模式追求性能極致:Redis6.0的多線程模型追求性能極致:客戶端緩存帶來的革命
1 前言我們在第一篇 深刻理解高性能Redis的本質 的時候就介紹過Redis的幾種基本數據結構,它是基于不同業務場景而設計的:

  • 動態字符串(REDIS_STRING):整數(REDIS_ENCODING_INT)、字符串(REDIS_ENCODING_RAW)
  • 雙端列表(REDIS_ENCODING_LINKEDLIST)
  • 壓縮列表(REDIS_ENCODING_ZIPLIST)
  • 跳躍表(REDIS_ENCODING_SKIPLIST)
  • 哈希表(REDIS_HASH)
  • 整數集合(REDIS_ENCODING_INTSET)
除了這常見數據類型,還有一些不常用的數據類型,如 BitMap、Geo、HyperLogLog 等等,他們在各自的領域為大數據量的統計 , 后面我們一一來介紹,學習下他們的實現原理和應用場景 。
2 BitMap介紹BitMap (位圖)的底層數據結構使用的是String類型的的 SDS 數據結構來保存 。因為一個字節8個bit位,為了有效的將字節的8個bit都利用到位,使用數組模式存儲 。并且每個bit都使用二值狀態表示,要么0,要么1 。所以,BitMap 是通過一個 bit 位來表示某個元素對應的值或者狀態,它的結構如下,key 對應元素本身;offset即是偏移量,固定整型,一般存數組下表或者唯一值;value存儲的是二值(要么0要么1),一般用來表示狀態,如性別、是否登錄、是否打卡等 。
Redis系列8:Bitmap實現億萬級數據計算

文章插圖
從上面可以看出這邊使用一個字節表示1行,每1行存儲8個bit,就是可以存儲8個狀態位,極大的提高了空間利用 。這也是BitMap的優勢,我們可以使用很少的字節 , 存儲大量的在線狀態、打卡標記等狀態信息 , 非常有效果 。
我們可以使用 setbit, getbit, bitcount 等幾個相關命令來管理BitMap 。語法如下:
SETBIT key offset value上面說過了 , key是元素名稱,offset 必須是數值類型,value 只能是 0 或者 1,如果我們存儲一個用戶的在線狀態,用戶,代碼如下:
//設置在線狀態// $redis->setBit('online', $uid, 1);$redis->setBit('online', 5, 1);$redis->setBit('online', 9, 1);則具體體現為:
bytebit0bit1bit2bit3bit4bit5bit6bit7buf[0]00000100buf[1]01000000可以看出用戶ID為5和9被打上1的標志,代表在線狀態,其他未設置值默認為0,是離線狀態 。除了Set之外,還有getBit、bitCount等語法,如下:
// 獲取是否在線的狀態$isOnline = $redis->getBit('online', $uid); // 獲取在線人數 統計$onlineNum = $redis->bitCount('online');3 BitMap的主要應用場景上面介紹了BitMap的原理和狀態存儲的優勢 。那我們存儲了bit位,其實目的還是為了高效的計算,而不是簡單的狀態記錄 。而在實際的應用場景中 , 他主要解決如下幾個類型的需求:
3.1 狀態統計上面其實我們已經演示過了,這種場景最常見,因為值只能是1或者0,所以所有的二值狀態的,所有存在是否對照關系的場景都可以使用 。如在線(1) 離線(0),打卡(1) 未打卡(0),登錄(1) 未登錄(0),群聊消息已閱(1) 未閱(0) 等等 。我們以用戶 離線/在線 為例子,看看如何使用 Bitmap 在海量的用戶數據之中判斷某個用戶是否是在線狀態 。假設我們使用一個online_statu 來作為key,用來存儲 用戶登錄后的狀態集合,而用戶的ID則為offset,online的狀態就用1表示,offline的狀態就用0表示 。
  • 如果1024用戶登錄系統,那么設置ID為1024的用戶為在線的代碼如下:
SETBIT online_statu 1024 1
  • 如果想看1024的用戶是否是在線狀態(這邊注意,key可能不存在,代表沒有這個用戶,這時候默認返回0),代碼如下:
GETBIT online_statu 1024
  • 如果1024的用戶退出系統,則為他執行下線,代碼如下:
SETBIT online_statu 1024 0
  • 空間上的有效利用,1億 人的狀態存儲只需要100000000/8/1024/1024 = 11.92 M,簡單的數據結構也保證了性能上的優勢 。
基于上面的討論 , 我們可以總結出一個預評估公式 , 根據實際的數據量獲取存儲空間:( offset / 8 / 1024 / 1024 ) M3.2 固定周期的簽到情況統計(周/月/年)固定周期可能是年/月/周,按照不同維度,可能有 365,31,7的bit位的統計周期 。假設這時候我們如果對于某個用戶(如1024)全年的簽到情況做統計,可以這么設計:

推薦閱讀