在Redis中如何保存時間序列數(shù)據(jù)詳解
前言
我們現(xiàn)在做互聯(lián)網(wǎng)產(chǎn)品的時候,都有這么一個需求:記錄用戶在網(wǎng)站或者App上的點(diǎn)擊行為數(shù)據(jù),來分析用戶行為。這里的數(shù)據(jù)一般包括用戶ID、行為類型(例如瀏覽、登錄、下單等)、行為發(fā)生的時間戳:
UserID, Type, TimeStamp
我之前做過的一個物聯(lián)網(wǎng)項(xiàng)目的數(shù)據(jù)存取需求,和這個很相似。我們需要周期性地統(tǒng)計近萬臺設(shè)備的實(shí)時狀態(tài),包括設(shè)備ID、壓力、溫度、濕度,以及對應(yīng)的時間戳:
DeviceID, Pressure, Temperature, Humidity, TimeStamp
這些與發(fā)生時間相關(guān)的一組數(shù)據(jù),就是時間序列數(shù)據(jù)。這些數(shù)據(jù)的特點(diǎn)是沒有嚴(yán)格的關(guān)系模型,記錄的信息可以表示成鍵和值的關(guān)系(例如,一個設(shè)備ID對應(yīng)一條記錄),所以,并不需要專門用關(guān)系型數(shù)據(jù)庫(例如MySQL)來保存。而Redis的鍵值數(shù)據(jù)模型,正好可以滿足這里的數(shù)據(jù)存取需求。Redis基于自身數(shù)據(jù)結(jié)構(gòu)以及擴(kuò)展模塊,提供了兩種解決方案。
這節(jié)課,我就以物聯(lián)網(wǎng)場景中統(tǒng)計設(shè)備狀態(tài)指標(biāo)值為例,和你聊聊不同解決方案的做法和優(yōu)缺點(diǎn)。
俗話說,“知己知彼,百戰(zhàn)百勝”,我們就先從時間序列數(shù)據(jù)的讀寫特點(diǎn)開始,看看到底應(yīng)該采用什么樣的數(shù)據(jù)類型來保存吧。
時間序列數(shù)據(jù)的讀寫特點(diǎn)
在實(shí)際應(yīng)用中,時間序列數(shù)據(jù)通常是持續(xù)高并發(fā)寫入的,例如,需要連續(xù)記錄數(shù)萬個設(shè)備的實(shí)時狀態(tài)值。同時,時間序列數(shù)據(jù)的寫入主要就是插入新數(shù)據(jù),而不是更新一個已存在的數(shù)據(jù),也就是說,一個時間序列數(shù)據(jù)被記錄后通常就不會變了,因?yàn)樗痛砹艘粋€設(shè)備在某個時刻的狀態(tài)值(例如,一個設(shè)備在某個時刻的溫度測量值,一旦記錄下來,這個值本身就不會再變了)。
所以,這種數(shù)據(jù)的寫入特點(diǎn)很簡單,就是插入數(shù)據(jù)快,這就要求我們選擇的數(shù)據(jù)類型,在進(jìn)行數(shù)據(jù)插入時,復(fù)雜度要低,盡量不要阻塞。看到這兒,你可能第一時間會想到用Redis的String、Hash類型來保存,因?yàn)樗鼈兊牟迦霃?fù)雜度都是O(1),是個不錯的選擇。但是,我在第11講中說過,String類型在記錄小數(shù)據(jù)時(例如剛才例子中的設(shè)備溫度值),元數(shù)據(jù)的內(nèi)存開銷比較大,不太適合保存大量數(shù)據(jù)。
那我們再看看,時間序列數(shù)據(jù)的“讀”操作有什么特點(diǎn)。
我們在查詢時間序列數(shù)據(jù)時,既有對單條記錄的查詢(例如查詢某個設(shè)備在某一個時刻的運(yùn)行狀態(tài)信息,對應(yīng)的就是這個設(shè)備的一條記錄),也有對某個時間范圍內(nèi)的數(shù)據(jù)的查詢(例如每天早上8點(diǎn)到10點(diǎn)的所有設(shè)備的狀態(tài)信息)。
除此之外,還有一些更復(fù)雜的查詢,比如對某個時間范圍內(nèi)的數(shù)據(jù)做聚合計算。這里的聚合計算,就是對符合查詢條件的所有數(shù)據(jù)做計算,包括計算均值、最大/最小值、求和等。例如,我們要計算某個時間段內(nèi)的設(shè)備壓力的最大值,來判斷是否有故障發(fā)生。
那用一個詞概括時間序列數(shù)據(jù)的“讀”,就是查詢模式多。
弄清楚了時間序列數(shù)據(jù)的讀寫特點(diǎn),接下來我們就看看如何在Redis中保存這些數(shù)據(jù)。我們來分析下:針對時間序列數(shù)據(jù)的“寫要快”,Redis的高性能寫特性直接就可以滿足了;而針對“查詢模式多”,也就是要支持單點(diǎn)查詢、范圍查詢和聚合計算,Redis提供了保存時間序列數(shù)據(jù)的兩種方案,分別可以基于Hash和Sorted Set實(shí)現(xiàn),以及基于RedisTimeSeries模塊實(shí)現(xiàn)。
接下來,我們先學(xué)習(xí)下第一種方案。
基于Hash和Sorted Set保存時間序列數(shù)據(jù)
Hash和Sorted Set組合的方式有一個明顯的好處:它們是Redis內(nèi)在的數(shù)據(jù)類型,代碼成熟和性能穩(wěn)定。所以,基于這兩個數(shù)據(jù)類型保存時間序列數(shù)據(jù),系統(tǒng)穩(wěn)定性是可以預(yù)期的。
不過,在前面學(xué)習(xí)的場景中,我們都是使用一個數(shù)據(jù)類型來存取數(shù)據(jù),那么,為什么保存時間序列數(shù)據(jù),要同時使用這兩種類型?這是我們要回答的第一個問題。
關(guān)于Hash類型,我們都知道,它有一個特點(diǎn)是,可以實(shí)現(xiàn)對單鍵的快速查詢。這就滿足了時間序列數(shù)據(jù)的單鍵查詢需求。我們可以把時間戳作為Hash集合的key,把記錄的設(shè)備狀態(tài)值作為Hash集合的value。
可以看下用Hash集合記錄設(shè)備的溫度值的示意圖:
當(dāng)我們想要查詢某個時間點(diǎn)或者是多個時間點(diǎn)上的溫度數(shù)據(jù)時,直接使用HGET命令或者HMGET命令,就可以分別獲得Hash集合中的一個key和多個key的value值了。
舉個例子。我們用HGET命令查詢202008030905這個時刻的溫度值,使用HMGET查詢202008030905、202008030907、202008030908這三個時刻的溫度值,如下所示:
HGET device:temperature 202008030905 "25.1" HMGET device:temperature 202008030905 202008030907 202008030908 1) "25.1" 2) "25.9" 3) "24.9"
你看,用Hash類型來實(shí)現(xiàn)單鍵的查詢很簡單。但是,Hash類型有個短板:它并不支持對數(shù)據(jù)進(jìn)行范圍查詢。
雖然時間序列數(shù)據(jù)是按時間遞增順序插入Hash集合中的,但Hash類型的底層結(jié)構(gòu)是哈希表,并沒有對數(shù)據(jù)進(jìn)行有序索引。所以,如果要對Hash類型進(jìn)行范圍查詢的話,就需要掃描Hash集合中的所有數(shù)據(jù),再把這些數(shù)據(jù)取回到客戶端進(jìn)行排序,然后,才能在客戶端得到所查詢范圍內(nèi)的數(shù)據(jù)。顯然,查詢效率很低。
為了能同時支持按時間戳范圍的查詢,可以用Sorted Set來保存時間序列數(shù)據(jù),因?yàn)樗軌蚋鶕?jù)元素的權(quán)重分?jǐn)?shù)來排序。我們可以把時間戳作為Sorted Set集合的元素分?jǐn)?shù),把時間點(diǎn)上記錄的數(shù)據(jù)作為元素本身。
我還是以保存設(shè)備溫度的時間序列數(shù)據(jù)為例,進(jìn)行解釋。下圖顯示了用Sorted Set集合保存的結(jié)果。
使用Sorted Set保存數(shù)據(jù)后,我們就可以使用ZRANGEBYSCORE命令,按照輸入的最大時間戳和最小時間戳來查詢這個時間范圍內(nèi)的溫度值了。如下所示,我們來查詢一下在2020年8月3日9點(diǎn)7分到9點(diǎn)10分間的所有溫度值:
ZRANGEBYSCORE device:temperature 202008030907 202008030910 1) "25.9" 2) "24.9" 3) "25.3" 4) "25.2"
現(xiàn)在我們知道了,同時使用Hash和Sorted Set,可以滿足單個時間點(diǎn)和一個時間范圍內(nèi)的數(shù)據(jù)查詢需求了,但是我們又會面臨一個新的問題,也就是我們要解答的第二個問題:如何保證寫入Hash和Sorted Set是一個原子性的操作呢?
所謂“原子性的操作”,就是指我們執(zhí)行多個寫命令操作時(例如用HSET命令和ZADD命令分別把數(shù)據(jù)寫入Hash和Sorted Set),這些命令操作要么全部完成,要么都不完成。
只有保證了寫操作的原子性,才能保證同一個時間序列數(shù)據(jù),在Hash和Sorted Set中,要么都保存了,要么都沒保存。否則,就可能出現(xiàn)Hash集合中有時間序列數(shù)據(jù),而Sorted Set中沒有,那么,在進(jìn)行范圍查詢時,就沒有辦法滿足查詢需求了。
那Redis是怎么保證原子性操作的呢?這里就涉及到了Redis用來實(shí)現(xiàn)簡單的事務(wù)的MULTI和EXEC命令。當(dāng)多個命令及其參數(shù)本身無誤時,MULTI和EXEC命令可以保證執(zhí)行這些命令時的原子性。關(guān)于Redis的事務(wù)支持和原子性保證的異常情況,我會在第30講中向你介紹,這節(jié)課,我們只要了解一下MULTI和EXEC這兩個命令的使用方法就行了。
- MULTI命令:表示一系列原子性操作的開始。收到這個命令后,Redis就知道,接下來再收到的命令需要放到一個內(nèi)部隊列中,后續(xù)一起執(zhí)行,保證原子性。
- EXEC命令:表示一系列原子性操作的結(jié)束。一旦Redis收到了這個命令,就表示所有要保證原子性的命令操作都已經(jīng)發(fā)送完成了。此時,Redis開始執(zhí)行剛才放到內(nèi)部隊列中的所有命令操作。
你可以看下下面這張示意圖,命令1到命令N是在MULTI命令后、EXEC命令前發(fā)送的,它們會被一起執(zhí)行,保證原子性。
以保存設(shè)備狀態(tài)信息的需求為例,我們執(zhí)行下面的代碼,把設(shè)備在2020年8月3日9時5分的溫度,分別用HSET命令和ZADD命令寫入Hash集合和Sorted Set集合。
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> HSET device:temperature 202008030911 26.8 QUEUED 127.0.0.1:6379> ZADD device:temperature 202008030911 26.8 QUEUED 127.0.0.1:6379> EXEC 1) (integer) 1 2) (integer) 1
可以看到,首先,Redis收到了客戶端執(zhí)行的MULTI命令。然后,客戶端再執(zhí)行HSET和ZADD命令后,Redis返回的結(jié)果為“QUEUED”,表示這兩個命令暫時入隊,先不執(zhí)行;執(zhí)行了EXEC命令后,HSET命令和ZADD命令才真正執(zhí)行,并返回成功結(jié)果(結(jié)果值為1)。
到這里,我們就解決了時間序列數(shù)據(jù)的單點(diǎn)查詢、范圍查詢問題,并使用MUTLI和EXEC命令保證了Redis能原子性地把數(shù)據(jù)保存到Hash和Sorted Set中。接下來,我們需要繼續(xù)解決第三個問題:如何對時間序列數(shù)據(jù)進(jìn)行聚合計算?
聚合計算一般被用來周期性地統(tǒng)計時間窗口內(nèi)的數(shù)據(jù)匯總狀態(tài),在實(shí)時監(jiān)控與預(yù)警等場景下會頻繁執(zhí)行。
因?yàn)镾orted Set只支持范圍查詢,無法直接進(jìn)行聚合計算,所以,我們只能先把時間范圍內(nèi)的數(shù)據(jù)取回到客戶端,然后在客戶端自行完成聚合計算。這個方法雖然能完成聚合計算,但是會帶來一定的潛在風(fēng)險,也就是大量數(shù)據(jù)在Redis實(shí)例和客戶端間頻繁傳輸,這會和其他操作命令競爭網(wǎng)絡(luò)資源,導(dǎo)致其他操作變慢。
在我們這個物聯(lián)網(wǎng)項(xiàng)目中,就需要每3分鐘統(tǒng)計一下各個設(shè)備的溫度狀態(tài),一旦設(shè)備溫度超出了設(shè)定的閾值,就要進(jìn)行報警。這是一個典型的聚合計算場景,我們可以來看看這個過程中的數(shù)據(jù)體量。
假設(shè)我們需要每3分鐘計算一次的所有設(shè)備各指標(biāo)的最大值,每個設(shè)備每15秒記錄一個指標(biāo)值,1分鐘就會記錄4個值,3分鐘就會有12個值。我們要統(tǒng)計的設(shè)備指標(biāo)數(shù)量有33個,所以,單個設(shè)備每3分鐘記錄的指標(biāo)數(shù)據(jù)有將近400個(33 * 12 = 396),而設(shè)備總數(shù)量有1萬臺,這樣一來,每3分鐘就有將近400萬條(396 * 1萬 = 396萬)數(shù)據(jù)需要在客戶端和Redis實(shí)例間進(jìn)行傳輸。
為了避免客戶端和Redis實(shí)例間頻繁的大量數(shù)據(jù)傳輸,我們可以使用RedisTimeSeries來保存時間序列數(shù)據(jù)。
RedisTimeSeries支持直接在Redis實(shí)例上進(jìn)行聚合計算。還是以剛才每3分鐘算一次最大值為例。在Redis實(shí)例上直接聚合計算,那么,對于單個設(shè)備的一個指標(biāo)值來說,每3分鐘記錄的12條數(shù)據(jù)可以聚合計算成一個值,單個設(shè)備每3分鐘也就只有33個聚合值需要傳輸,1萬臺設(shè)備也只有33萬條數(shù)據(jù)。數(shù)據(jù)量大約是在客戶端做聚合計算的十分之一,很顯然,可以減少大量數(shù)據(jù)傳輸對Redis實(shí)例網(wǎng)絡(luò)的性能影響。
所以,如果我們只需要進(jìn)行單個時間點(diǎn)查詢或是對某個時間范圍查詢的話,適合使用Hash和Sorted Set的組合,它們都是Redis的內(nèi)在數(shù)據(jù)結(jié)構(gòu),性能好,穩(wěn)定性高。但是,如果我們需要進(jìn)行大量的聚合計算,同時網(wǎng)絡(luò)帶寬條件不是太好時,Hash和Sorted Set的組合就不太適合了。此時,使用RedisTimeSeries就更加合適一些。
好了,接下來,我們就來具體學(xué)習(xí)下RedisTimeSeries。
基于RedisTimeSeries模塊保存時間序列數(shù)據(jù)
RedisTimeSeries是Redis的一個擴(kuò)展模塊。它專門面向時間序列數(shù)據(jù)提供了數(shù)據(jù)類型和訪問接口,并且支持在Redis實(shí)例上直接對數(shù)據(jù)進(jìn)行按時間范圍的聚合計算。
因?yàn)镽edisTimeSeries不屬于Redis的內(nèi)建功能模塊,在使用時,我們需要先把它的源碼單獨(dú)編譯成動態(tài)鏈接庫redistimeseries.so,再使用loadmodule命令進(jìn)行加載,如下所示:
loadmodule redistimeseries.so
當(dāng)用于時間序列數(shù)據(jù)存取時,RedisTimeSeries的操作主要有5個:
- 用TS.CREATE命令創(chuàng)建時間序列數(shù)據(jù)集合;
- 用TS.ADD命令插入數(shù)據(jù);
- 用TS.GET命令讀取最新數(shù)據(jù);
- 用TS.MGET命令按標(biāo)簽過濾查詢數(shù)據(jù)集合;
- 用TS.RANGE支持聚合計算的范圍查詢。
下面,我來介紹一下如何使用這5個操作。
1.用TS.CREATE命令創(chuàng)建一個時間序列數(shù)據(jù)集合
在TS.CREATE命令中,我們需要設(shè)置時間序列數(shù)據(jù)集合的key和數(shù)據(jù)的過期時間(以毫秒為單位)。此外,我們還可以為數(shù)據(jù)集合設(shè)置標(biāo)簽,來表示數(shù)據(jù)集合的屬性。
例如,我們執(zhí)行下面的命令,創(chuàng)建一個key為device:temperature、數(shù)據(jù)有效期為600s的時間序列數(shù)據(jù)集合。也就是說,這個集合中的數(shù)據(jù)創(chuàng)建了600s后,就會被自動刪除。最后,我們給這個集合設(shè)置了一個標(biāo)簽屬性{device_id:1},表明這個數(shù)據(jù)集合中記錄的是屬于設(shè)備ID號為1的數(shù)據(jù)。
TS.CREATE device:temperature RETENTION 600000 LABELS device_id 1 OK
2.用TS.ADD命令插入數(shù)據(jù),用TS.GET命令讀取最新數(shù)據(jù)
我們可以用TS.ADD命令往時間序列集合中插入數(shù)據(jù),包括時間戳和具體的數(shù)值,并使用TS.GET命令讀取數(shù)據(jù)集合中的最新一條數(shù)據(jù)。
例如,我們執(zhí)行下列TS.ADD命令時,就往device:temperature集合中插入了一條數(shù)據(jù),記錄的是設(shè)備在2020年8月3日9時5分的設(shè)備溫度;再執(zhí)行TS.GET命令時,就會把剛剛插入的最新數(shù)據(jù)讀取出來。
TS.ADD device:temperature 1596416700 25.1 1596416700 TS.GET device:temperature 25.1
3.用TS.MGET命令按標(biāo)簽過濾查詢數(shù)據(jù)集合
在保存多個設(shè)備的時間序列數(shù)據(jù)時,我們通常會把不同設(shè)備的數(shù)據(jù)保存到不同集合中。此時,我們就可以使用TS.MGET命令,按照標(biāo)簽查詢部分集合中的最新數(shù)據(jù)。在使用TS.CREATE創(chuàng)建數(shù)據(jù)集合時,我們可以給集合設(shè)置標(biāo)簽屬性。當(dāng)我們進(jìn)行查詢時,就可以在查詢條件中對集合標(biāo)簽屬性進(jìn)行匹配,最后的查詢結(jié)果里只返回匹配上的集合中的最新數(shù)據(jù)。
舉個例子。假設(shè)我們一共用4個集合為4個設(shè)備保存時間序列數(shù)據(jù),設(shè)備的ID號是1、2、3、4,我們在創(chuàng)建數(shù)據(jù)集合時,把device_id設(shè)置為每個集合的標(biāo)簽。此時,我們就可以使用下列TS.MGET命令,以及FILTER設(shè)置(這個配置項(xiàng)用來設(shè)置集合標(biāo)簽的過濾條件),查詢device_id不等于2的所有其他設(shè)備的數(shù)據(jù)集合,并返回各自集合中的最新的一條數(shù)據(jù)。
TS.MGET FILTER device_id!=2 1) 1) "device:temperature:1" 2) (empty list or set) 3) 1) (integer) 1596417000 2) "25.3" 2) 1) "device:temperature:3" 2) (empty list or set) 3) 1) (integer) 1596417000 2) "29.5" 3) 1) "device:temperature:4" 2) (empty list or set) 3) 1) (integer) 1596417000 2) "30.1"
4.用TS.RANGE支持需要聚合計算的范圍查詢
最后,在對時間序列數(shù)據(jù)進(jìn)行聚合計算時,我們可以使用TS.RANGE命令指定要查詢的數(shù)據(jù)的時間范圍,同時用AGGREGATION參數(shù)指定要執(zhí)行的聚合計算類型。RedisTimeSeries支持的聚合計算類型很豐富,包括求均值(avg)、求最大/最小值(max/min),求和(sum)等。
例如,在執(zhí)行下列命令時,我們就可以按照每180s的時間窗口,對2020年8月3日9時5分和2020年8月3日9時12分這段時間內(nèi)的數(shù)據(jù)進(jìn)行均值計算了。
TS.RANGE device:temperature 1596416700 1596417120 AGGREGATION avg 180000 1) 1) (integer) 1596416700 2) "25.6" 2) 1) (integer) 1596416880 2) "25.8" 3) 1) (integer) 1596417060 2) "26.1"
與使用Hash和Sorted Set來保存時間序列數(shù)據(jù)相比,RedisTimeSeries是專門為時間序列數(shù)據(jù)訪問設(shè)計的擴(kuò)展模塊,能支持在Redis實(shí)例上直接進(jìn)行聚合計算,以及按標(biāo)簽屬性過濾查詢數(shù)據(jù)集合,當(dāng)我們需要頻繁進(jìn)行聚合計算,以及從大量集合中篩選出特定設(shè)備或用戶的數(shù)據(jù)集合時,RedisTimeSeries就可以發(fā)揮優(yōu)勢了。
小結(jié)
在這節(jié)課,我們一起學(xué)習(xí)了如何用Redis保存時間序列數(shù)據(jù)。時間序列數(shù)據(jù)的寫入特點(diǎn)是要能快速寫入,而查詢的特點(diǎn)有三個:
- 點(diǎn)查詢,根據(jù)一個時間戳,查詢相應(yīng)時間的數(shù)據(jù);
- 范圍查詢,查詢起始和截止時間戳范圍內(nèi)的數(shù)據(jù);
- 聚合計算,針對起始和截止時間戳范圍內(nèi)的所有數(shù)據(jù)進(jìn)行計算,例如求最大/最小值,求均值等。
關(guān)于快速寫入的要求,Redis的高性能寫特性足以應(yīng)對了;而針對多樣化的查詢需求,Redis提供了兩種方案。
第一種方案是,組合使用Redis內(nèi)置的Hash和Sorted Set類型,把數(shù)據(jù)同時保存在Hash集合和Sorted Set集合中。這種方案既可以利用Hash類型實(shí)現(xiàn)對單鍵的快速查詢,還能利用Sorted Set實(shí)現(xiàn)對范圍查詢的高效支持,一下子滿足了時間序列數(shù)據(jù)的兩大查詢需求。
不過,第一種方案也有兩個不足:一個是,在執(zhí)行聚合計算時,我們需要把數(shù)據(jù)讀取到客戶端再進(jìn)行聚合,當(dāng)有大量數(shù)據(jù)要聚合時,數(shù)據(jù)傳輸開銷大;另一個是,所有的數(shù)據(jù)會在兩個數(shù)據(jù)類型中各保存一份,內(nèi)存開銷不小。不過,我們可以通過設(shè)置適當(dāng)?shù)臄?shù)據(jù)過期時間,釋放內(nèi)存,減小內(nèi)存壓力。
我們學(xué)習(xí)的第二種實(shí)現(xiàn)方案是使用RedisTimeSeries模塊。這是專門為存取時間序列數(shù)據(jù)而設(shè)計的擴(kuò)展模塊。和第一種方案相比,RedisTimeSeries能支持直接在Redis實(shí)例上進(jìn)行多種數(shù)據(jù)聚合計算,避免了大量數(shù)據(jù)在實(shí)例和客戶端間傳輸。不過,RedisTimeSeries的底層數(shù)據(jù)結(jié)構(gòu)使用了鏈表,它的范圍查詢的復(fù)雜度是O(N)級別的,同時,它的TS.GET查詢只能返回最新的數(shù)據(jù),沒有辦法像第一種方案的Hash類型一樣,可以返回任一時間點(diǎn)的數(shù)據(jù)。
所以,組合使用Hash和Sorted Set,或者使用RedisTimeSeries,在支持時間序列數(shù)據(jù)存取上各有優(yōu)劣勢。我給你的建議是:
- 如果你的部署環(huán)境中網(wǎng)絡(luò)帶寬高、Redis實(shí)例內(nèi)存大,可以優(yōu)先考慮第一種方案;
- 如果你的部署環(huán)境中網(wǎng)絡(luò)、內(nèi)存資源有限,而且數(shù)據(jù)量大,聚合計算頻繁,需要按數(shù)據(jù)集合屬性查詢,可以優(yōu)先考慮第二種方案。
每課一問
按照慣例,我給你提個小問題。
在這節(jié)課上,我提到,我們可以使用Sorted Set保存時間序列數(shù)據(jù),把時間戳作為score,把實(shí)際的數(shù)據(jù)作為member,你覺得這樣保存數(shù)據(jù)有沒有潛在的風(fēng)險?另外,如果你是Redis的開發(fā)維護(hù)者,你會把聚合計算也設(shè)計為Sorted Set的一個內(nèi)在功能嗎?
總結(jié)
到此這篇關(guān)于在Redis中如何保存時間序列數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Redis保存時間序列數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于?Spring?Aop?環(huán)繞通知實(shí)現(xiàn)?Redis?緩存雙刪功能(示例代碼)
基于 spring aop 常規(guī)應(yīng)用場景多是用于日志記錄以及實(shí)現(xiàn) redis 分布式鎖,在 github 中也有項(xiàng)目是把它拿來當(dāng)作緩存的異常捕捉,這篇文章主要介紹了基于?Spring?Aop?環(huán)繞通知實(shí)現(xiàn)?Redis?緩存雙刪,需要的朋友可以參考下2022-08-08Redis實(shí)戰(zhàn)之商城購物車功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了Redis實(shí)戰(zhàn)之商城購物車功能的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02Redis+threading實(shí)現(xiàn)多線程消息隊列的使用示例
Redis多線程消息隊列是一種使用Redis作為存儲后端的消息隊列實(shí)現(xiàn),它利用Redis的線程并發(fā)處理能力來提高消息隊列的處理效率,本文主要介紹了Redis+threading實(shí)現(xiàn)多線程消息隊列的使用示例,感興趣的可以了解一下2023-12-12