Redis 緩衝失效機制

來源:互聯網
上載者:User

標籤:

Redis緩衝失效的故事要從EXPIRE這個命令說起,EXPIRE允許使用者為某個key指定逾時時間,當超過這個時間之後key對應的值會被清除,這篇文章主要在分析Redis源碼的基礎上站在Redis設計者的角度去思考Redis緩衝失效的相關問題。

 

Redis緩衝失效機制

 

Redis緩衝失效機制是為應對緩衝應用的一種很常見的情境而設計的,講個情境:

 

我們為了減輕後端資料庫的壓力,很開心的藉助Redis服務把變化頻率不是很高的資料從DB load出來放入了緩衝,因此之後的一段時間內我們都可以直接從緩衝上拿資料,然而我們又希望一段時間之後,我們再重新的從DB load出當前的資料放入緩衝,這個事情怎麼做呢?

 

問題提出來了,這個問題怎麼解決呢?好吧,我們對於手頭的語言工具很熟悉,堅信可以很快的寫出這麼一段邏輯:我們記錄上次從db load資料的時間,然後每次響應服務的時候都去判斷時間是不是到期了,要不要從db重新load了……。當然這種方法也是可以的,然而當我們查閱Redis command document的時候,發現我們做了本來不需要做的事情,Redis本身提供這種機制,我們只要藉助EXPIRE命令就可以輕鬆的搞定這件事情:

 

EXPIRE key 30

 

上面的命令即為key設定30秒的到期時間,超過這個時間,我們應該就訪問不到這個值了,到此為止我們大概明白了什麼是緩衝失效機制以及緩衝失效機制的一些應用情境,接下來我們繼續深入探究這個問題,Redis緩衝失效機制是如何?的呢?

 

延遲失效機制

 

延遲失效機制即當用戶端請求操作某個key的時候,Redis會對用戶端請求操作的key進行有效期間檢查,如果key到期才進行相應的處理,延遲失效機制也叫消極失效機制。我們看看t_string組件下面對get請求處理的服務端端執行堆棧:

 

getCommand

     -> getGenericCommand

            -> lookupKeyReadOrReply

                   -> lookupKeyRead

                         -> expireIfNeeded

 

關鍵的地方是expireIfNeed,Redis對key的get操作之前會判斷key關聯的值是否失效,這裡先插入一個小插曲,我們看看Redis中實際儲存值的地方是什麼樣子的:

 

typedef struct redisDb {

    dict *dict;                 /* The keyspace for this DB */

    dict *expires;              /* Timeout of keys with a timeout set */

    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP) */

    dict *ready_keys;           /* Blocked keys that received a PUSH */

    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */

    int id;

    long long avg_ttl;          /* Average TTL, just for stats */

} redisDb;

 

上面是Redis中定義的一個結構體,dict是一個Redis實現的一個字典,也就是每個DB會包括上面的五個欄位,我們這裡只關心兩個字典,一個是dict,一個是expires:

 

  1. dict是用來儲存正常資料的,比如我們執行了set key “hahaha”,這個資料就儲存在dict中。

     

  2. expires使用來儲存關聯了到期時間的key的,比如我們在上面的基礎之上有執行的expire key 1,這個時候就會在expires中添加一條記錄。

 

回過頭來看看expireIfNeeded的流程,大致如下:

 

  1. 從expires中尋找key的到期時間,如果不存在說明對應key沒有設定到期時間,直接返回。

     

  2. 如果是slave機器,則直接返回,因為Redis為了保證資料一致性且實現簡單,將緩衝失效的主動權交給Master機器,slave機器沒有許可權將key失效。

     

  3. 如果當前是Master機器,且key到期,則master會做兩件重要的事情:1)將刪除命令寫入AOF檔案。2)通知Slave當前key失效,可以刪除了。

     

  4. master從本地的字典中將key對於的值刪除。

  主動失效機制

 

主動失效機制也叫積極失效機制,即服務端定時的去檢查失效的緩衝,如果失效則進行相應的操作。

 

我們都知道Redis是單線程的,基於事件驅動的,Redis中有個EventLoop,EventLoop負責對兩類事件進行處理:

 

  1. 一類是IO事件,這類事件是從底層的多工器分離出來的。

     

  2. 一類是定時事件,這類事件主要用來事件對某個任務的定時執行。

 

看起來Redis的EventLoop和Netty以及JavaScript的EventLoop功能設計的大概類似,一方面對網路I/O事件處理,一方面還可以做一些小任務。

 

為什麼講到Redis的單執行緒模式,因為Redis的主動失效機制邏輯是被當做一個定時任務來由主線程執行的,相關代碼如下:

 

if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {

        redisPanic("Can‘t create the serverCron time event.");

        exit(1);

    }

 

serverCron就是這個定時任務的函數指標,adCreateTimeEvent將serverCron任務註冊到EventLoop上面,並設定初始的執行時間是1毫秒之後。接下來,我們想知道的東西都在serverCron裡面了。serverCron做的事情有點多,我們只關心和本篇內容相關的部分,也就是緩衝失效是怎麼實現的,我認為看代碼做什麼事情,呼叫堆疊還是比較直觀的:

 

aeProcessEvents

    ->processTimeEvents

        ->serverCron

             -> databasesCron

                   -> activeExpireCycle

                           -> activeExpireCycleTryExpire

 

EventLoop通過對定時任務的處理,觸發對serverCron邏輯的執行,最終之執行key到期處理的邏輯,值得一提的是,activeExpireCycle邏輯只能由master來做。

 

遺留問題

 

Redis對緩衝失效的處理機制大概分為兩種,一種是用戶端訪問key的時候消極的處理,一種是主線程週期性積極地去執行緩衝失效清理邏輯,上面文章對於一些細節還沒有展開介紹,但是對於Redis緩衝失效實現機制這個話題,本文留下幾個問題:

 

  1. Redis緩衝失效邏輯為什麼只有master才能操作?

     

  2. 上面提到如果用戶端訪問的是slave,slave並不會清理失效緩衝,那麼這次用戶端豈不是擷取了失效的緩衝?

     

  3. 上面介紹的兩種緩衝失效機制各有什麼優缺點?Redis設計者為什麼這麼設計?

     

  4. 服務端對用戶端的請求處理是單線程的,單線程又要去處理失效的緩衝,是不是會影響Redis本身的服務能力?

Redis 緩衝失效機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.