redis系列之------過期策略

来源:https://www.cnblogs.com/wenbochang/archive/2020/03/07/12436350.html
-Advertisement-
Play Games

前言 我們都知道redis是常駐在記憶體當中的,因此他的效率比MySQL要快很多很多。但又引發了另外一個問題,記憶體從本質上講,它是昂貴的,不能用於大量的長時間的存儲,他是“不安全不穩定的“,並且有可能存在記憶體泄露,不能與磁碟相比。 那麼如果解決這種問題呢?因此我們使用redis的時候,強制的應該給每個 ...


前言

我們都知道redis是常駐在記憶體當中的,因此他的效率比MySQL要快很多很多。但又引發了另外一個問題,記憶體從本質上講,它是昂貴的,不能用於大量的長時間的存儲,他是“不安全不穩定的“,並且有可能存在記憶體泄露,不能與磁碟相比。

那麼如果解決這種問題呢?因此我們使用redis的時候,強制的應該給每個Key加上過期時間。我們來看看redis對過期的Key是怎麼處理的。

過期鍵的判定

第一個問題,redis如何知道他是一個過期鍵呢?又該如何判定他過期了呢?

在資料庫中, 所有鍵的過期時間都被保存在 redisDb 結構的 expires 字典里:

1 typedef struct redisDb {
2 
3     // ...
4 
5     dict *expires;
6 
7     // ...
8 
9 } redisDb;

expires 字典的鍵是一個指向 dict 字典(鍵空間)里某個鍵的指針, 而字典的值則是鍵所指向的資料庫鍵的到期時間, 這個值以 long long類型表示。

下圖展示了一個含有三個鍵的資料庫,其中 number 和 book 兩個鍵帶有過期時間

 

我們可以看到number和book是有一個過期時間的,他是long long類型。實則他是一個unix的時間戳,因此判斷他是否過期就十分的簡單了。

通過 expires 字典, 可以用以下步驟檢查某個鍵是否過期:

  1. 檢查鍵是否存在於 expires 字典:如果存在,那麼取出鍵的過期時間;
  2. 檢查當前 UNIX 時間戳是否大於鍵的過期時間:如果是的話,那麼鍵已經過期;否則,鍵未過期。

可以用偽代碼來描述這一過程:

 1 def is_expired(key):
 2 
 3     # 取出鍵的過期時間
 4     key_expire_time = expires.get(key)
 5 
 6     # 如果過期時間不為空,並且當前時間戳大於過期時間,那麼鍵已經過期
 7     if expire_time is not None and current_timestamp() > key_expire_time:
 8         return True
 9 
10     # 否則,鍵未過期或沒有設置過期時間
11     return False

過期鍵的清除

當我們知道這個鍵過期了,我們該如何清除呢?基本上有以下三種策略:

  • 定時刪除:在設置鍵的過期時間時,創建一個定時事件,當過期時間到達時,由事件處理器自動執行鍵的刪除操作。
  • 惰性刪除:放任鍵過期不管,但是在每次從 dict 字典中取出鍵值時,要檢查鍵是否過期,如果過期的話,就刪除它,並返回空;如果沒過期,就返回鍵值。
  • 定期刪除:每隔一段時間,對 expires 字典進行檢查,刪除裡面的過期鍵。

定時刪除

定時刪除策略對記憶體是最友好的: 因為它保證過期鍵會在第一時間被刪除, 過期鍵所消耗的記憶體會立即被釋放。

這種策略的缺點是, 它對 CPU 時間是最不友好的: 因為刪除操作可能會占用大量的 CPU 時間 —— 在記憶體不緊張、但是 CPU 時間非常緊張的時候 (比如說,進行交集計算或排序的時候), 將 CPU 時間花在刪除那些和當前任務無關的過期鍵上, 這種做法毫無疑問會是低效的。

除此之外, 目前 Redis 事件處理器對時間事件的實現方式 —— 無序鏈表, 查找一個時間複雜度為 O(N) —— 並不適合用來處理大量時間事件。

惰性刪除

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

惰性刪除的缺點是, 它對記憶體是最不友好的: 如果一個鍵已經過期, 而這個鍵又仍然保留在資料庫中, 那麼 dict 字典和 expires 字典都需要繼續保存這個鍵的信息, 只要這個過期鍵不被刪除, 它占用的記憶體就不會被釋放。

在使用惰性刪除策略時, 如果資料庫中有非常多的過期鍵, 但這些過期鍵又正好沒有被訪問的話, 那麼它們就永遠也不會被刪除(除非用戶手動執行), 這對於性能非常依賴於記憶體大小的 Redis 來說, 肯定不是一個好消息。

舉個例子, 對於一些按時間點來更新的數據, 比如日誌(log), 在某個時間點之後, 對它們的訪問就會大大減少, 如果大量的這些過期數據積壓在資料庫裡面, 用戶以為它們已經過期了(已經被刪除了), 但實際上這些鍵卻沒有真正的被刪除(記憶體也沒有被釋放), 那結果肯定是非常糟糕。

定期刪除

從上面對定時刪除和惰性刪除的討論來看, 這兩種刪除方式在單一使用時都有明顯的缺陷: 定時刪除占用太多 CPU 時間, 惰性刪除浪費太多記憶體。

定期刪除是這兩種策略的一種折中:

  • 它每隔一段時間執行一次刪除操作,並通過限制刪除操作執行的時長和頻率,籍此來減少刪除操作對 CPU 時間的影響。
  • 另一方面,通過定期刪除過期鍵,它有效地減少了因惰性刪除而帶來的記憶體浪費。

因此最終redis使用的過期鍵刪除策略是惰性刪除加上定期刪除, 這兩個策略相互配合,可以很好地在合理利用 CPU 時間和節約記憶體空間之間取得平衡。

因此redis大致流程如下:獲取key之前,會檢查key是否過期,如過期,直接刪除,返回null。

並且會定期的隨機的檢查大約25%的key是否過期,如果超過一定比例的key被過期。那麼繼續迴圈,直至低於這個數值。

這個定期的時間,以及數值都可以在conf文件裡面配置。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java的三魂七魄之一:多線程。本文章帶你瞭解多線程的多個知識點,包括多線程的創建、線程安全問題、線程通信問題... ...
  • 1、while迴圈 使用while列印1.2.3.4.5.6.8.9.10 #快速註釋Ctrl+?count = 1 while count <= 10: if count == 7: count = count + 1 pass #表示過,不執行下麵程式 else: print(count) co ...
  • 1.PHP語法基礎是否都會,比如異常捕捉,面向對象,數組操作語法,字元串操作,cookie,session,全局變數,超全局數組,防止sql註入,mysql預處理 2.MYSQL基礎語法,欄位設計,原生sql語句,如何優化查詢效率,索引如何使用,分組聚合,表關聯(一對多,多對多),分庫分表, 3.服 ...
  • 如何使用python將大量數據導出到Excel中的小技巧 (1) 問題描述:為了更好地展示數據,Excel格式的數據文件往往比文本文件更具有優勢,但是具體到python中,該如何導出數據到Excel呢?如果碰到需要導出大量數據又該如何操作呢?本文主要解決以上兩個問題。 PS註意:很多人學Python ...
  • 視頻地址:https://www.bilibili.com/video/av59676843/?p=631 課件、源碼及習題:鏈接:https://pan.baidu.com/s/1Jt59yZfuK-4j7sYZgzmUqA 提取碼:yz8l 習題答案:https://www.cnblogs.co ...
  • 1、Mac下安裝requests庫: pip3 install requests 2、requests庫的使用 2.1 發送請求 使用Requests發送網路請求第一步,導入requests模塊: import requests 嘗試獲取某個網頁。如百度首頁: r = requests.get('h ...
  • 1. 起因 ​ 使用springboot也有些時間,一直很好奇它如何做到自動配置的,所以查閱了相關資料並且學習了相關內容,才寫了這篇文章。 2. 分析 ​ ①第一步我們從它的啟動配置類(XxxApplication)收起,我們進入到他的@SpringBootApplication註解。 ​ ②我們可 ...
  • 曾有邪教稱1999年12月31日是世界末日,當然該謠言已經不攻自破。 還有人稱今後的某個世紀末的12月31日,如果是星期一則會..…. 有趣的是,任何一個世紀末的年份的12月31日都不可能是星期一!!! 於是,“謠言製造商”又修改為星期日...... 1999年的12月31日是星期五,請問:未來哪一 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...