Redis(二十):Redis資料過期和淘汰策略詳解(轉)

weixin_34292959發表於2018-10-31

原文地址:https://yq.aliyun.com/articles/257459#

背景

Redis作為一個高效能的記憶體NoSQL資料庫,其容量受到最大記憶體限制的限制。

使用者在使用Redis時,除了對效能,穩定性有很高的要求外,對記憶體佔用也比較敏感。在使用過程中,有些使用者會覺得自己的線上例項記憶體佔用比自己預想的要大。

事實上,例項中的記憶體除了儲存原始的鍵值對所需的開銷外,還有一些執行時產生的額外記憶體,包括:

  1. 垃圾資料和過期Key所佔空間
  2. 字典漸進式Rehash導致未及時刪除的空間
  3. Redis管理資料,包括底層資料結構開銷,客戶端資訊,讀寫緩衝區等
  4. 主從複製,bgsave時的額外開銷
  5. 其它

本文主要分析第一項Redis過期策略對記憶體的影響

設定過期時間

  • expire key time(以秒為單位)--這是最常用的方式
  • setex(String key, int seconds, String value)–字串獨有的方式

注意:

  • 除了字串自己獨有設定過期時間的方法外,其他方法都需要依靠expire方法來設定時間
  • 如果沒有設定時間,那快取就是永不過期
  • 如果設定了過期時間,之後又想讓快取永不過期,使用persist key

Redis三種Key過期策略

    1、被動刪除(惰性刪除)

  當讀/寫一個已經過期的key時,會觸發惰性刪除策略,直接刪除掉這個過期key。

  只有key被操作時(如GET),REDIS才會被動檢查該key是否過期,如果過期則刪除之並且返回NIL。

    a.這種刪除策略對CPU是友好的,刪除操作只有在不得不的情況下才會進行,不會其他的expire key上浪費無謂的CPU時間。

    b.但是這種策略對記憶體不友好,一個key已經過期,但是在它被操作之前不會被刪除,仍然佔據記憶體空間。如果有大量的過期鍵存在但是又很少被訪問到,那會造成大量的記憶體空間浪費。expireIfNeeded(redisDb *db, robj *key)函式位於src/db.c。

  但僅是這樣是不夠的,因為可能存在一些key永遠不會被再次訪問到,這些設定了過期時間的key也是需要在過期後被刪除的,我們甚至可以將這種情況看作是一種記憶體洩露----無用的垃圾資料佔用了大量的記憶體,而伺服器卻不會自己去釋放它們,這對於執行狀態非常依賴於記憶體的Redis伺服器來說,肯定不是一個好訊息

  優點:刪除操作只發生在從資料庫取出key的時候發生,而且只刪除當前key,所以對CPU時間的佔用是比較少的,而且此時的刪除是已經到了非做不可的地步(如果此時還不刪除的話,我們就會獲取到了已經過期的key了)

  缺點:若大量的key在超出超時時間後,很久一段時間內,都沒有被獲取過,那麼可能發生記憶體洩露(無用的垃圾佔用了大量的記憶體)

    2、主動刪除

  由於惰性刪除策略無法保證冷資料被及時刪掉,所以Redis會定期主動淘汰一批已過期的key。

  先說一下時間事件,對於持續執行的伺服器來說, 伺服器需要定期對自身的資源和狀態進行必要的檢查和整理, 從而讓伺服器維持在一個健康穩定的狀態, 這類操作被統稱為常規操作(cron job)。在 Redis 中, 常規操作由 redis.c/serverCron 實現。

  優點:通過限制刪除操作的時長和頻率,來減少刪除操作對CPU時間的佔用–處理"定時刪除"的缺點,定期刪除過期key–處理"惰性刪除"的缺點。

  缺點:在記憶體友好方面,不如"定時刪除",在CPU時間友好方面,不如"惰性刪除"。

  難點:合理設定刪除操作的執行時長(每次刪除執行多長時間)和執行頻率(每隔多長時間做一次刪除)(這個要根據伺服器執行情況來定了)

    3、maxmemory

當前已用記憶體超過maxmemory限定時,觸發主動清理策略。

  • volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用 的資料淘汰
  • volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選將要過期的數 據淘汰
  • volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料 淘汰
  • allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰
  • allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
  • no-enviction(驅逐):(預設)禁止驅逐資料

相關最佳實踐優化配置

    • 不要放垃圾資料,及時清理無用資料
      實驗性的資料和下線的業務資料及時刪除;
    • key儘量都設定過期時間
      對具有時效性的key設定過期時間,通過redis自身的過期key清理策略來降低過期key對於記憶體的佔用,同時也能夠減少業務的麻煩,不需要定期手動清理了.
    • 單Key不要過大
      給使用者排查問題時遇到過單個string的value有43M的,也有一個list 100多萬個大成員佔了1G多記憶體的。這種key在get的時候網路傳輸延遲會比較大,需要分配的輸出緩衝區也比較大,在定期清理的時候也容易造成比較高的延遲. 最好能通過業務拆分,資料壓縮等方式避免這種過大的key的產生。
    • 不同業務如果公用一個業務的話,最好使用不同的邏輯db分開
      從上面的分析可以看出,Redis的過期Key清理策略和強制淘汰策略都會遍歷各個db。將key分佈在不同的db有助於過期Key的及時清理。另外不同業務使用不同db也有助於問題排查和無用資料的及時下線.

相關文章