1. 程式人生 > >巧用redis點陣圖儲存億級資料與訪問 - 簡書

巧用redis點陣圖儲存億級資料與訪問 - 簡書

原文:巧用redis點陣圖儲存億級資料與訪問 - 簡書

業務背景

現有一個業務需求,需要從一批很大的使用者活躍資料(2億+)中判斷使用者是否是活躍使用者。由於此資料是基於使用者的各種行為日誌清洗才能得到,資料部門不能提供實時介面,只能提供包含使用者及是否活躍的指定格式的文字由業務方使用。

存在的挑戰

  1. 海量資料如何儘可能用小的空間儲存
  2. 如何能快速獲取指定的資料
  3. 如何能快速的寫入到目標儲存

解決思路

  1. 由於我的業務中只需要根據某個使用者id查詢是否是活躍使用者,不存在複雜的查詢條件,所以用redis很合適。

  2. 如此大的資料如果用普通的鍵值對一一儲存所有使用者的活躍資料,即使每個key/value佔用的記憶體很小,但數億個key/value所花費的記憶體每個節點隨便都需要數G,業務中有很多類似的需求,都用這種方式的話,儲存是個很大的問題。

這裡使用redis的點陣圖來處理。

redis中所有資料都是二進位制形式儲存的。redis支援一個setbit和getbit操作,它支援在某個key的value上直接對某個二進位制位操作,每個二進位制位都只有0和1兩種狀態,正好可以表示使用者是否活躍兩種狀態。

比如redis中鍵a的value資料的二進位制碼是
0110 0110 0001

它總共有12位,在redis的位操作中,二進位制中的第幾位稱為offset。

我們可以這樣將這個資料的第10位設定為1:
setbit a 10 1

這樣,原來的資料就變成了
0110 0110 0101

如果key不存在,也會自動建立。

當然,如果某個位還不存在,redis也會自動填充。

可以通過getbit獲取某個二進位制位的值

getbit a 10 //獲取鍵a的值上第10位的值(0或1兩種狀態)

這是所謂的點陣圖。

那麼我們考慮在redis中放一個key,通過這個key直接操作二進位制位,redis中單個key的最大值是512M,可以達到40多億bit,足夠很多業務的需要了。我們以使用者id作為offset,該offset的值作為是否活躍的值即可達到我們的目的。這樣只需要一個key就能解決對所有資料的查詢問題。假設我們的id最大值是1億,那麼我們需要一億個bit就行了,相當於只需要1億/(81024

1024)=11.9M記憶體。這裡大家瞭解下二進位制就能理解。

//使用者id123456是活躍使用者
setbit a 123456 1
//使用者id234567不是活躍使用者
setbit a 234567 0

getbit a 123456

具體操作:

迴圈所有id列表,id作為offset,通過setbit寫入該id是否活躍。

查詢時,呼叫getbit a 123456即可

這樣完美解決了儲存和訪問的問題!

  1. 接下來還要解決資料寫入問題,這麼多資料要怎樣快速寫入呢?使用redis官方提供的方式,將資料轉成redis協議格式,使用redis-cli提供的pipe模式寫入。
    一個命令的例子:
*4
$6
setbit
$9
is_active
$3
123
$1
1

上面*4表示這個命令總共有四個引數:
$資料表示下面的引數的位元組數量,一個引數對應一個$
以換行結尾,注意,換行必須是\r\n,linux中需要轉換。
得到redis協議格式的文字後,使用redis-cli執行。

cat data.txt|redis-cli  --pipe