Redis 的過時時間設置是一個很經常使用的操做,畢竟 redis 不是用來作持久化存儲的。java
Redis 自帶的過時機制只能對 key 過時,而不能對具體的值過時,可是在某些特定的場景下須要對部分值過時。設想一個場景,有一篇文章,經過惟一的 id 進行標識。如今有個需求是要對每篇文章 15 分鐘內的的閱讀量進行統計,每分鐘統計一次,而後查看文章閱讀量的變化。因此數據形式大體以下:redis
[1, 5, 6, 10, 16 ...]
複製代碼
可是我只須要 15 分鐘內的數據,要否則內存可能就不夠用了,這個時候利用 key 過時的方式就沒法知足需求了,因此能夠利用 Redis 的一些特性來完成這個需求。shell
Redis 的有序集合能夠存儲一系列有序的值,對於值能夠指定 score,而後根據 score 來進行排序:json
ZAAD key score value
複製代碼
而後能夠經過 ZRANGEBYSCORE 來獲取必定範圍內 score 所對應的 value。bash
ZRANGEBYSCORE key score1 score2
複製代碼
能夠利用上面的這個特性來完成需求。微信
能夠把統計的文章的閱讀數量經過以下的格式添加進行 Redis,以文章的 id 做爲 key, 當前的時間戳做爲 score,當前文章的閱讀數做爲 value。像下面這樣:spa
# 文章id 時間戳 閱讀數
ZADD id 1577591750 54
複製代碼
而後要獲取 15 分鐘內的閱讀數量統計,假設當前的時間戳是 now:設計
ZRANGEBYSCORE id now - 15 * 60 now
複製代碼
上面的操做就能夠達到目的了,可是仍是有點不完美,由於隨着時間的推移,這個有序列表會愈來愈長,最後內存仍是會被搞爆掉。因此在每次獲取 15 分鐘內的值時,還要把超過 15 分鐘的值給刪掉,這樣就和過時的效果同樣了:code
ZRANGEBYSCORE id 0 now - 15 * 60
複製代碼
如今看起來比較完美了,即能完成需求,又能保住內存。可是仍是存在一個小問題,假設這篇文章再也不有人訪問了,那麼這個值就會永遠停在內存中(假設不宕機)。因此保險一點,能夠給這個 key 也設置一個過時的時間:cdn
# 24 小時後整個 key 過時,內存回收
EXPIRE key 24* 60 * 60
複製代碼
如今果然完美了,即知足了要求,也保全了內存。不是我囉嗦,可是這個從功能的角度仍是有點小問題,由於有序集合中存儲的值只能是惟一的,要是兩次統計的閱讀量同樣,就會有點小問題。這個也容易解決,把每一個 value 設計成以下的形式就能夠了:
{
value: numbers,
timestamp: 1577591750
}
複製代碼
這樣一來,每一個 value 都是獨一無二的了,這樣真的是完美了。示意圖以下:
只有 黃色框內的值纔是有效的,這個框就表示15分鐘的有效時間。框外的就表示過時的 value。
關注微信公衆號,聊點其餘的