原文出處:點擊開啟連結
對於緩衝失效,不同的緩衝有不同的處理機制,可以說是大同中有小異,作者通過對Redis 文檔與相關源碼的仔細研讀,為大家詳細剖析了 Redis 的緩衝到期/失效機制相關的技術原理與實現細節。
下面是作者原文:
作為一種定期清理無效資料的重要機制,主鍵失效存在於大多數緩衝系統中,Redis 也不例外。在 Redis 提供的諸多命令中,EXPIRE、EXPIREAT、PEXPIRE、PEXPIREAT 以及 SETEX 和 PSETEX 均可以用來設定一條 Key-Value 對的失效時間,而一條 Key-Value 對一旦被關聯了失效時間就會在到期後自動刪除(或者說變得無法訪問更為準確)。可以說,主鍵失效這個概念還是比較容易理解的,但是在具體實現到 Redis 中又是如何呢。最近本博主就對 Redis 中的主鍵失效機制產生了幾個疑問,並根據這些疑問對其進行了仔細的探究,現總結所得如下,以饗各位看客。 一、失效時間的控制
除了調用PERSIST命令外,還有沒有其他情況會撤銷一個主鍵的失效時間。答案是肯定的。首先,在通過 DEL 命令刪除一個主鍵時,失效時間自然會被撤銷(這不是廢話麼,哈哈)。其次,在一個設定了失效時間的主鍵被更新覆蓋時,該主鍵的失效時間也會被撤銷(這貌似也是廢話,哈哈)。但需要注意的是,這裡所說的是主鍵被更新覆蓋,而不是主鍵對應的 Value 被更新覆蓋,因此 SET、MSET 或者是 GETSET 可能會導致主鍵被更新覆蓋,而像 INCR、DECR、LPUSH、HSET 等都是更新主鍵對應的值,這類操作是不會觸碰主鍵的失效時間的。此外,還有一個特殊的命令就是 RENAME,當我們使用 RENAME 對一個主鍵進行重新命名後,之前關聯的失效時間會自動傳遞給新的主鍵,但是如果一個主鍵是被RENAME所覆蓋的話(如主鍵 hello 可能會被命令 RENAME world hello 所覆蓋),這時被覆蓋主鍵的失效時間會被自動撤銷,而新的主鍵則繼續保持原來主鍵的特性。 二、失效的內部實現
Redis 中的主鍵失效是如何?的,即失效的主鍵是如何刪除的。實際上,Redis 刪除失效主鍵的方法主要有兩種: 消極方法(passive way),在主鍵被訪問時如果發現它已經失效,那麼就刪除它 積極方法(active way),周期性地從設定了失效時間的主鍵中選擇一部分失效的主鍵刪除 失效的內部表示
接下來我們就通過代碼來探究一下這兩種方法的具體實現,但在此之前,我們先看一看Redis是如何管理和維護主鍵的吧(註:本博文中的源碼全部來自 Redis-2.6.12)。
【程式碼片段一】給出了 Redis 中關於資料庫的結構體定義,這個結構體定義中除了 id 以外都是指向字典的指標,其中我們只看 dict 和 expries,前者用來維護一個 Redis 資料庫中包含的所有 Key-Value 對(其結構可以理解為 dict[key]:value,即主鍵與值之間的映射),後者則用於維護一個 Redis 資料庫中設定了失效時間的主鍵(其結構可以理解為 expires[key]:timeout,即主鍵與失效時間的映射)。當我們使用 SETEX 和 PSETEX 命令向系統插入資料時,Redis 首先將 Key 和 Value 添加到 dict 這個字典表中,然後將 Key 和失效時間添加到 expires 這個字典表中。當我們使用 EXPIRE、EXPIREAT、PEXPIRE 和 PEXPIREAT 命令設定一個主鍵的失效時間時,Redis 首先到 dict 這個字典表中尋找要設定的主鍵是否存在,如果存在就將這個主鍵和失效時間添加到 expires 這個字典表。簡單地總結來說就是,設定了失效時間的主鍵和具體的失效時間全部都維護在 expires 這個字典表中。
【程式碼片段一】 C
1 2 3 4 5 6 7 8 |
typedef struct redisDb { dict * dict ; dict * expires ; dict * blocking_keys ; dict * ready_keys ; dict * watched_keys ; int id ; } redisDb ; |
消極方法
在大致瞭解了 Redis 是如何維護設定了失效時間的主鍵之後,我們就先來看一看 Redis 是如何?消極地刪除失效主鍵的。【程式碼片段二】給出了一個名為 expireIfNeeded 的函數,這個函數在任何訪問資料的函數中都會被調用