Redis數據過時策略探究

經過EXPIRE key seconds命令來設置數據的過時時間。返回1代表設置成功,返回0代表key不存在或者不能成功設置過時時間。mysql

在key上設置了過時時間後key將在指定的秒數後被自動刪除。被指定了過時時間的key在Redis中被稱爲是不穩定的。redis

當key被DEL命令刪除或者被SET、GETSET命令重置後與之關聯的過時時間會被清除。算法

redis 127.0.0.1:6379> set mykey "test expire"  
OK  
redis 127.0.0.1:6379> expire mykey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) 97  
redis 127.0.0.1:6379> ttl mykey  
(integer) 93  
redis 127.0.0.1:6379> set mykey "test expire reset"  
OK  
redis 127.0.0.1:6379> ttl mykey  
(integer) -1  
  
redis 127.0.0.1:6379> set mykey "test expire"  
OK  
redis 127.0.0.1:6379> expire mykey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) 98  
redis 127.0.0.1:6379> ttl mykey  
(integer) 91  
redis 127.0.0.1:6379> getset mykey "test expire reset"  
"test expire"  
redis 127.0.0.1:6379> ttl mykey  
(integer) -1

這也意味着僅從概念上更新了存儲在key中的值而沒有用全新的值替換key原有值的全部操做都不會影響在該key上設置的過時時間。例如使用INCR命令增長key的值或者經過LPUSH命令在list中增長一個新的元素或者使用HSET命令更新hash字段的值都會回清除原有的過時時間設置。sql

redis 127.0.0.1:6379> set mykey 1  
OK  
redis 127.0.0.1:6379> expire mykey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) 95  
redis 127.0.0.1:6379> incr mykey  
(integer) 2  
redis 127.0.0.1:6379> ttl mykey  
(integer) 77  
  
redis 127.0.0.1:6379> lpush listkey 1  
(integer) 1  
redis 127.0.0.1:6379> expire listkey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl listkey  
(integer) 94  
redis 127.0.0.1:6379> lpush listkey 2  
(integer) 2  
redis 127.0.0.1:6379> ttl listkey  
(integer) 82  
  
redis 127.0.0.1:6379> hmset hashkey name "redis" passwd "redis"  
OK  
redis 127.0.0.1:6379> expire hashkey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl hashkey  
(integer) 95  
redis 127.0.0.1:6379> hset hashkey  passwd "redis.vs.mysql"  
(integer) 0  
redis 127.0.0.1:6379> ttl hashkey  
(integer) 66

固然也可經過PERSIST命令清除已設置的過時時間從新將key變爲持久的。測試

redis 127.0.0.1:6379> set mykey 'test clear expire'  
OK  
redis 127.0.0.1:6379> expire mykey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) 96  
redis 127.0.0.1:6379> persist mykey  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) -1

若key被RENAME命令重命名則與之關聯的過時時間將傳遞到新名稱的key。code

redis 127.0.0.1:6379> get mykeynew  
(nil)  
redis 127.0.0.1:6379> set mykey 'test expire transfer'  
OK  
redis 127.0.0.1:6379> expire mykey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) 96  
redis 127.0.0.1:6379> rename mykey mykeynew  
OK  
redis 127.0.0.1:6379> ttl mykey  
(integer) -1  
redis 127.0.0.1:6379> ttl mykeynew  
(integer) 80

若key被RENAME命令重寫,好比本存在名爲mykey_a和mykey_b的key一個RENAME mykey_b mykey_a命令將mykey_b重命名爲本已存在的mykey_a那麼不管mykey_a原來的設置如何都將繼承mykey_b的全部特性,包括過時時間設置。繼承

redis 127.0.0.1:6379> set mykey_b 'b'  
OK  
redis 127.0.0.1:6379> set mykey_a 'a'  
OK  
redis 127.0.0.1:6379> expire mykey_b 100  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey_b  
(integer) 93  
redis 127.0.0.1:6379> ttl mykey_a  
(integer) -1  
redis 127.0.0.1:6379> rename mykey_b mykey_a  
OK  
redis 127.0.0.1:6379> ttl mykey_b  
(integer) -1  
redis 127.0.0.1:6379> ttl mykey_a  
(integer) 66

EXPIRE key seconds應用於一個已經設置了過時時間的key上時原有的過時時間將被更新爲新的過時時間內存

redis 127.0.0.1:6379> set mykey 'test expire update'  
OK  
redis 127.0.0.1:6379> expire mykey 100  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) 95  
redis 127.0.0.1:6379> expire mykey 1000  
(integer) 1  
redis 127.0.0.1:6379> ttl mykey  
(integer) 998

附錄:
key的過時時間
一般,Redis key被建立時不會自動關聯過時時間,key將長久存在,除非經過DEL等命令顯示的刪除。EXPIRE命令簇能夠爲指定的key關聯一個過時時間,代價是一點額外的內存開銷。當key被設置了過時時間後Redis要保證在超時時移除該key。key的過時時間可被EXPIRE命令更新或者被PERSIST命令徹底移除。

過時時間的精度
Redis2.4中expire精度不高,一般在0到1秒間,Redis2.6之後expire精度能夠控制在0到1毫秒內。

過時與持久化
key的過時信息以絕對Unix時間戳的形式存儲(Redis2.6以後以毫秒級別的精度存儲)。這意味着,即便Redis實例沒有運行也不會對key的過時時間形成影響。
爲了使過時時間更正確的工做,必須檢查計算機的時間。若是將RDB快照從一臺計算機移動到另外一臺時間超前或滯後的計算機便會發生好玩的事情,好比數據剛載入便超時。即便是在同一機器的同一實例中若計算機的時間不正確或發生了變化一樣爲引發問題,好比一批數據的過時時間被設置爲了1000,以後計算機時間意外的快了2000秒,那麼這些key將馬上過時,而不是1000秒後過時。

Redis如何使key過時
Redis key過時的方式有二:被動方式和主動方式
當clients試圖訪問設置了過時時間且已過時的key時,爲主動過時方式。
但僅是這樣是不夠的,覺得可能存在一些key永遠不會被再次訪問到,這些設置了過時時間的key也是須要在過時後被刪除的。所以,Redis會週期性的隨機測試一批設置了過時時間的key並進行處理。測試到的已過時的key將被刪除。典型的方式爲,Redis每秒作10次以下的步驟:
1.隨機測試100個設置了過時時間的key
2.刪除全部發現的已過時的key
3.若刪除的key超過25個則重複步驟1
這是一個基於機率的簡單算法,基本的假設是抽出的樣本可以表明整個key空間,redis持續清理過時的數據直至將要過時的key的百分比降到了25%如下。這也意味着在任何給定的時刻已通過期但仍佔據着內存空間的key的量最多爲每秒的寫操做量除以4.

replication link和AOF文件中的過時處理
爲了得到正確的行爲而不至於致使一致性問題,當一個key過時時DEL操做將被記錄在AOF文件並傳遞到全部相關的slave。也即過時刪除操做統一在master實例中進行並向下傳遞,而不是各salve各自掌控。這樣一來便不會出現數據不一致的情形。當slave鏈接到master後並不能當即清理已過時的key(須要等待由master傳遞過來的DEL操做),slave仍需對數據集中的過時狀態進行管理維護以便於在slave被提高爲master會能像master同樣獨立的進行過時處理。get

相關文章
相關標籤/搜索