1. 程式人生 > >Redis 的資料持久化方法

Redis 的資料持久化方法

工作中經常會遇到 Redis 資料庫相關的使用操作,因為其將資料儲存在記憶體中的緣故,其資料的讀寫效率要遠遠高於資料庫等方式的讀寫。但也因為資料儲存在記憶體中,如果機器意外關機,就會導致資料的丟失。為了避免資料丟失造成的損失,因此就需要對 Redis 中的資料進行持久化的備份處理。本篇是對最近學習 Redis 資料持久化的一個筆記,簡要介紹了 Redis 提供的 RDB (快照方式) 與 AOF (只追加檔案) 兩種持久化方式的使用。

一. RDB 持久化

RDB 持久化方式有點類似 MySQL 的 mysqldump 命令,就是將庫中的資料匯出後作為備份。Redis 提供了 SAVE、 BGSAVE 以及自動化 SAVE 三種方式。下面分別演示一下。

首先修改下配置檔案,來指定一下當前 Redis 程序生成的 RDB 檔案的目錄和檔名稱

# 指定檔案目錄
dir /Users/mymac/study/Redis/data
# 指定檔名
dbfilename dump-6379.rdb

1. SAVE

直接執行命令 SAVE 命令即可

127.0.0.1:6379> set hello redis
OK
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379>

檢視其日誌可以看到其備份的日誌列印

20 67675:M 02 Jun 11:19:49.072 # Server started, Redis
version 3.2.8 21 67675:M 02 Jun 11:19:49.073 * The server is now ready to accept connections on port 6379 22 67675:M 02 Jun 11:20:21.974 * DB saved on disk

檢視上面配置的 目錄就可以看到對應的 rdb 檔案了,整個過程非常簡單,但是 SAVE 命令有幾個注意點:

  • 和 mysqldump 會阻塞資料庫一樣,SAVE 命令也會阻塞 Redis 主程序服務,導致服務暫時不可用
  • 生成的 RDB 檔案會覆蓋掉舊檔案

2. BGSAVE

BGSAVE,多了 BG, 顧名思義就是後臺 SAVE 的意思,和上面 SAVE 命令直接阻塞主程序不同,BGSAVE 會 Fork 一個子程序,然後通過子程序進行備份,這樣就不會影響到主程序對外提供服務了。操作如下

127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379>

日誌列印

23 67675:M 02 Jun 11:25:08.063 * Background saving started by pid 68038
24 68038:C 02 Jun 11:25:08.064 * DB saved on disk
25 67675:M 02 Jun 11:25:08.081 * Background saving terminated with success

可以看到其是新啟動了一個程序進行 Background saving, 對應的 rdb 檔案也會覆蓋之前的檔案。

不過需要注意的是,雖然 BGSAVE 的備份過程不會阻塞主程序,但是其 Fork 子程序的操作是由主程序進行的,所以當 Fork 子程序花費時間過多的時候也會導致服務不可用。

3. 自動間隔備份

除了上面兩種手動儲存之外, Redis 還提供了相關配置允許我們根據時間和 key 的改變次數類進行自動備份。

下面是配置方式

save 900 1 # 在 900 秒(15分鐘)內有一個 key 發生改變則進行 rdb 備份
save 300 10 # 在 300 秒內有至少 10 個 key 發生變化則進行備份
save 60 10000 # 在 60 秒內如果有 10000 個 key 發生變化則進行備份

可以通過註釋掉上面的配置來關閉自動間隔備份。

4. 使用建議

  • 建議關掉自動 rdb 備份
  • 對於 rdb 檔案管理進行集中管理
  • 可以考慮在主從系統中,在從節點進行 RDB 備份,但是要注意控制粒度

以上就是三種 RDB 方式的簡要介紹,除了上面三種方式之外,還有全量複製、shutdown 時等觸發 RDB 的操作,使用時需要加以注意。

二. AOF (Append only file)持久化方式

雖然 RDB 可以實現資料的備份,但也存在如下問題:

  • 耗時耗效能,其將所有資料進行 dump, 效能是 O(n),消耗記憶體和 IO 效能
  • 易丟失資料,在最後一次 save 和宕機時間之間的資料無法備份

鑑於 RDB 的問題,Redis 還提供了 AOF 方式進行資料備份。

要使用 AOF 功能的話需要在配置檔案中進行配置

593 appendonly yes # 開啟 AOF 功能,預設是 no
594 appendfilename "appendonly.aof" # 指定 aof 檔名
595 no-appendfsync-on-rewrite no #  重寫時是否做 aof 操作,關閉可以節省 IO 資源消耗, 但也會造成資料丟失的可能,需要權衡
596 appendfsync always # 重新整理方式

AOF (只追加檔案)類似於 MySQL 的 binlog,其會將 Redis 的每一條寫命令新增到 aof 檔案中,本質上是先寫入一個緩衝區,然後在重新整理到磁碟中,可以通過 appendfsync 進行配置其重新整理方式有三種:

  • always: 每條命令會立即重新整理到 aof 檔案中,這樣可以保證資料不丟失,但是會導致較大的 IO 開銷
  • everysec: 每秒重新整理,可以減輕 IO 壓力,但會存在丟失一秒資料的
  • no: 由作業系統決定何時重新整理

上面三種方式,大部分都是用第二種,達到資料安全性和效能的平衡,不推薦使用第三種,雖然不需要我們進行管理,但是也不可控。對於資料安全性較高的部分資料可以考慮使用第一種 always 方式。

1. AOF 檔案重寫

AOF 的方式會將每一條寫命令存到 aof 檔案中,隨著寫命令的增多,其檔案會越來越大,佔用儲存資源,並且恢復資料的時候也會越來越慢。為了減少資源的消耗,Redis 提供了 AOF 重寫,本質就是將過期的寫命令移除掉,只保留最新的一條。如下面三條命令,對 a 這個 key 我寫入了三次,AOF 備份會將三條命令都寫入到檔案中備份,但此時其實只有第三條命令是有效的,那麼 AOF 檔案重寫就會將 前兩條命令移除掉,只保留第三條。這樣可以達到減少磁碟佔用和加速資料恢復的目的。

127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> set a 2
OK
127.0.0.1:6379> set a 3
OK

2. AOF 檔案重寫的兩種方式

BGREWRITEAOF 命令

執行該命令,Redis 會將記憶體中的資料進行一次回溯,然後將對應的寫入命令儲存到 aof 檔案中。

127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

檢視 Redis 日誌其列印如下, 可以看到重寫也是先 fork 一個新的程序然後進行:

62 69318:M 02 Jun 12:17:09.042 * Background append only file rewriting started by pid 71343
63 69318:M 02 Jun 12:17:09.067 * AOF rewrite child asks to stop sending diffs.
64 71343:C 02 Jun 12:17:09.067 * Parent agreed to stop sending diffs. Finalizing AOF...
65 71343:C 02 Jun 12:17:09.068 * Concatenating 0.00 MB of AOF diff received from parent.
66 71343:C 02 Jun 12:17:09.068 * SYNC append only file rewrite performed
67 69318:M 02 Jun 12:17:09.101 * Background AOF rewrite terminated with success
68 69318:M 02 Jun 12:17:09.101 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
69 69318:M 02 Jun 12:17:09.102 * Background AOF rewrite finished successfully

重寫自動配置

Redis 提供了兩個重寫相關的配置


664 auto-aof-rewrite-min-size 64mb # AOF 檔案重寫所需的尺寸,當 aof 檔案達到該值時進行一次重寫
665 auto-aof-rewrite-percentage 100 # AOF 檔案的增長率, 即 AOF 變大多少時再次重寫,100 表示下次到達 128 M 時進行重寫

Redis 中提供了 aof_curren_size 和 aof_base_size 分別表示當前 AOF 檔案大小和上次重寫時的 AOF 檔案大小,其自動重寫就是滿足下面兩個條件:

aof_curren_size > auto-aof-rewrite-min-size
aof_curren_size - aof_base_size / aof_base_size > auto-aof-rewrite-percentage

3. AOF 檔案重寫過程

Redis 在 AOF 重寫時是通過 fork 一個子程序實現的,這樣可以在 aof 重寫時不影響服務。但此時如果有新的寫入命令的話,那樣就會導致 Redis 實際資料和 AOF 檔案不一致。針對該問題 Redis 提供了 aof_rewrite_buffer 緩衝區。結合緩衝區,其整個重寫過程如下:

  • Redis 接到 AOF 重寫命令,fork 子程序
  • 子程序執行 AOF 重寫
  • Redis 收到寫命令時,子程序繼續將寫命令寫入原來的 aof_buffer 並重新整理到舊的 aof 檔案中
  • 子程序將寫命令寫入到 aof_rewrite_buffer 中
  • 子程序完成 aof 重寫後,將 aof_rewrite_buffer 中的寫命令寫入新的 aof 檔案
  • 新的 aof 檔案代替舊的 aof 檔案,完成重寫

4. 使用建議

  • 建議開啟,當然如果只是作快取使用資料丟失影響不大時可以關閉
  • AOF 重寫集中管理
  • 重新整理機制建議使用 everysec
  • 足夠的記憶體!足夠的記憶體!足夠的記憶體! (要是硬體資源無限,哪來那麼多分散式系統微服務的破事= =!)

三. AOF 與 RDB 對比

上面介紹了 AOF 與 RDB 的使用,最後做一下簡要的對比

RDB AOF
載入優先順序 後加載
體積
恢復速度
資料安全
操作效能 重,全量備份比較消耗資源

上面就是 Redis 持久化的簡單使用,基本會用了,後面需要的話在考慮對其機制、檔案格式和內容做深入的學習。