Redis 是一個鍵值對數據庫服務器。基於內存存儲數據,它常被用做緩存數據庫,用來替代 memcached。官網: https://redis.io/
什么是持久化?
持久化,指將數據存儲到可永久保存的設備中。
例如,將內存中的數據存儲到可永久保存的硬盤中。
為什么需要持久化?
- Redis 基於內存存儲,內存掉電后數據會丟失
- 內存比硬盤貴得多,所以需要將一些不能丟失的數據持久化到硬盤上
甚至,一些特別重要的數據,是需要存到 MySQL 的。
Redis 本身有持久化,為什么還要寫進 mysql 呢?:https://www.v2ex.com/t/219551
如何做持久化?
Redis 提供了四種持久化方式:
- RDB(Redis database|Snapshoting)
- AOF(Append-Only file)
VM(虛擬內存)被淘汰了Diskstore 不了解
這次主要說的是 RDB 和 AOF 兩種持久化方式。
RDB 持久化
RDB:Redis database 的簡稱。一看這個,你就應該能猜到,這是 Redis 的默認持久化方式。
RDB 中持久化生成的是一個經過壓縮的二進制文件。
RDB 持久化時機:
- 在客戶端執行 SAVE 或者 BGSAVE
- 根據配置規則自動快照(稍后會講到)
- 執行 FLUSHALL 命令
- 執行復制(replication)
RDB 持久化步驟:
- fork 復制出一個父進程的副本子進程
- 子進程將內存中的數據寫入到硬盤中的臨時文件
- 將臨時文件替換舊的 rdb 文件
自動間隔保存(配置規則):
save 900 1 # 每900秒檢查一次,如果有1條數據修改了,那么執行 rdb
save 300 10 # 每300秒檢查一次,如果有10條數據修改了,那么執行 rdb
save 60 10000 # 每60秒檢查一次,如果有10000條數據修改了,那么執行 rdb
RDB 文件還原
服務器啟動時,會直接載入 RDB 文件。
但是如果 AOF 文件存在,則會載入 AOF 文件。AOF 文件載入過程會在后文中描述
AOF 持久化
AOF 是 Append Only File 的簡稱。
AOF 通過保存客戶端傳過來的寫命令來記錄數據庫的狀態。
如:
$3(后面是 \r\n)
SET
$3
msg
$1
5
$3
SET
$3
msg
$1
3
AOF 持久化的時機
需要在配置文件中加入:
appendonly yes
刷新到硬盤的時機
由於操作系統的緩存機制,每次寫入到 aof 文件之后,其實是寫入到了系統緩存中,默認情況下,操作系統每 30 秒同步磁盤一次
# appendfsync always # 每次執行寫入都會同步, Redis 底層是基於事件的,如果事件沒有處理完,而機器掛了,就會丟失一個事件的內容。所以,即使是 always 也不能保證數據不丟失。
appendfsync everysec # 默認值,每秒同步一次
# appendfsync no # 依靠操作系統的同步頻率
AOF 持久化的步驟
主進程進行如文章末尾所示的三個步驟:
- 命令追加
- 文件寫入
- 文件同步
AOF 重寫的時機
- 配置:
# 當前 AOF 文件超過上次重寫時的 AOF 文件大小的百分之多少時再次進行重寫
# 如果之前沒有沖寫過,則以啟動時的 AOF 文件大小為依據。
auto-aof-rewrite-percentage 100
# 允許重寫的最小值
auto-aof-rewrite-min-size 64mb
- 主動執行 BGREWRITEAOF 命令觸發 AOF 重寫。
AOF 重寫步驟
如果是在客戶端直接執行 REWRITEAOF ,會阻塞服務,直到重寫完成,將新的 AOF 文件覆蓋舊的文件。這種方式一般不會考慮。
BGREWRITEAOF 命令的執行過程如文末圖片所示:
- 父進程寫入 AOF 緩沖區和 AOF 重寫緩沖區
- 子進程執行 AOF 重寫,完成之后發送信號給父進程
- 父進程收到信號將 AOF 重寫緩沖區的內容寫入到新的 AOF 文件中,並且覆蓋原有的 AOF 文件
AOF 重寫是將多條命令用一條命令代替。
如上面代碼所示,存儲一個 msg 使用了兩條命令。經過 AOF 文件重寫之后,就會變成如下所示,大大減少了使用的存儲空間:
$3
SET
$3
msg
$1
AOF 文件還原
AOF 文件還原的步驟如下:
- 創建一個偽客戶端(fake client)
- 從 AOF 文件中分析並讀取一條寫命令
- 使用偽客戶端執行寫命令
- 一直重復步驟 2 和 3
AOF 寫入與重寫過程圖:
參考
《Redis入門指南》
《Redis設計與實現》