如何週期性地統計近萬臺裝置的實時狀態?Redis時間序列儲存方案

凱凱王的技術生涯發表於2020-12-18

場景:如何週期性地統計近萬臺裝置的實時狀態,包含裝置ID、壓力、溫度、溼度、時間戳

時間序列:與發生時間相關的一組資料,沒有嚴格的關係模型,記錄的資訊可以表示成鍵和值的關係。

讀寫特點

  • 要求插入速度快,所以選擇的資料結構插入的時候,複雜度要低,可以選String和hash
  • String記錄小資料時,後設資料的記憶體開銷比較大

多場景的讀

  • 有對單調記錄的讀
  • 對時間範圍內的資料的查詢
  • 對時間範圍內的資料做聚合計算(均值、最大值、最小值、求和等)

Redis提供了儲存時間序列的以下兩種方案

基於Hash和Sorted Set實現(單鍵和範圍查詢)

Hash和Sort Set都是Redis內部成熟和效能穩定的資料型別,使用原因如下:

單鍵查詢

Hash滿足對單鍵的快速查詢,時間戳作為hash集合的key,裝置狀態值作為hash的value,不支援對資料的範圍查詢
在這裡插入圖片描述

範圍查詢

Sorted Sort滿足按時間戳範圍進行查詢,時間戳作為元素分數score,時間點上記錄的資料作為元素本身member,可以通過ZRANGEBYSCORE獲取某個範圍的資料
在這裡插入圖片描述
採用Sorted做聚合計算,需要把資料取回客戶端做,資料量大的時候,會導致大量資料在Redis例項和客戶端之間頻繁傳輸,阻塞網路。

原子性保障

同時使用兩種結構的時候,存資料的時候,就需要保證操作兩種結構的命令的原子性

Redis使用MULTI和EXEC命令保證執行這些命令時的原子性。

  • MULTI 命令:表示一系列原子性操作的開始。收到這個命令後,Redis 就知道,接下來 再收到的命令需要放到一個內部佇列中,後續一起執行,保證原子性。
  • EXEC 命令:表示一系列原子性操作的結束。一旦 Redis 收到了這個命令,就表示所有 要保證原子性的命令操作都已經傳送完成了。此時,Redis 開始執行剛才放到內部佇列 中的所有命令操作。
    在這裡插入圖片描述

基於RedisTimeSeries實現(聚合計算)

通過RedisTimeSeries可以對時間序列的資料做聚合計算

場景模擬

場景:每3分鐘計算一次所有裝置各個指標的最大值

不使用方案

  • 每個裝置每15s記錄一個指標值,1分鐘4個,3分鐘12個
  • 假設要統計的指標值有33個,那麼單個裝置每3分鐘有33*12=396個資料
  • 假設裝置總數1萬臺,每3分鐘有396*10000=396萬資料需要在客戶端和Redis例項之間傳輸

使用方案

  • 在Redis上直接做聚合計算,單個裝置每3分鐘的12條記錄做一次聚合計算,也就是1個值
  • 假設要統計的指標值有33個,那麼單個裝置每3分鐘有33個資料
  • 假設裝置總數1萬臺,每3分鐘有33*10000=33萬資料需要在客戶端和Redis例項之間傳輸

使用方案RedisTimeSeries比不使用方案只是其十分之一的網路傳輸。

RedisTimeSeries 使用

RedisTimeSeries 是 Redis 的一個擴充套件模組,需要額外新增。專門面向時間序列資料提供了資料型別和訪問介面,並且支援在 Redis 例項上直接對資料進行按時間範圍的聚合計算。

TS.CREATE 建立一個時間序列資料集合

  • 設定集合的key和過期時間
  • 為資料集合設定標籤
// 建立key為device:temperature、資料有效期為 600s 的時間序列資料集合。
// 集合資料建立了 600s後,就會被自動刪除。
// 給集合設定了一個標籤屬性{device_id:1},表明資料集合中記錄的是屬於裝置ID號為1的資料。
TS.CREATE device:temperature RETENTION 600000 LABELS device_id 1 

TS.ADD 插入資料

往時間序列集合中插入資料,包括時間戳和具體的數值

//往device:temperature 集合中插入了一條資料,記錄的是裝置在 2020 年 8 月 3 日 9 時 5 分的裝置溫度;
TS.ADD device:temperature 1596416700 25.1

TS.GET 讀取最新資料

使用 TS.GET 命令讀取資料集合中的最新一條資料。

TS.GET device:temperature

TS.MGET 按標籤過濾查詢資料集合

儲存多個裝置的時間序列資料時,我們通常會把不同裝置的資料儲存到不同集合中

使用 TS.MGET 命令,按照標籤查詢部分集合中的最新資料

假設用 4 個集合為 4 個裝置儲存時間序列資料,裝置的 ID 號是 1、 2、3、4建立資料集合時,把 device_id 設定為每個集合的標籤。

可以使用TS.MGET 命令,以及 FILTER (設定集合標籤的過濾條件),查詢 device_id 不等於 2 的所有其他裝置的資料集合,並返回各自集合中的最新的一條資料。

TS.MGET FILTER device_id!=2

TS.RANGE:支援需要聚合計算的範圍查詢

對時間序列資料進行聚合計算時,我們可以使用 TS.RANGE 命令指定要查詢的資料的時間範圍,同時用 AGGREGATION 引數指定要執行的聚合計算型別。

TS.RANGE device:temperature 1596416700 1596417120 AGGREGATION avg 180000
1) (integer) 1596416700
2) "25.6"
1) (integer) 1596416880
2) "25.8"
1) (integer) 1596417060
2) "26.1"

相關文章