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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...