如何給redis集合中的元素設置過期時間


我們知道redis中的過期時間只能作用於key上。對於string數據結構來說,因為它是key/value的形式,只有一個value與key對應,所以當過期時間到了,整個key/value被移除,符合心理預期,皆大歡喜。但好多時候我們用到的是其他數據結構,比如:一個擁有多個元素的集合。由於過期時間只能作用於key(集合數據結構可以理解為集合ID)上,當過期時間到了,整個集合被移除。一般使用集合的場景都不希望各個元素在同一時間過期,有時也希望進行與時間相關的查詢,這該怎么辦呢?

 

redis有一種數據結構是Sorted Set,有序集合,它的實現是hash table(element->score, 用於實現zscore及判斷element是否在集合內)和skiplist(score->element,按score排序)的混合體。 skiplist有點像平衡二叉樹那樣,不同范圍的score被分成一層一層,每層是一個按score排序的鏈表。其中zadd/zrem是O(log(N)),zrangebyscore/zremrangebyscore是O(log(N)+M),N是Set大小,M是結果/操作元素的個數。可見,原本可能很大的N被很關鍵的Log了一下,1000萬大小的Set,復雜度也只是幾十不到。當然,如果一次命中很多元素M很大那誰也沒辦法了。

 

這里我們用到了它如下特性:

1. 元素唯一

2. 每個元素擁有一個score

3. 所有元素依據score進行有序排列

4. 可通過score來進行查詢

我們可以借助這些特性來讓集合中的元素擁有時間維度。每當add一個元素時,把當前時間的unix timestamp作為score設置到這個元素上,這樣sorted set會根據這個timestamp將元素排序存儲。

 

場景一:當我們查詢最近1分鍾內有更新的元素時,可以使用命令 zrangebyscore key min max來獲取。例如:

zadd set1 1522598879 "one"

zadd set1 1522598969 "two"

zadd set1 1522598979 "three"

執行查詢:zrangebyscore set1 1522598920 1522598980

返回值:"two"和"three"

 

場景二:當我們查詢最新更新的2個元素,可以使用 zrevrange key start stop來獲取。例如:

zadd set1 1522598879 "one"

zadd set1 1522598969 "two"

zadd set1 1522598979 "three"

執行查詢:zrevrange set1 0 1

返回值:"three"和"two"

 

場景三:當我們需要刪除最近1分鍾沒有過更新的元素,可以使用 zremrangebyscore key min max 來刪除過期元素。例如:

zadd set1 1522598879 "one"

zadd set1 1522598969 "two"

zadd set1 1522598979 "three"

執行命令: zremrangebyscore set1 0 1522598920

執行結果:刪除了元素"one"

一般來講,我們會啟動一個后台任務來不斷進行過期元素的刪除操作,任務的重復執行間隔可以視業務對過期數據的容忍度。如果容忍度較高,可以設置時間久一點,相反可以設置時間短一些。

 

當我們應用到生產環境時,還應該考慮內存占用和訪問效率。有序集合的長度較短或者體積較小的時候,Redis可以選擇使用ziplist的緊湊存儲方式來存儲這些結構,從而達到優化存儲空間的目的。然而,ziplist會以序列化的方式存儲數據,這些序列化數據每次被讀取的時候都要就行解碼,每次被寫入的時候都要進行局部的重新編碼,並且可能需要對內存里的數據進行移動。因此讀寫一個長度較大的ziplist可能會造成性能問題。從我們的生產運維經驗上來講,以下參數設置可以借鑒(根據業務和實際情況進行不斷調整):

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

即:當有序集合的元素都小於64字節並且元素數量小於128個的時候,使用ziplist,反之使用skiplist。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM