一、時序資料介紹
什麼是時間序列資料(Time Series Data,TSD,以下簡稱時序)?
從定義上來說,就是一串按時間次元索引的資料。簡單的說,就是這類資料描述了某個被測量的主體在一個時間範圍内的每個時間點上的測量值。它普遍存在于IT基礎設施、運維監控系統和物聯網中。
對時序資料進行模組化,包含三個重要部分,分别是:主體,時間點和測量值。時序資料從時間次元上将孤立的觀測值連成一條線,進而揭示軟硬體系統的狀态變化。孤立的觀測值不能叫時序資料,但如果把大量的觀測值用時間線串起來,我們就可以研究和分析觀測值的趨勢及規律。
二、時序資料特征
資料寫入:資料持續高速生成,持續高并發寫入,資料點一旦插入資料庫,就不會發生更改,可設定過期時間。
非結構化标簽:時序資料通常是由許多來源在很長一段時間内連續産生的。例如,在IoT用例中,每個傳感器都是時序資料的來源。在這種情況下,序列中的每個資料點都将源資訊和其他傳感器測量結果存儲為标簽。來自每個來源的資料标簽可能不符合相同的結構或順序。
資料價值遞減:将來隻有适當時間範圍内的彙總資料摘要才有意義,存在明顯的冷熱資料,一般隻會頻繁查詢近期資料。
三、Redis 時序資料方案
Redis是現在最受歡迎的NoSQL資料庫之一,redis 内置了多種常用資料結構,适用于多種應用場景:緩存、隊列、分布式鎖、排行榜等等。除此之外redis 還可以自定義擴充子產品引入更多資料結構,比如引入RediSearch 子產品用于redis 支援全文檢索( 了解更多有用的子產品可通路 https://redis.io/modules)。以下主要講述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 https://github.com/RedisTimeSeries/RedisTimeSeries.gitlinux執行指令編譯:
cd RedisTimeSeriesmake 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-cli127.0.0.1:6379> module list1) 1) "name" 2) "timeseries" 3) "ver" 4) (integer) 10608 |
遇到的問題與解決方案:
(1)解決make的版本低不能使用,更新make
wget http://mirrors.ustc.edu.cn/gnu/make/make-4.3.tar.gztar xf make-4.3.tar.gzcd make-4.3/# 安裝到指定目錄./configure --prefix=/usr/local/makemake && make installmake -v# 此時的 make 還是3.82 與環境變量有關系,可執行下面操作mv /usr/bin/make /usr/lib/make.oldln -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.MADD:給某個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 541) (integer) 15481491800002) (integer) 1548149183000127.0.0.1:6379>TS.MADD temperature:2:32 1548149181000 45 cpu:2:32 1548149180000 301) (integer) 15481491810002) (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.CREATERULE:建立資料壓縮規則
指令格式:
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 50001) 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=321) 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 擴充子產品可以用來存儲最近一段熱點資料,曆史資料可考慮壓縮采樣以更大時間粒度存儲資料,亦可以搭配其他資料庫存儲原始資料。