Redis 的持久化與過時鍵

簡介

Redis 是使用很是普遍的 Key-Value 內存數據庫。由於數據都存放在內存中,因此存取速度很是快。不過,不少狀況下咱們須要將 Redis 中的數據保存到硬盤中以便作備份。Redis 提供了兩種數據持久化方式,分別是 RDB 和 AOP,本文分析這兩種方式的使用以及過時鍵對持久化的影響。數據庫

RDB

RDB 指的是將 Redis 數據庫在某個時間點的快照保存到磁盤,所生成的 RDB 文件是一個通過壓縮的二進制文件,經過這個文件能夠還原出 Redis 的數據狀態。安全

建立快照的方式有如下幾種:服務器

  • 客戶端向 Redis 發送 BGSAVE 命令,Redis 會調用 fork 建立一個子進程,而後子進程負責將快照寫入硬盤,而父進程繼續處理命令請求。
  • 客戶端向 Redis 發送 SAVE 命令,此時 Redis 將開始建立快照,而且在完成以前再也不響應其它命令。
  • 用戶設置 save 配置選項,好比 save 60 10000,那麼從 Redis 最近一次建立快照算起,當 「60 秒內有 10000 次寫入」 這個條件被知足時, Redis 就會自動觸發 BGSAVE 命令。若是用戶設置了多個 save 配置選項,那麼當任意一個 save 配置知足時,Redis 就會觸發一次 BGSAVE 命令。save 配置的格式以下所示:
save 60 10000
stop-writes-on-bgsave-error no
rdbcompression yes    // 使用壓縮
dbfilename dump.rdb  // RBD 文件的名字

dir ./
  • 當 Redis 經過 SHUTDOWN 命令接收到關閉服務器的請求時,或者接收到 TERM命令時,會執行一個 SAVE 命令,而且阻塞全部的客戶端,再也不執行任何請求。在 SAVE 命令執行結束後關閉服務器。
  • 當一個 Redis 服務器鏈接另外一個 Redis 服務器,並向對方發送 SYNC 命令來開始一次複製操做的時候,若是主服務器沒有在執行 BGSAVE 操做,或者主服務器並不是剛執行完 BGSAVE,那麼主服務器會執行 BGSAVE 命令。

RDB 的主要問題是,若是系統發生崩潰,那麼最近一次執行完快照後修改的數據將被丟失。所以,RDB 適合用於即便丟失一部分數據也不會形成影響的應用程序。app

AOF

AOF 指的是將全部執行的寫命令寫到 AOF 文件的末尾,以此來記錄數據發生的變化。若是 Redis 想要恢復 AOF 中的數據,只要從新執行一次 AOF 文件中所包含的寫命令就能夠。性能

AOF 的配置以下所示:學習

appendonly yes  // 打開 aof
appendfsync everysec // aof 同步的頻率
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100 // 文件大小增加比超過這個值開始自動重寫 aof
auto-aof-rewrite-min-size 64mb  // 文件大小超過這個值才能夠有可能自動重寫 aof

上面的配置中,appendfsync everysec 設置的是同步的頻率。應用程序在向硬盤寫入數據的時候有 3 個步驟:操作系統

  1. 調用 file.write() 向文件寫入,此時須要寫入的內容被存儲到了緩衝區,並非真正寫到硬盤上了。
  2. 操做系統在某個時候將緩衝區的內容寫入硬盤,這時數據才真正被持久化了。

操做系統使用以上的文件寫入方式是爲了提升性能,畢竟硬盤 I/O 操做是比較耗時的。可是,這種方式的缺點在於若是機器崩潰了那麼緩衝區的內容將丟失。程序可使用 file.flush() 來請求操做系統儘快地將緩衝區的內容刷新到硬盤上,不過什麼時候開始執行仍然由操做系統決定。程序也能夠命令操做系統將文件同步 ( sync ) 到硬盤,同步操做會阻塞應用程序直到數據被寫入硬盤。當同步操做完成後,即便系統出現故障,也不會對被同步的文件形成影響。設計

對於 Redis 來說,能夠指定 appendfsync 以何種方式讓數據徹底同步到硬盤,這個配置有 3 個選項:code

  1. always: 每一個 Redis 寫命令都當即同步到硬盤,這是比較消耗性能的
  2. everysec: 每秒執行一次同步,兼顧性能與數據安全,是比較經常使用的選項
  3. no: 讓操做系統決定什麼時候進行同步

always 可使得在 Redis 發生崩潰時丟失的數據最少,可是也是最消耗性能的,致使 Redis 的處理速度變慢。ererysec 是一種兼顧性能與數據安全的方式,在這種狀況下,若是系統崩潰,用戶最多會丟失一秒內的數據。no 選項徹底將同步交給操做系統被決定,性能也不比 everysec 高多少,是不推薦的方式。進程

AOF 的缺點是隨着 Redis 的不斷運行,AOF 文件可能會很是大,甚至用完硬盤的空間。解決這個問題的辦法是 AOF 重寫。

重寫

客戶端能夠發送 BGREWRITEAOF 命令讓 Redis 重寫 AOF 文件,Redis 會移除冗餘的 AOF 命令進行重寫,使得 AOF 文件的體積儘量地小。

除了客戶端主動發送 BGREWRITEAOF 命令,也可使用配置讓 Redis 在知足必定條件地狀況下自動開始重寫 AOF 文件。例如上一小節設置了 auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb。這兩個配置的含義是,若是 AOF 文件大於 64MB 而且比上一次重寫以後的大小增長了一倍的時候,Redis 將執行 BGREWERITEAOF 命令。

過時鍵刪除

用戶每每爲 Redis 中的鍵設定過時時間,所以須要必定的策略來刪除過時鍵,能夠有三種策略:

  1. 定時刪除,即經過定時器在過時時間到達的時候刪除過時的鍵。這種方式的優勢是節省內存,不會由於大量的過時鍵佔用內存資源,而缺點則是消耗 CPU 資源,尤爲是過時鍵數量較多的時候,刪除操做消耗太長時間,下降了 Redis 的響應時間。
  2. 惰性刪除,即在每次獲取某個鍵的時候判斷是否過時,若是未過時,則正常返回其值,不然刪除這個鍵,返回空。這種方式的優勢是節省 CPU 資源,可是消耗了內存。尤爲是過時鍵數量較多的時候,大量內存被無效的鍵佔用,至關於內存泄露。
  3. 按期刪除,即每隔一段時間週期對數據庫中的鍵進行掃描,可是隻掃描其中一部分,力求在內存和 CPU 之間達到一個平衡。

從上面 3 種策略能夠看出,單用第一個確定是不行的,Redis 的響應時間相當重要。第二個則是比較好的方式,在獲取鍵的時候判斷是否過時並決定是否刪除,它的缺點是不少鍵沒法及時刪除。若是一個過時鍵再也沒有被訪問,那麼它將永遠留在內存中,而第三種方式正好能夠彌補。

Redis 中過時鍵的刪除策略正是惰性刪除與按期刪除的結合。

過時鍵與持久化

瞭解了過時鍵的刪除策略後,下面看下鍵的過時時間對持久化的影響。

在生成 RDB 文件的過程當中,若是一個鍵已通過期,那麼其不會被保存到 RDB 文件中。在載入 RDB 的時候,要分兩種狀況:

  1. 若是 Redis 以主服務器的模式運行,那麼會對 RDB 中的鍵進行時間檢查,過時的鍵不會被恢復到 Redis 中。
  2. 若是 Redis 以從服務器的模式運行,那麼 RDB 中全部的鍵都會被載入,忽略時間檢查。在從服務器與主服務器進行數據同步的時候,從服務器的數據會先被清空,因此載入過時鍵不會有問題。

對於 AOF 來講,若是一個鍵過時了,那麼不會馬上對 AOF 文件形成影響。由於 Redis 使用的是惰性刪除和按期刪除,只有這個鍵被刪除了,纔會往 AOF 文件中追加一條 DEL 命令。在重寫 AOF 的過程當中,程序會檢查數據庫中的鍵,已通過期的鍵不會被保存到 AOF 文件中。

在運行過程當中,對於主從複製的 Redis,主服務器和從服務器對於過時鍵的處理也不相同:

  1. 對於主服務器,一個過時的鍵被刪除了後,會向從服務器發送 DEL 命令,通知從服務器刪除對應的鍵
  2. 從服務器接收到讀取一個鍵的命令時,即便這個鍵已通過期,也不會刪除,而是照常處理這個命令。
  3. 從服務器接收到主服務器的 DEL 命令後,纔會刪除對應的過時鍵。

這麼作的主要目的是保證數據一致性,因此當一個過時鍵存在於主服務器時,也必然存在於從服務器。

總結

本文對 Redis 的兩種持久化方式進行了簡要的梳理,分析了 Redis 刪除過時鍵的策略以及對持久化的影響。理解了這部份內容不只可讓咱們對 Redis 的使用更加駕輕就熟,對於學習 Redis 的其它內容如複製的過程也會頗有幫助。

參考

  • 《Redis 實戰》
  • 《Redis 設計與實現》

若是個人文章對您有幫助,不妨點個贊支持一下(^_^)

相關文章
相關標籤/搜索