redis的逾時刪除策略

來源:互聯網
上載者:User

標籤:

 

這個問題有三種可能的答案,它們分別代表了三種不同的刪除策略:

·定時刪除:在設定鍵的到期時間的同時,建立一個定時器(timer),讓定時器在鍵的到期時間來臨時,立即執行對鍵的刪除操作。

·惰性刪除:放任鍵到期不管,但是每次從鍵空間中擷取鍵時,都檢查取得的鍵是否到期,如果到期的話,就刪除該鍵;如果沒有到期,就返回該鍵。

·定期刪除:每隔一段時間,程式就對資料庫進行一次檢查,刪除裡面的到期鍵。至於要刪除多少到期鍵,以及要檢查多少個資料庫,則由演算法決定。

在這三種策略中,第一種和第三種為主動刪除策略,而第二種則為被動刪除策略。

 定時刪除

定時刪除策略對記憶體是最友好的:通過使用定時器,定時刪除策略可以保證到期鍵會儘可能快地被刪除,並釋放到期鍵所佔用的記憶體。

另一方面,定時刪除策略的缺點是,它對CPU時間是最不友好的:在到期鍵比較多的情況下,刪除到期鍵這一行為可能會佔用相當一部分CPU時間,在記憶體不緊張但是CPU時間非常緊張的情況下,將CPU時間用在刪除和當前任務無關的到期鍵上,無疑會對伺服器的回應時間和輸送量造成影響。

例如,如果正有大量的命令請求在等待伺服器處理,並且伺服器當前不缺少記憶體,那麼伺服器應該優先將CPU時間用在處理用戶端的命令請求上面,而不是用在刪除到期鍵上面。

除此之外,建立一個定時器需要用到Redis伺服器中的時間事件,而目前時間事件的實現方式——無序鏈表,尋找一個事件的時間複雜度為O(N)——並不能高效地處理大量時間事件。

因此,要讓伺服器建立大量的定時器,從而實現定時刪除策略,在現階段來說並不現實。

 惰性刪除

惰性刪除策略對CPU時間來說是最友好的:程式只會在取出鍵時才對鍵進行到期檢查,這可以保證刪除到期鍵的操作只會在非做不可的情況下進行,並且刪除的目標僅限於當前處理的鍵,這個策略不會在刪除其他無關的到期鍵上花費任何CPU時間。

惰性刪除策略的缺點是,它對記憶體是最不友好的:如果一個鍵已經到期,而這個鍵又仍然保留在資料庫中,那麼只要這個到期鍵不被刪除,它所佔用的記憶體就不會釋放。

在使用惰性刪除策略時,如果資料庫中有非常多的到期鍵,而這些到期鍵又恰好沒有被訪問到的話,那麼它們也許永遠也不會被刪除(除非使用者手動執行FLUSHDB),我們甚至可以將這種情況看作是一種記憶體流失——無用的垃圾資料佔用了大量的記憶體,而伺服器卻不會自己去釋放它們,這對於運行狀態非常依賴於記憶體的Redis伺服器來說,肯定不是一個好訊息。

舉個例子,對於一些和時間有關的資料,比如日誌(log),在某個時間點之後,對它們的訪問就會大大減少,甚至不再訪問,如果這類到期資料大量地積壓在資料庫中,使用者以為伺服器已經自動將它們刪除了,但實際上這些鍵仍然存在,而且鍵所佔用的記憶體也沒有釋放,那麼造成的後果肯定是非常嚴重的。

定期刪除

從上面對定時刪除和惰性刪除的討論來看,這兩種刪除方式在單一使用時都有明顯的缺陷:

·定時刪除佔用太多CPU時間,影響伺服器的回應時間和輸送量。

·惰性刪除浪費太多記憶體,有記憶體流失的危險。

定期刪除策略是前兩種策略的一種整合和折中:

·定期刪除策略每隔一段時間執行一次刪除到期鍵操作,並通過限制刪除操作執行的時間長度和頻率來減少刪除操作對CPU時間的影響。

·除此之外,通過定期刪除到期鍵,定期刪除策略有效地減少了因為到期鍵而帶來的記憶體浪費。

定期刪除策略的痛點是確定刪除操作執行的時間長度和頻率:

·如果刪除操作執行得太頻繁,或者執行的時間太長,定期刪除策略就會退化成定時刪除策略,以至於將CPU時間過多地消耗在刪除到期鍵上面。

·如果刪除操作執行得太少,或者執行的時間太短,定期刪除策略又會和惰性刪除策略一樣,出現浪費記憶體的情況。

因此,如果採用定期刪除策略的話,伺服器必鬚根據情況,合理地設定刪除操作的執行時間長度和執行頻率。

 

 

 

到期鍵的定期刪除策略由redis.c/activeExpireCycle函數實現,每當Redis的伺服器周期性操作redis.c/serverCron函數執行時,activeExpireCycle函數就會被調用,它在規定的時間內,分多次遍曆伺服器中的各個資料庫,從資料庫的expires字典中隨機檢查一部分鍵的到期時間,並刪除其中的到期鍵。

整個過程可以用虛擬碼描述如下:

# 預設每次檢查的資料庫數量DEFAULT_DB_NUMBERS = 16# 預設每個資料庫檢查的鍵數量DEFAULT_KEY_NUMBERS = 20# 全域變數,記錄檢查進度current_db = 0def activeExpireCycle():    # 初始化要檢查的資料庫數量    # 如果伺服器的資料庫數量比 DEFAULT_DB_NUMBERS 要小    # 那麼以伺服器的資料庫數量為準    if server.dbnum < DEFAULT_DB_NUMBERS:        db_numbers = server.dbnum    else:        db_numbers = DEFAULT_DB_NUMBERS    # 遍曆各個資料庫    for i in range(db_numbers):        # 如果current_db的值等於伺服器的資料庫數量        # 這表示檢查程式已經遍曆了伺服器的所有資料庫一次        # 將current_db重設為0,開始新的一輪遍曆        if current_db == server.dbnum:            current_db = 0        # 擷取當前要處理的資料庫        redisDb = server.db[current_db]        # 將資料庫索引增1,指向下一個要處理的資料庫        current_db += 1        # 檢查資料庫鍵        for j in range(DEFAULT_KEY_NUMBERS):            # 如果資料庫中沒有一個鍵帶有到期時間,那麼跳過這個資料庫            if redisDb.expires.size() == 0: break            # 隨機擷取一個帶有到期時間的鍵            key_with_ttl = redisDb.expires.get_random_key()            # 檢查鍵是否到期,如果到期就刪除它            if is_expired(key_with_ttl):                delete_key(key_with_ttl)            # 已達到時間上限,停止處理            if reach_time_limit(): return

activeExpireCycle函數的工作模式可以總結如下:

·函數每次運行時,都從一定數量的資料庫中取出一定數量的隨機鍵進行檢查,並刪除其中的到期鍵。

·全域變數current_db會記錄當前activeExpireCycle函數檢查的進度,並在下一次activeExpireCycle函數調用時,接著上一次的進度進行處理。比如說,如果當前activeExpireCycle函數在遍曆10號資料庫時返回了,那麼下次activeExpireCycle函數執行時,將從11號資料庫開始尋找並刪除到期鍵。

·隨著activeExpireCycle函數的不斷執行,伺服器中的所有資料庫都會被檢查一遍,這時函數將current_db變數重設為0,然後再次開始新一輪的檢查工作。

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.