Redis過期--淘汰機制的解析和記憶體占用過高的解決方案

来源:https://www.cnblogs.com/xlecho/archive/2019/11/10/11832128.html
-Advertisement-
Play Games

echo編輯整理,歡迎轉載,轉載請聲明文章來源。歡迎添加echo微信(微信號:t2421499075)交流學習。 百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!!! Redis在我們平時的開發或者練習的時候,往往很容易忽略一個問題,那就是我們的Redis記憶體占滿的問題。但 ...


echo編輯整理,歡迎轉載,轉載請聲明文章來源。歡迎添加echo微信(微信號:t2421499075)交流學習。 百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!!!


Redis在我們平時的開發或者練習的時候,往往很容易忽略一個問題,那就是我們的Redis記憶體占滿的問題。但是在真是的商業開發中,Redis的實際占滿是真正會存在這樣的問題的。那麼如果Redis在某一刻占滿記憶體,我們又沒有對它進行相應的設置它會出現什麼情況呢?會不會導致我們整個因為使用Redis而整個業務垮掉?這就是我們本篇文章所要講述的問題。

什麼是Redis淘汰機制

Redis記憶體淘汰機制其實簡單講就是將過期的數據或者很久沒有訪問,或者在一段時間內很少有訪問的數據進行刪除。它分為很多中,有主動的數據淘汰,如:用戶設定過期時間。有被動的淘汰,比如:Redis數據占滿了記憶體,這個時候就會將過期的數據或者很久沒有訪問的數據刪除掉。

Redis的淘汰有哪些類型

  • 定時過期:每個設置過期時間的key都需要創建一個定時器,到過期時間就會立即清除。該策略可以立即清除過期的數據,對記憶體很友好;但是會占用大量的CPU資源去處理過期的數據,從而影響緩存的響應時間和吞吐量。
  • 惰性過期:只有當訪問一個key時,才會判斷該key是否已過期,過期則清除。該策略可以最大化地節省CPU資源,卻對記憶體非常不友好。極端情況可能出現大量的過期key沒有再次被訪問,從而不會被清除,占用大量記憶體。
  • 定期過期:每隔一定的時間,會掃描一定數量的資料庫的expires字典中一定數量的key,並清除其中已過期的key。該策略是前兩者的一個折中方案。通過調整定時掃描的時間間隔和每次掃描的限定耗時,可以在不同情況下使得CPU和記憶體資源達到最優的平衡效果。
    (expires字典會保存所有設置了過期時間的key的過期時間數據,其中,key是指向鍵空間中的某個鍵的指針,value是該鍵的毫秒精度的UNIX時間戳表示的過期時間。鍵空間是指該Redis集群中保存的所有鍵。)

定時過期的問題:緩存雪崩

很多人可能對這個詞很熟悉,因為有很多的商業案例展示了血淋淋的教訓,但是也有一部分人估計沒有接觸過。緩存雪崩其實也不是什麼新詞,它主要的引起原因就是指緩存中數據大批量的到過期時間。定時過期它本身就有一個缺點,那就是會占用大量的CPU資源,如果我們主動設置過期時間的鍵過多,在同一時間過期,很有可能就會造就我們Redis掛掉。但是這並不是最可怕的,雪崩不僅僅影響自己,還在我們的業務中影響資料庫。因為我們很多業務設計都是在我們Redis的數據過期之後,從新查詢資料庫,但我們Redis主動批量過期的時候,會有大量的請求發送到我們的資料庫,很有可能導致我們的資料庫也掛掉。這才是最大的問題所在。

解決方案:

  • 緩存數據的過期時間設置隨機,防止同一時間大量數據過期現象發生。
  • 如果緩存資料庫是分散式部署,將熱點數據均勻分佈在不同搞得緩存資料庫中。
  • 設置熱點數據永遠不過期。

從幾種淘汰策略中其實我們可以看到基本的一些問題所在,所以我們在使用緩存的時候最好有一個全面的瞭解和全面的考慮應對。在實際開發中,我們更應該多去關註的和瞭解的是定期過期,因為它涉及真實開發中的一些問題。所以我們應該提前設置好。

怎麼設置定期過期最大使用記憶體

定期過期的最大記憶體設置在我們的redis.conf文件中,我們可以在該文件中看到這個配置:maxmemory <bytes>,但是這個配置一般都是註釋掉的,也就是說安裝之後如果我們沒有主動對他進行配置,那麼他就不會有預設大小值。對應的它不設置的情況下,那麼它可以使用多少的記憶體空間呢?這個跟系統有關。如果說我們將Redis安裝在32位的系統上,它的最大使用記憶體空間應該是在3G左右,如果是64位的系統,那麼可以將我們的記憶體占滿。當然如果真正占滿記憶體,這是一件比較惡劣的事情,不僅僅訪問Redis的時候,我們不能在進行寫的操作,而且我們系統本身的其他操作也會受到限制。所以我們可以採用命令來對它進行一個初始化的設置

config set maxmemory 268435456

使用命令進行設置之後我們需要重啟Redis才能生效。當然我們也可以直接找到Redis的安裝目錄,然後使用vi命令,直接更改配置文件中的對應的該內容,更改完之後,重啟即可。

定期過期的淘汰策略

  • volatile-lru:根據LRU演算法生成的過期時間來刪除。
  • allkeys-lru:根據LRU演算法刪除任何key。
  • volatile-lfu:從所有配置了過期時間的鍵中驅逐使用頻率最少的鍵
  • allkeys-lfu:從所有鍵中驅逐使用頻率最少的鍵
  • volatile-random:根據過期設置來隨機刪除key。
  • allkeys-random:無差別隨機刪。
  • volatile-ttl:根據最近過期時間來刪除(輔以TTL)
  • noeviction:誰也不刪,直接在寫操作時返回錯誤。

隨機淘汰策略

隨機找hash桶再次hash指定位置的dictEntry即可。就是在場景REDIS_MAXMEMORY_VOLATILE_RANDOM和REDIS_MAXMEMORY_ALLKEYS_LRU情況下的待淘汰的key。我們可以一觀它的源碼:

dictEntry *dictGetRandomKey(dict *d)
{
    dictEntry *he, *orighe;
    unsigned int h;
    int listlen, listele;
 
    if (dictSize(d) == 0) return NULL;
 
    if (dictIsRehashing(d)) _dictRehashStep(d);
 
    if (dictIsRehashing(d)) {
        // T = O(N)
        do {
            h = random() % (d->ht[0].size+d->ht[1].size);
            he = (h >= d->ht[0].size) ? d->ht[1].table[h - d->ht[0].size] :
                                      d->ht[0].table[h];
        } while(he == NULL);
    } else {
        // T = O(N)
        do {
            h = random() & d->ht[0].sizemask;
            he = d->ht[0].table[h];
        } while(he == NULL);
    }
 
    /* Now we found a non empty bucket, but it is a linked
     * list and we need to get a random element from the list.
     * The only sane way to do so is counting the elements and
     * select a random index. */
    listlen = 0;
    orighe = he;
    while(he) {
        he = he->next;
        listlen++;
    }
    listele = random() % listlen;
    he = orighe;
    // T = O(1)
    while(listele--) he = he->next;
 
    return he;
}

TTL時間淘汰

for (k = 0; k < server.maxmemory_samples; k++) {
    sds thiskey;
    long thisval;

    de = dictGetRandomKey(dict);
    thiskey = dictGetKey(de);
    thisval = (long) dictGetVal(de);

    /* Expire sooner (minor expire unix timestamp) is better
     * candidate for deletion */
    if (bestkey == NULL || thisval < bestval) {
        bestkey = thiskey;
        bestval = thisval;
    }
}

更多源碼,請參考redis官網。這裡只是簡單的展示兩種。我們可以根據這樣的代碼來對我們的redis的定期過期做一個合理的配置

思考:

基於一個數據結構做緩存,怎麼實現一個LRU演算法?

做一個有底線的博客主


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

-Advertisement-
Play Games
更多相關文章
  • 23種GoF設計模式概述 在前面,我們對 GoF 的 23 種設計模式進行了分類,這裡先對各個設計模式的功能進行簡要介紹,以便有個大概瞭解。後面的章節再進行詳細介紹。 創建型模式 關註於怎麼創建對象的創建型模式,他們將對象的創建與使用相互分離,對象的使用者無需關心如何創建對象,只知道怎麼使用就行,以 ...
  • 1 基礎概念 1.1. 什麼是事務 什麼是事務?舉個生活的例子 :你去小賣部買東西,“一手交錢,一手交貨“就是一個事務的例子,交錢和交貨必須全部成功,事務才算成功,任一個活動失敗,事務將撤銷所有已成功的活動。明白上述例子,再來看事務的定義 :事務可以看做是一次大的活動,它由不同的小活動組成,這些活動 ...
  • 本段源碼可以學習的地方: 1. 考慮到效率問題,可以通過上下文的機制,在屬性被訪問的時候臨時構建; 2. 可以重寫一些魔術方法,比如 __new__ 方法,在調用 object.__new__(cls) 前後進行屬性的一些小設置; 3. 在本庫中使用的重寫魔術方法,上下文這兩種基礎之上,我們可以想... ...
  • '''''' ''' 1 python的定義 是一門弱類型的解釋性的高級編程語言 這裡的高級是相對低級(例如:彙編語言等) 高級編程語言和低級編程語言的區別 1、前者更接近於人的理解--字母組成的語法 2、後者更接近於計算器的理解--位元組碼、二進位 2 python的特點 人生苦短,我用python... ...
  • (手機橫屏看源碼更方便) 簡介 線程系列我們基本就學完了,這一個系列我們基本都是圍繞著線程池在講,其實關於線程還有很多東西可以講,後面有機會我們再補充進來。當然,如果你有什麼好的想法,也可以公從號右下角聯繫我。 重要知識點 直接上圖,看著這張圖我相信你能夠回憶起很多東西,也可以看著這張圖來自己提問自 ...
  • 一、常量 1.常量的定義:final修飾的實例變數是不可變的,這種變數一般和static聯合使用,被稱為“常量” 2.常量的語法格式: public static final 類型 常量名 = 值; java規範中要求所有常量的名字全部大寫,每個單詞之間使用下劃線連接 package com.bjp ...
  • 新聞 "邀請博客主們:2019年的F Advent日曆" "宣告ML.NET 1.4" ".NET Core與Jupyter筆記本" "在Jupyter筆記本中使用ML.NET" "用於Windows桌面的.NET Core 3" "宣告.NET Core 3.1預覽版2" "在.NET Core ...
  • PSR是PHP Standards Recommendation的簡稱,意為PHP推薦標準。要想瞭解PSR,首先得知道制定這一標準的人/組織是誰————PHP-FIG。 PHP-FIG PHP-FIG全稱為PHP Framework Interop Group,是一個組織,這個組織的成員由一些PHP ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...