技術乾貨 | 解鎖Redis 時間序列資料的應用

Linksla發表於2022-04-14
一、時序資料介紹

什麼是時間序列資料(Time Series Data,TSD,以下簡稱時序)?

從定義上來說,就是一串按時間維度索引的資料。簡單的說,就是這類資料描述了某個被測量的主體在一個時間範圍內的每個時間點上的測量值。它普遍存在於IT基礎設施、運維監控系統和物聯網中。

對時序資料進行建模,包含三個重要部分,分別是:主體,時間點和測量值。時序資料從時間維度上將孤立的觀測值連成一條線,從而揭示軟硬體系統的狀態變化。孤立的觀測值不能叫時序資料,但如果把大量的觀測值用時間線串起來,我們就可以研究和分析觀測值的趨勢及規律。


二、時序資料特徵

資料寫入:資料持續高速生成,持續高併發寫入,資料點一旦插入資料庫,就不會發生更改,可設定過期時間。

非結構化標籤:時序資料通常是由許多來源在很長一段時間內連續產生的。例如,在IoT用例中,每個感測器都是時序資料的來源。在這種情況下,序列中的每個資料點都將源資訊和其他感測器測量結果儲存為標籤。來自每個來源的資料標籤可能不符合相同的結構或順序。

資料價值遞減:將來只有適當時間範圍內的彙總資料摘要才有意義,存在明顯的冷熱資料,一般只會頻繁查詢近期資料。

 

三、Redis 時序資料方案

Redis是現在最受歡迎的NoSQL資料庫之一,redis 內建了多種常用資料結構,適用於多種應用場景:快取、佇列、分散式鎖、排行榜等等。除此之外redis 還可以自定義擴充套件模組引入更多資料結構,比如引入RediSearch 模組用於redis 支援全文檢索( 瞭解更多有用的模組可訪問  )。以下主要講述redis在時序資料儲存的應用方案。


3.1 使用 Sorted Set 儲存

SortedSets 是redis 內建的資料結構,跟set相比支援按權重值儲存資料,支援權重的範圍查詢。時序資料的場景下,可將資料時間戳作為權重值儲存,key儲存具體的度量維度。

缺點:
1、SortedSets 不是一種節約記憶體的資料結構;
2、寫入效能不高;
3、內建缺少聚合工具,只支援客戶端程式聚合,造成程式碼繁瑣且網路IO佔用高。
 

3.2 使用 Stream  儲存

Redis Stream 是 Redis 5.0 版本新增加的資料結構,使用 Rax(Radix樹的單獨實現)實現,與 Sorted Sets 相比,Redis Streams 增強了插入和讀取的效能。但 Stream 主要用於訊息佇列,仍然缺少了特定於時間序列的聚合工具。

缺點:
內建缺少聚合工具。

3.3 使用 RedisTimeSeries 儲存

RedisTimeSeries 是專門為Redis 存取時序資料而設計的擴充套件模組。由於 RedisTimeSeries 不屬於 Redis 的內建資料結構,在使用時,需要先把它的原始碼單獨編譯成動態連結庫 redistimeseries.so。

3.3.1 模組安裝

步驟1:生成動態庫
下載原始碼:  git clone --recursive 
linux執行命令編譯:

cd RedisTimeSeries
make setup

如果編譯不成功,有個捷徑獲取動態庫:
拉取docker 映象redislabs/redistimeseries,啟動容器可在容器中找到 redistimeseries.so檔案。
步驟2:載入動態檔案到redis
在 redis.conf 檔案中加入 
loadmodule /path/to/redistimeseries.so
在啟動的 client 中輸入  
module load /path/to/redistimeseries.so
在伺服器啟動是載入 
redis-server --loadmodule /path/to/redistimeseries.so

步驟3:檢視timeseries模組是否安裝成功

root@1738e25ad4eb:/data# redis-cli
127.0.0.1:6379> module list
1) 1) "name"
   2) "timeseries"
   3) "ver"
   4) (integer) 10608


遇到的問題與解決方案:

(1)解決make的版本低不能使用,升級make

wget
tar xf make-4.3.tar.gz
cd make-4.3/
# 安裝到指定目錄
./configure  --prefix=/usr/local/make
make && make install
make -v
# 此時的 make 還是3.82 與環境變數有關係,可執行下面操作
mv /usr/bin/make /usr/lib/make.old
ln -s /usr/local/make/bin/make /usr/bin/make

 
(2)解決報錯 libssl.so.1.1: cannot open shared object file: No such file or directory
參考: https://blog.csdn.net/estelle_belle/article/details/111181037
(3)解決libc.so.6版本問題 /lib64/libc.so.6:version 'GLIBC_XXX' not found
參考: https://blog.csdn.net/qq_35869630/article/details/105746221


3.3.2 主要命令

以下命令基本可以實現時序資料儲存與查詢:

1、 TS.CREATE 建立一個時序資料集合


命令格式:

TS.CREATE key [RETENTION retentionTime] [ENCODING [UNCOMPRESSED|COMPRESSED]] [CHUNK_SIZE size] [DUPLICATE_POLICY policy] [LABELS label value..]


引數說明:

- RETENTION: 與最後的事件時間相比樣本的最大年齡(以毫秒為單位),預設值為0,代表資料不會過期
- ENCODING: 編碼模式COMPRESSED使用壓縮演算法儲存 ,UNCOMPRESSED將原始樣本儲存在記憶體中
- CHUNK_SIZE: 資料分配的記憶體大小,單位位元組,必須是 8 的倍數,預設值:4096。
- DUPLICATE_POLICY: 重複樣本策略配置。
- LABELS: 標籤是key的後設資料,以鍵值對方式儲存


示例命令:

 TS.CREATE temperature:2:32 RETENTION 60000 DUPLICATE_POLICY MAX LABELS sensor_id 2 area_id 32

 

2、 TS.ADD :給某個key 新增時序資料,如果不存在則會建立集合


命令格式:

TS.CREATE key [RETENTION retentionTime] [ENCODING [UNCOMPRESSED|COMPRESSED]] [CHUNK_SIZE size] [DUPLICATE_POLICY policy] [LABELS label value..]

 
複雜度:
如果在時間序列上存在壓縮規則,則  TS.ADD 效能可能會降低。 TS.ADD  M 是壓縮規則的數量或沒有壓縮的 O(1) 時 ,複雜度 總是 O(M)。
引數說明:
- timestamps: 時間戳,單位毫秒
- value:  double 型別的數值
其他引數是可選的,與TS.CREATE 一致

示例命令:

 TS.CREATE temperature:2:32 RETENTION 60000 DUPLICATE_POLICY MAX LABELS sensor_id 2 area_id 32

 

3、 TS. M ADD :給某個key  批次新增 資料


命令格式:

TS.MADD key timestamp value [key timestamp value ...]

 
示例命令:

127.0.0.1:6379>TS.MADD temperature:2:32 1548149180000 26 cpu:2:32 1548149183000 54
1) (integer) 1548149180000
2) (integer) 1548149183000
127.0.0.1:6379>TS.MADD temperature:2:32 1548149181000 45 cpu:2:32 1548149180000 30
1) (integer) 1548149181000
2) (integer) 1548149180000

 

4、 TS.DEL 刪除某個key 某個時間範圍的樣本資料


命令格式:

TS.DEL key fromTimestamp toTimestamp

返回值: 被移除的樣本數


示例命令:

127.0.0.1:6379>TS.DEL temperature:2:32 1548149180000 1548149183000
(integer) 150

 

5、 TS.CREA T ERULE : 建立 資料 壓縮規則


命令格式:

TS.CREATERULE sourceKey destKey AGGREGATION aggregationType timeBucket


引數說明:
- sourceKey : 源時間序列的鍵名
- destKey : 目標時間序列的鍵名
- aggregationType : 聚合型別avg、sum、min、max、range、count、first、last、std.p、std.s、var.p、var.s
- timeBucket : 以毫秒為單位的聚合時間桶
   

6、 TS.DELETERULE:  刪除壓縮規則


命令格式:

TS.DELETERULE sourceKey destKey

 
引數說明:
- sourceKey : 源時間序列的鍵名
- destKey : 目標時間序列的鍵名
 

7、 TS.RANGE 範圍查詢,可配合聚合函式使用, 需要指定key


命令格式:

TS.RANGE key fromTimestamp toTimestamp
         [FILTER_BY_TS TS1 TS2 ..]
         [FILTER_BY_VALUE min max]
         [COUNT count] [ALIGN value]
         [AGGREGATION aggregationType timeBucket]

 

引數說明:

- FILTER_BY_TS: 返回特定時間戳的資料
- FILTER_BY_VALUE: 過濾結果中最大值或最小值
- COUNT:返回的結果的最大數量
- AGGREGATION:搭配聚合函式生成聚合桶bucket
- timeBucket: 聚合桶的時間範圍(單位毫秒)
 

示例命令:

127.0.0.1:6379> TS.RANGE temperature:3:32 1548149180000 1548149210000 AGGREGATION avg 5000
1) 1) (integer) 1548149180000
   2) "26.199999999999999"
2) 1) (integer) 1548149185000
   2) "27.399999999999999"
3) 1) (integer) 1548149190000
   2) "24.800000000000001"

 

8、 TS.GET 獲取 指定key的 新一條資料


命令格式:

TS.GET key

複雜度:

TS.GET 複雜度為 O(1)


示例命令:

127.0.0.1:6379> TS.GET temperature:2:32

1) (integer) 1548149279

2) "23"


9、TS.MGET:獲取與特定過濾器匹配的所有key的最新一條資料。


命令格式:

TS.MGET [WITHLABELS | SELECTED_LABELS label1 ..] FILTER filter...


引數說明:
- FILTER: 過濾器
- WITHLABELS:   包含表示時間序列後設資料標籤的標籤-值對
複雜度:
TS.MGET 複雜度為 O(n)。


示例命令:

#過濾area_id=32的所有key 的最新資料
127.0.0.1:6379> TS.MGET FILTER area_id=32
1) 1) "temperature:2:32"
    2) (empty list or set)
    3) 1) (integer) 1548149181000
       2) "30"
2) 1) "temperature:3:32"
    2) (empty list or set)
    3) 1) (integer) 1548149181000
        2) "29"

 

3.3.3客戶端庫 

Project
Language
License
Author
JRedisTimeSeries
Java
BSD-3
Redis
redis-modules-java
Java
Apache-2
dengliming
redistimeseries-go
Go
Apache-2
Redis
redis-py
Python
MIT
Redis
NRedisTimeSeries
.NET
BSD-3
Redis
phpRedisTimeSeries
PHP
MIT
Alessandro Balasco
redis-time-series
JavaScript
MIT
Rafa Campoy
redistimeseries-js
JavaScript
MIT
Milos Nikolovski
redis-modules-sdk
Typescript
BSD-3-Clause
Dani Tseitlin
redis_ts
Rust
BSD-3
Thomas Profelt
redistimeseries
Ruby
MIT
Eaden McKee
redis-time-series
Ruby
MIT
Matt Duszynski

 

優點:

1、 快速提取資料: 作為一個記憶體資料庫,RedisTimeSeries每秒可以在標準節點上提取超過500,000條記錄。測試表明,使用16個Redis分片叢集,每秒可以攝取超過1150萬條記錄。

2、工具豐富: 具有基本的時間序列功能,支援多種聚合。

3、資源效率: 支援定期取樣資料,寫入另外的集合,方便分粒度儲存資料。例如,如果一天收集了超過十億個資料點,則可以每分鐘彙總一次資料以便對資料進行下采樣,從而將資料集的大小減小為24 * 60 = 1,440個資料點。


缺點:

1、時序值只能存double型別,不能存字元
2、點查詢只能獲取最新資料,不支援直接取某一輪的資料
3、redis 是基於記憶體的,不適合儲存太長時間的歷史資料,當然除非有足夠多的記憶體。
 

3.3.4選型建議

目前市面上也有一些專門的時序資料庫,如influxDB,不過influxDB 叢集版是收費的,單機版計算能力受限。如不想引入額外的架構,透過Redis RedisTimeSeries  擴充套件模組可以用來儲存最近一段熱點資料,歷史資料可考慮壓縮取樣以更大時間粒度儲存資料,亦可以搭配其他資料庫儲存原始資料。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70013542/viewspace-2887132/,如需轉載,請註明出處,否則將追究法律責任。

相關文章