Redis 过期键删除策略
??點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:八個開源的 Spring Boot 學習資源,你值得擁有個人原創+1博客:點擊前往,查看更多 作者:羅曼蒂克 鏈接:https://www.jianshu.com/p/137aab0b0a1b有沒有想過Redis中過期的那些鍵去哪了?是誰在什么時候怎么刪掉的?
先來介紹一下各種方案:
定時刪除: 在設置鍵的過期時間的同時,創建一個定時器(timer),讓定時器在鍵的過期時間來臨時,立即執行對鍵的刪除操作.即從設置key的Expire開始,就啟動一個定時器,到時間就刪除該key;這樣會對內存比較友好,但浪費CPU資源
惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。即平時不處理,在使用的時候,先檢查該key是否已過期,已過期則刪除,否則不做處理;這樣對CPU友好,但是浪費內存資源,并且如果一個key不再使用,那么它會一直存在于內存中,造成浪費
定期刪除:**每隔一段時間,程序就對數據庫進行一次檢查,刪除里面的過期鍵。至于要刪除多少過期鍵,以及要檢查多少個數據庫,則由算法決定。**即設置一個定時任務,比如10分鐘刪除一次過期的key;間隔小則占用CPU,間隔大則浪費內存
在這三種策略中,第一種和第三種為主動刪除策略,而第二種則為被動刪除策略。
★Redis服務器實際使用的是惰性刪除和定期刪除兩種策略:通過配合使用這兩種刪除策略,服務器可以很好地在合理使用CPU時間和避免浪費內存空間之間取得平衡。
”惰性刪除策略的實現
過期鍵的惰性刪除策略由db.c/expireIfNeeded函數實現,所有讀寫數據庫的Redis命令在執行之前都會調用expireIfNeeded函數對輸入鍵進行檢查:
如果輸入鍵已經過期,那么expireIfNeeded函數將輸入鍵從數據庫中刪除。
如果輸入鍵未過期,那么expireIfNeeded函數不做動作。
expireIfNeeded函數就像一個過濾器,它可以在命令真正執行之前,過濾掉過期的輸入鍵,從而避免命令接觸到過期鍵。
另外,因為每個被訪問的鍵都可能因為過期而被expireIfNeeded函數刪除,所以每個命令的實現函數都必須能同時處理鍵存在以及鍵不存在這兩種情況:
當鍵存在時,命令按照鍵存在的情況執行。
當鍵不存在或者鍵因為過期而被expireIfNeeded函數刪除時,命令按照鍵不存在的情況執行。
舉個例子,下圖展示了GET命令的執行過程,在這個執行過程中,命令需要判斷鍵是否存在以及鍵是否過期,然后根據判斷來執行合適的動作。
定期刪除策略的實現
過期鍵的定期刪除策略由redis.c/activeExpireCycle函數實現,每當Redis的服務器周期性操作redis.c/serverCron函數執行時,activeExpireCycle函數就會被調用,它在規定的時間內,分多次遍歷服務器中的各個數據庫,從數據庫的expires字典中隨機檢查一部分鍵的過期時間,并刪除其中的過期鍵。
DEFAULT_DB_NUMBERS = 16 //默認每次檢查的數據庫數量 DEFAULT_KEY_NUMBERS = 20 //默認每個數據庫檢查的鍵數量 current_db = 0 //全局變量,記錄檢查進度 //以實際數據庫數量為準 if server.dbnum < DEFAULT_DB_NUMBERS:db_numbers = server.dbnum else:db_numbers = DEFAULT_DB_NUMBERS //遍歷各個數據庫 for i in range(db_numbers):if current_db == server.dbnum://如果current_db的值等于服務器的數據庫數量,current_db = 0 //這表示檢查程序已經遍歷了服務器的所有數據庫一次,將current_db重置為0,開始新的一輪遍歷redisDb = server.db[current_db] //獲取當前要處理的數據庫current_db += 1 //將數據庫索引增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//已達到時間上限,停止處理</code>activeExpireCycle函數的工作模式可以總結如下:
函數每次運行時,都從一定數量的數據庫中取出一定數量的隨機鍵進行檢查,并刪除其中的過期鍵。
全局變量current_db會記錄當前activeExpireCycle函數檢查的進度,并在下一次activeExpireCycle函數調用時,接著上一次的進度進行處理。比如說,如果當前activeExpireCycle函數在遍歷10號數據庫時返回了,那么下次activeExpireCycle函數執行時,將從11號數據庫開始查找并刪除過期鍵。
隨著activeExpireCycle函數的不斷執行,服務器中的所有數據庫都會被檢查一遍,這時函數將current_db變量重置為0,然后再次開始新一輪的檢查工作。
本文參考自 《Redis設計與實現》
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Redis 过期键删除策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring 事务底层原理,你会了吗?
- 下一篇: 硬核!如何在 Github 精准搜索开源