Redis鍵過期-內存淘汰-持久化原理

1. Redis數據過期策略

轉自:https://www.cnblogs.com/xuliangxing/p/7151812.html

1.1 設置過期時間

Redis對存儲值的過期處理實際上是針對該值的鍵(key)處理的,即時間的設置也是設置key的有效時間。Expires字典保存了所有鍵的過期時間,Expires也被稱爲過期字段。

expire key time(以秒爲單位)–這是最常用的方式
setex(String key, int seconds, String value)–字符串獨有的方式
注:
  1、除了字符串自己獨有設置過期時間的方法外,其他方法都需要依靠expire方法來設置時間。
  2、如果沒有設置時間,那緩存就是永不過期。
  3、如果設置了過期時間,之後又想讓緩存永不過期,使用persist <key>

1.1.1 常用方式

一般主要包括4種處理過期方,其中expire都是以秒爲單位,pexpire都是以毫秒爲單位的。

1 EXPIRE key seconds  //將key的生存時間設置爲ttl秒
2 PEXPIRE key milliseconds  //將key的生成時間設置爲ttl毫秒
3 EXPIREAT key timestamp  //將key的過期時間設置爲timestamp所代表的的秒數的時間戳
4 PEXPIREAT key milliseconds-timestamp  //將key的過期時間設置爲timestamp所代表的的毫秒數的時間戳

1.1.2 字符串獨有方式

對字符串特殊處理的方式爲SETEX命令,SETEX命令爲指定的 key 設置值及其過期時間。如果 key 已經存在, SETEX 命令將會替換舊的值。

返回值

設置成功時返回 OK 。

語法

Redis Setex 命令基本語法如下:

SETEX KEY_NAME TIMEOUT VALUE

示例

redis 127.0.0.1:6379> SETEX mykey 60 redis
OK
redis 127.0.0.1:6379> TTL mykey
60
redis 127.0.0.1:6379> GET mykey

1.2 三種過期策略

1.2.1 定時刪除

含義:在設置key的過期時間的同時,爲該key創建一個定時器,讓定時器在key的過期時間來臨時對key進行刪除

優點:保證內存被儘快釋放

缺點:

  • 若過期key很多,刪除這些key會佔用很多的CPU時間,在CPU時間緊張的情況下,CPU不能把所有的時間用來做要緊的事兒,還需要去花時間刪除這些key。
  • 定時器的創建耗時,若爲每一個設置過期時間的key創建一個定時器(將會有大量的定時器產生),性能影響嚴重
  • 沒人用。

1.2.2 惰性刪除

含義:key過期的時候不刪除,每次從數據庫獲取key的時候去檢查是否過期,若過期,則刪除,返回null。

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

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


1.2.3 定期刪除

含義:每隔一段時間執行一次刪除(在redis.conf配置文件設置hz,1s刷新的頻率)過期key操作

優點:

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

缺點:

  • 在內存友好方面,不如”定時刪除”
  • 在CPU時間友好方面,不如”惰性刪除”

1.2.4 Redis使用的過期策略

看完上面三種策略後可以得出以下結論:
定時刪除和定期刪除爲主動刪除:Redis會定期主動淘汰一批已過去的key。

惰性刪除爲被動刪除:用到的時候纔會去檢驗key是不是已過期,過期就刪除。

(1)惰性刪除爲redis服務器內置策略。

(2)配置redis.confhz選項,默認爲10 (即1秒執行10次,100ms一次,值越大說明刷新頻率越快,最Redis性能損耗也越大)。

(3)配置redis.confmaxmemory最大值,當已用內存超過maxmemory限定時,就會觸發主動清理策略。


1.3 AOF對過期key的處理

(1)當key過期後,還沒有被刪除,此時進行執行持久化操作(該key是不會進入aof文件的,因爲沒有發生修改命令)。

(2)當key過期後,在發生刪除操作時,程序會向aof文件追加一條del命令(在將來的以aof文件恢復數據的時候該過期的鍵就會被刪掉)。

(3)AOF重寫:重寫時,會先判斷key是否過期,已過期的key不會重寫到aof文件 。


1.4 RDB對過期key的處理

  • 從內存數據庫持久化數據到RDB文件
    • 持久化key之前,會檢查是否過期,過期的key不進入RDB文件
  • 從RDB文件恢復數據到內存數據庫
    • 數據載入數據庫之前,會對key先進行過期檢查,如果過期,不導入數據庫(主庫情況)

2. Redis的內存淘汰策略

Redis的內存淘汰策略是指在Redis的用於緩存的內存不足時,怎麼處理需要新寫入且需要申請額外空間的數據。

  • noeviction:當內存不足以容納新寫入數據時,新寫入操作會報錯。
  • allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。
  • allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。
  • volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key。
  • volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。
  • volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。

3. Redis 持久化

Redis 提供了多種不同級別的持久化方式:

  • RDB 持久化可以在指定的時間間隔內生成數據集的時間點快照(point-in-time snapshot)。
  • AOF 持久化記錄服務器執行的所有寫操作命令,並在服務器啓動時,通過重新執行這些命令來還原數據集。 AOF 文件中的命令全部以 Redis 協議的格式來保存,新命令會被追加到文件的末尾。 Redis 還可以在後臺對 AOF 文件進行重寫(rewrite),使得 AOF 文件的體積不會超出保存數據集狀態所需的實際大小。
  • Redis 還可以同時使用 AOF 持久化和 RDB 持久化。 在這種情況下, 當 Redis 重啓時, 它會優先使用 AOF 文件來還原數據集, 因爲 AOF 文件保存的數據集通常比 RDB 文件所保存的數據集更完整。
  • 你甚至可以關閉持久化功能,讓數據只在服務器運行時存在。

瞭解 RDB 持久化和 AOF 持久化之間的異同是非常重要的, 以下幾個小節將詳細地介紹這這兩種持久化功能, 並對它們的相同和不同之處進行說明。


3.1 RDB

3.1.1 優點

  • RDB 是一個非常緊湊(compact)的文件,它保存了 Redis 在某個時間點上的數據集。 這種文件非常適合用於進行備份: 比如說,你可以在最近的 24 小時內,每小時備份一次 RDB 文件,並且在每個月的每一天,也備份一個 RDB 文件。 這樣的話,即使遇上問題,也可以隨時將數據集還原到不同的版本。
  • RDB 非常適用於災難恢復(disaster recovery):它只有一個文件,並且內容都非常緊湊,可以(在加密後)將它傳送到別的數據中心,或者亞馬遜 S3 中。
  • RDB 可以最大化 Redis 的性能:父進程在保存 RDB 文件時唯一要做的就是 fork 出一個子進程,然後這個子進程就會處理接下來的所有保存工作,父進程無須執行任何磁盤 I/O 操作
  • RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。

3.1.2 缺點

  • 如果你需要儘量避免在服務器故障時丟失數據,那麼 RDB 不適合你。 雖然 Redis 允許你設置不同的保存點(save point)來控制保存 RDB 文件的頻率, 但是, 因爲RDB 文件需要保存整個數據集的狀態, 所以它並不是一個輕鬆的操作。 因此你可能會至少 5 分鐘才保存一次 RDB 文件。 在這種情況下, 一旦發生故障停機, 你就可能會丟失好幾分鐘的數據。
  • 每次保存 RDB 的時候,Redis 都要 fork() 出一個子進程,並由子進程來進行實際的持久化工作。 在數據集比較龐大時, fork() 可能會非常耗時,造成服務器在某某毫秒內停止處理客戶端; 如果數據集非常巨大,並且 CPU 時間非常緊張的話,那麼這種停止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也需要進行 fork() ,但無論 AOF 重寫的執行間隔有多長,數據的耐久性都不會有任何損失。

3.2 AOF

3.2.1 優點

  • 使用 AOF 持久化會讓 Redis 變得非常耐久(much more durable):你可以設置不同的 fsync 策略,比如無 fsync ,每秒鐘一次 fsync ,或者每次執行寫入命令時 fsyncAOF 的默認策略爲每秒鐘 fsync 一次,在這種配置下,Redis 仍然可以保持良好的性能,並且就算髮生故障停機,也最多隻會丟失一秒鐘的數據fsync 會在後臺線程執行,所以主線程可以繼續努力地處理命令請求)。
  • AOF 文件是一個只進行追加操作的日誌文件(append only log), 因此對 AOF 文件的寫入不需要進行 seek , 即使日誌因爲某些原因而包含了未寫入完整的命令(比如寫入時磁盤已滿,寫入中途停機,等等), redis-check-aof 工具也可以輕易地修復這種問題。
  • Redis 可以在 AOF 文件體積變得過大時,自動地在後臺對 AOF 進行重寫: 重寫後的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。 整個重寫操作是絕對安全的,因爲 Redis 在創建新 AOF 文件的過程中,會繼續將命令追加到現有的 AOF 文件裏面,即使重寫過程中發生停機,現有的 AOF 文件也不會丟失。 而一旦新 AOF 文件創建完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,並開始對新 AOF 文件進行追加操作。
  • AOF 文件有序地保存了對數據庫執行的所有寫入操作, 這些寫入操作以 Redis 協議的格式保存, 因此 AOF 文件的內容非常容易被人讀懂, 對文件進行分析(parse)也很輕鬆。 導出(export) AOF 文件也非常簡單: 舉個例子, 如果你不小心執行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那麼只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 並重啓 Redis , 就可以將數據集恢復到 FLUSHALL 執行之前的狀態。

3.3 AOF重寫

http://blog.csdn.net/hezhiqiang1314/article/details/69396887

爲了解決AOF文件體積膨脹的問題,Redis提供了AOF重寫功能:Redis服務器可以創建一個新的AOF文件來替代現有的AOF文件,新舊兩個文件所保存的數據庫狀態是相同的,但是新的AOF文件不會包含任何浪費空間的冗餘命令,通常體積會較舊AOF文件小很多。實現原理:

首先從數據庫中讀取鍵現在的值,然後用一條命令去記錄鍵值對,代替之前記錄該鍵值對的多個命令。

Redis不希望AOF重寫會造成服務器無法處理請求,所以Redis決定將AOF重寫程序放到子進程(後臺)裏執行。這樣處理的最大好處是:

  • 子進程進行AOF重寫期間,主進程可以繼續處理命令請求;
  • 子進程帶有主進程的數據副本,使用子進程而不是線程,可以避免在鎖的情況下,保證數據的安全性。

3.3.1 AOF重寫緩存

子進程在進行AOF重寫期間,服務器進程還要繼續處理命令請求,而新的命令可能對現有的數據進行修改,這會讓當前數據庫的數據和重寫後的AOF文件中的數據不一致。爲了解決這種數據不一致的問題,Redis增加了一個AOF重寫緩存,這個緩存在fork出子進程之後開始啓用,Redis服務器主進程在執行完寫命令之後,會同時將這個寫命令追加到AOF緩衝區和AOF重寫緩衝區。即子進程在執行AOF重寫時,主進程需要執行以下三個工作:

  • 執行client發來的命令請求;
  • 將寫命令追加到現有的AOF文件中;
  • 將寫命令追加到AOF重寫緩存中。

這裏寫圖片描述


3.3.2 完成AOF重寫之後

當子進程完成對AOF文件重寫之後,它會向父進程發送一個完成信號,父進程接到該完成信號之後,會調用一個信號處理函數(此時主線程被阻塞),該函數完成以下工作:
- 將AOF重寫緩存中的內容全部寫入到新的AOF文件中;這個時候新的AOF文件所保存的數據庫狀態和服務器當前的數據庫狀態一致;
- 對新的AOF文件進行改名,原子地覆蓋原有的AOF文件;完成新舊兩個AOF文件的替換。

當這個信號處理函數執行完畢之後,主進程就可以繼續像往常一樣接收命令請求了。在整個AOF後臺重寫過程中,只有最後的“主進程寫入命令到AOF緩存”和“對新的AOF文件進行改名,覆蓋原有的AOF文件。”這兩個步驟(信號處理函數執行期間)會造成主進程阻塞,在其他時候,AOF後臺重寫都不會對主進程造成阻塞,這將AOF重寫對性能造成的影響降到最低。

以上,即AOF後臺重寫,也就是BGREWRITEAOF命令的工作原理。


3.3.3 觸發AOF後臺重寫的條件

  • AOF重寫可以由用戶通過調用BGREWRITEAOF手動觸發。
  • 服務器在AOF功能開啓的情況下,會維持以下三個變量:
    • 記錄當前AOF文件大小的變量aof_current_size
    • 記錄最後一次AOF重寫之後,AOF文件大小的變量aof_rewrite_base_size
    • 增長百分比變量aof_rewrite_perc
  • 每次當serverCron(服務器週期性操作函數)函數執行時,它會檢查以下條件是否全部滿足,如果全部滿足的話,就觸發自動的AOF重寫操作:
    • 沒有BGSAVE命令(RDB持久化)/AOF持久化在執行;
    • 沒有BGREWRITEAOF在進行;
    • 當前AOF文件大小要大於server.aof_rewrite_min_size(默認爲1MB),或者在redis.conf配置了auto-aof-rewrite-min-size大小;
    • 當前AOF文件大小和最後一次重寫後的大小之間的比率等於或者等於指定的增長百分比(在配置文件設置了auto-aof-rewrite-percentage參數,不設置默認爲100%)

如果前面三個條件都滿足,並且當前AOF文件大小比最後一次AOF重寫時的大小要大於指定的百分比,那麼觸發自動AOF重寫。


發佈了94 篇原創文章 · 獲贊 43 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章