首頁  >  文章  >  資料庫  >  redis有定時刪除功能嗎

redis有定時刪除功能嗎

尚
原創
2019-06-28 17:50:078394瀏覽

redis有定時刪除功能嗎

Redis逾時刪除三種可能的答案,它們分別代表了三種不同的刪除策略:

定時刪除:在設定鍵的過期時間的同時,建立一個定時器(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 = 0
def 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相關知識,請造訪Redis使用教學欄位!

以上是redis有定時刪除功能嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn