redis設置鍵的生存時間或過期時間


設置鍵的生存時間或過期時間

通過EXPIRE 命令或者PEXPIRE 命令,客戶端可以以秒或者毫秒精度為數據庫中的某個鍵設置生存時間( Time To Live , TTL) ,在經過指定的秒數或者毫秒數之后,服務器就會自動刪除生存時間為0的鍵:

復制代碼
redis> SET key value
OK
redis> EXP 工RE key 5
(integer) 1
redis> GET key // 5 秒之內
"value"
redis> GET key // 5 秒之后
(nil)
復制代碼

注意
SETEX 命令可以在設直一個字符串鍵的同時為鍵設直過期時間,因為這個命令是一個類型限定的命令(只能用於字符串鍵),但SETEX 命令設置過期時間的原理和EXPIRE命令設置過期時間的原理是完全一樣的。

與EXPlRE 命令和PEXPIRE 命令類似,客戶端可以通過EXPlREAT 命令或PEXPlREAT命令,以秒或者毫秒精度給數據庫中的某個鍵設置過期時間(expire time)。
過期時間是一個UNIX時間戳,當鍵的過期時間來臨時,服務器就會自動從數據庫中刪除這個鍵:

 

復制代碼
redis> SET key value
OK
redis> EXPIREAT key 1377257300
(integer) 1
redis> TIME

1)"1377257296"
2)"296543"
redis> GET key // 1377257300 之前
"value"
redis> TIME
1)"1377257303"
2)"230656 "
redis> GET key // 1377257300 之后
(nil)
復制代碼

 

TTL 命令和PTTL 命令接受一個帶有生存時間或者過期時間的鍵,返回這個鍵的剩余生存時間,也就是,返回距離這個鍵被服務器自動刪除還有多長時間:

復制代碼
redis> SET key va1ue
OK
redis> EXPlRE key 1000
(integer) 1
redis> TTL key
(integer) 997
redis> SET another_key another_value
OK
redis> TIME
1) "1377333070 "
2)  "761687 "
redis> EXPlREAT another key 1377333100
(integer ) 1
redis> TTL another key
(integer) 10
復制代碼

設置過期時間

 

Redis 有四個不同的命令可以用於設置鍵的生存時間(鍵可以存在多久)或過期時間(鍵什么時候會被刪除) :
EXPlRE <key> <ttl> 命令用於將鍵key 的生存時間設置為ttl 秒。
PEXPIRE <key> <ttl> 命令用於將鍵key 的生存時間設置為ttl 毫秒。
EXPIREAT <key> < timestamp> 命令用於將鍵key 的過期時間設置為timestamp所指定的秒數時間戳。
PEXPIREAT <key> < timestamp > 命令用於將鍵key 的過期時間設置為timestamp所指定的毫秒數時間戳。

雖然有多種不同單位和不同形式的設置命令,但實際上EXPlRE、PEXPlRE 、EXPIREAT三個命令都是使用PEXPlREAT 命令來實現的:無論客戶端執行的是以上四個命令中的哪一個, 經過轉換之后,最終的執行效果都和執行PEXPlREAT 命令一樣。
首先, EXPIRE 命令可以轉換成PEXPlRE 命令:

def EXPIRE(key,ttl_in_sec):
#將TTL 從秒轉換成毫秒
ttl_in_ms = sec_to_ms(ttl_in_sec )
PEXPlRE(key, ttl_in_ms)

接着,PEXPlRE 命令又可以轉換成PEXPlREAT 命令:

def PEXPIRE(key,ttl_in_ms) :
#獲取以毫秒計算的當前UNIX 時間戳
now_ms = get_current_unix_timestamp_in_ms()
#當前時間加上TTL,得出毫秒格式的鍵過期時間
PEXPlREAT(key,now_ms+ttl_in_ms)

並且,EXPlREAT命令也可以轉換成PEXPlREAT命令:

def EXPIREAT (key,expire_time_in_ sec):
#將過期時間從秒轉換為毫秒
expire_time_ in_ms = sec_to_ms (expire_time_in_sec)
PEXPlREAT(key, expire_time_in_ms)

保存過期時間

redisDB結構的expires字典保存了數據庫中所有鍵的過期時間,我們稱這個字典為過期字典:
過期字典的鍵是一個指針,這個指針指向鍵空間中的某個鍵對象( 也即是某個數據庫鍵)。
過期字典的值是一個long long 類型的整數,這個整數保存了鍵所指向的數據庫鍵的過期時間:一個毫秒精度的UNIX 時間戳。

復制代碼
typedef struct redisDb {
//...
// 過期字典,保存着鍵的過期時間

dict *expires ;
//...
} redisDb;
復制代碼

如下圖展示了一個帶有過期字典的數據庫例子,在這個例子中,鍵空間保存了數據庫中的所有鍵值對,而過期字典則保存了數據庫鍵的過期時間。

過期字典將新增一個鍵值對, 其中鍵為message 鍵對象,而值則為1391234400000(2014年2月1日零時) ,如圖9-13 所示。

圖9-12 中的過期字典保存了兩個鍵值對:
第一個鍵值對的鍵為alphabet 鍵對象,值為1385877600000 ,這表示數據庫鍵alphabet 的過期時間為1385877600000 (2013年12月1日零時)。
第二個鍵值對的鍵為book鍵對象,值為1388556000000,這表示數據庫鍵book的過期時間為1388556000000(2014年1月1日零時)。
當客戶端執行PEXPIREAT 命令(或者其他三個會轉換成PEXPIREAT命令的命令)為一個數據庫鍵設置過期時間時,服務器會在數據庫的過期字典中關聯給定的數據庫鍵和過期時間。
舉個例子, 如果數據庫當前的狀態如圖9-12 所示, 那么在服務器執行以下命令之后:

redis> PEXPIREAT message 1 391234400000
(integer) 1

過期字典將新增一個鍵值對,其中鍵為message鍵對象,而值則為1391234400000(2014年2月1日零時),如圖9-13 所示。

 以下是PEXPlREAT 命令的偽代碼定義:

復制代碼
def PEXPIREAT(key,expire_time_in_ms) :
#如果給定的鍵不存在於鍵空間,那么不能設置過期時間
if key not in redisDB.dict :
return 0
#在過期字典中關聯鍵和過期時間
redisDB.expires[key]=expire_tirne_in_ms
#過期時間設置成功
return 1
復制代碼

移除過期時間

PERSIST命令可以移除一個鍵的過期時間:

復制代碼
redis>PEXPlREAT message 1391234400000
(integer) 1
redis>TTL message
(integer) 13893281
redis> PERSIST message
(integer) 1
redis> TTL message
(integer) - 1
復制代碼

PERSIST命令就是PEXPIREAT命令的反操作: PERSIST 命令在過期字典中查找給定的鍵,並解除鍵和值(過期時間)在過期字典中的關聯。
舉個例子,如果數據庫當前的狀態如圖9-12所示,那么當服務器執行以下命令之后:

redis> PERSIST book
(integer) 1

數據庫將更新成圖9-14 所示的狀態。

可以看到,當PERSIST命令執行之后,過期字典中原來的book鍵值對消失了,這代表數據庫鍵book的過期時間已經被移除。
以下是PERSIST 命令的偽代碼定義:

復制代碼
def PERSIST(key) :
#如果鍵不存在,或者鍵沒有設置過期時間,那么直接返回
if key not in redisDB.expires:
return 0
#移除過期字典中給定鍵的鍵值對關聯
redisDB.expires.remove(key)
#鍵的過期時間移除成功
return 1
復制代碼

計算並返回剩余生存時間

TTL 命令以秒為單位返回鍵的剩余生存時間, 而P TTL 命令則以毫秒為單位返回鍵的剩余生存時間:

redis> PEXPIREAT alphabet 1385877600000
(integer) 1
redis> TTL alphabet
(integer) 85 49007
redis> PTTL alphabet
(integer) 8549001011

TTL 和PTTL 兩個命令都是通過計算鍵的過期時間和當前時間之間的差來實現的,以下
是這兩個命令的偽代碼實現:

復制代碼
def PTTL (key) :
#鍵不存在於數據庫
if key not in redisDb.dict:
return -2
#嘗試取得鍵的過期時間
#如果鍵沒有設置過期時間,那么expire_time_in_ms將為None
expire_time_in_ms = redisDB.expires.get(key)
#鍵沒有設置過期時間
if expire time in ms is None:
return -1
#獲得當前時間
now_ms = get_current_unix _timestamp_in_ms ()
#過期時間減去當前時間, 得出的差就是鍵的剩余生存時間
return(expire_time_in_ms - now_ms)
def TTL(key):
#獲取以毫秒為單位的剩余生存時間
ttl_in_ms = PTTL (key )
if ttl_in_ms < 0:
#處理返回值為2 和斗的情況
return ttl_in_ms
else:
#將毫秒轉換為秒
return ms_to_sec(ttl_in_ms)
復制代碼

舉個例子,對於一個過期時間為1385877600000(2013年12月1日零時)的鍵alphabet來說:
如果當前時間為1383282000000 (2013年11月1日零時),那么對鍵alphabet執行PTTL命令將返回2595600000 ,這個值是通過用a1phabet 鍵的過期時間減去當前時間計算得出的: 1385877600000-1383282000000=25956000000
另一方面,如果當前時間為1383282000000 ( 2013年11月1日零時),那么對鍵alphabet執行TTL命令將返回2595600,這個值是通過計算alphabet 鍵的過期時間減去當前時間的差,然后將差值從毫秒轉換為秒之后得出的。

過期鍵的判定

通過過期字典,程序可以用以下步驟檢查一個給定鍵是否過期:
1 )檢查給定鍵是否存在於過期字典:如果存在,那么取得鍵的過期時間。
2 )檢查當前UNIX 時間戳是否大於鍵的過期時間: 如果是的話,那么鍵已經過期;否則的話,鍵未過期。
可以用偽代碼來描述這一過程:

復制代碼
def is expired(key) :
#取得鍵的過期時間
expire_time_in_ms = redisDB.expires.get(key)
#鍵沒有設置過期時間
if expire_time_in_ms is none:
    return false
#取得當前時間的UNIX 時間戳
now_ms = get_current_unix_timestamp_in_ms()
#檢查當前時間是否大於鍵的過期時間
if now_ms > expire time_in_ms :
#是,鍵已經過期
return true
else :
# 否,鍵未過期
return false
復制代碼

舉個例子,對於一個過期時間為1385877600000 (2013年12月1日零時)的鍵alphabet來說:

如果當前時間為1383282000000 (2013 年II 月1 日零時),那么調用is_expired ( alphabet ) 將返回False ,因為當前時間小於alphabet 鍵的過期時間。
另一方面,如果當前時間為1385964000000 (2013年12月2日零時),那么調用is_expired(alphabet) 將返回True. 因為當前時間大於alphabet 鍵的過期時間。

注意
實現過期鍵判定的另一種方法是使用TTL 命令或者PTTL 命令,比如說,如采對某個鍵執行TTL 命令,並且命令返回的位大於等於0 ,那么說明該鍵未過期。在實際中, Redis檢查鍵是否過期的方法和is_expired函數所描述的方法一致,因為直接訪問字典比執行一個命令稍微快一些。


免責聲明!

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



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