1. 持久化機制的作用
Redis 是基于內存的數據結構數據庫,雖然讀寫性能非常高,但所有數據默認保存在內存中。一旦服務器宕機、進程意外崩潰或容器重啟,內存中的數據將全部丟失。這對于生產環境的可用性與可靠性是極其危險的。因此,Redis 提供了持久化機制,將內存數據定期或實時寫入磁盤,以便在服務重啟時能夠從磁盤數據中恢復,防止宕機導致的數據全部丟失。
2. 三種持久化機制
Redis 提供了三種持久化方式:
- RDB(Redis DataBase)快照持久化
- AOF(Append Only File)日志持久化
- 混合持久化(RDB + AOF,Redis 4.0+ 引入)
在生產環境中使用時,這些策略都可能會失敗。
2.1 RDB 快照持久化
1 基本原理
RDB 是一種 周期性快照機制,Redis 會在滿足特定條件時,將當前內存中的所有數據以快照方式保存為一個二進制文件(默認為 dump.rdb
)。
RDB 采用了 COW(Copy-On-Write)機制,由 Redis 主進程通過 fork()
創建子進程,子進程將內存快照寫入磁盤,而主進程則繼續處理客戶端請求,保證高并發。
子進程剛創建時共享父進程內存,但當父進程修改某塊內存數據時,會將該頁面復制一份,以避免子進程快照不一致,這一機制稱為 “頁面分離”。
2 觸發方式
- 自動觸發:通過配置
redis.conf
文件中的save
參數,如:
//默認如下配置:
save 900 1:每隔900s(15min),如果有超過1個key發生了變化,就寫一份新的RDB文件
save 300 10:每隔300s(5min),如果有超過10個key發生了變化,就寫一份新的RDB文件
save 60 10000:每隔60s(1min),如果有超過10000個key發生了變化,就寫一份新的RDB文件
//(配置多種策略可以同時生效,無論滿足哪一種條件都會寫一份新的RDB文件)
- 手動觸發:
save
:阻塞主進程,生成 RDB 文件。bgsave
:異步觸發,fork 子進程處理持久化。
3 優缺點
優點:對主進程性能影響小,快照文件便于備份與遠程傳輸。恢復速度快,適合冷啟動。數據文件緊湊,占用空間小。
缺點:數據可能丟失幾分鐘。 fork 子進程時內存翻倍,數據量大時存在性能抖動風險。使用特定二進制格式存儲,版本兼容性差。
4 RDB可能的故障場景
??場景1:數據丟失??。默認配置下,如果Redis在快照之間崩潰,可能丟失最多15分鐘數據。
??場景2:Fork失敗??。當內存不足時,fork操作可能失敗。
# Redis log
[1111] 4 Aug # Can't save in background: fork: Cannot allocate memory
??場景3:磁盤空間耗盡??。RDB文件先寫入臨時位置,再原子性的重命名。如果寫入期間磁盤空間不足,快照會失敗,Redis仍然繼續運行。
# Redis log
[1111] 4 Aug # Write error saving DB on disk: No space left on device
??場景4:斷電后RDB文件損壞??。斷電時RDB文件只寫入部分內容。重啟時Redis拒絕啟動損壞的RDB文件。
# Redis startup log
[1111] 4 Aug # Short read or OOM loading DB. Unrecoverable error, aborting now.
2.2 AOF 日志持久化
1 基本原理
AOF 通過將所有修改命令(如 SET
、DEL
)按順序追加到日志文件(默認為 appendonly.aof
)中來實現持久化。Redis 在收到命令后,先記錄日志,再執行命令。寫入流程如下:
- 指令被追加至 OS 緩沖區;
- 根據
appendfsync
策略定期 fsync 到磁盤。
2 配置方式
通過 appendfsync
參數配置:
appendfsync everysec # 每秒刷一次
appendfsync always # 每寫入一條命令都 fsync,最安全但最慢
appendfsync no # 不主動 fsync,完全交由 OS 決定
3 重寫(Rewrite)
隨著操作積累,AOF 文件會越來越大,影響重啟速度。因此 Redis 提供了AOF Rewrite:
- fork 子進程;
- 將當前內存快照轉化為最小指令集;
- 合并重寫后的小文件;
- 替換原有 AOF 文件。
// 自動觸發規
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
4 優缺點
優點:更高的數據安全性,最多丟失 1 秒數據。日志可讀,可手動恢復誤刪數據。重寫機制可控制文件大小。
缺點:恢復速度比 RDB 慢。寫入性能略低于 RDB。文件體積通常比 RDB 大。
5 AOF可能的失敗場景
??場景1:系統崩潰后AOF損壞??
# Redis startup log
[1111] 4 Aug # Bad file format reading the append only file:
make a backup of your AOF file, then use ./redis-check-aof --fix <filename>
??場景2:AOF重寫失敗??。隨著AOF文件增長,Redis會定期重寫以保持精簡。但這個重寫過程可能出錯。
# Redis log during rewrite failure
[1111] 4 Aug # Error rewriting AOF: No space left on device
[1111] 4 Aug # AOF rewrite failed:
Previous AOF was kept, but disk is full, cannot proceed with rewrite.
這個錯誤的大意是重寫AOF錯誤,因為設備剩余存儲空間不足。雖然重寫失敗,但Redis繼續向舊AOF文件追加。磁盤完全填滿后,Redis開始拒絕寫入。
??場景3:重寫期間內存爆炸??。AOF重寫期間,Redis在內存中緩沖所有新寫入。如果重寫耗時過長(慢磁盤常見),可能在"安全"的重寫操作期間因OOM而崩潰。
??場景4:"appendfsync always"導致腦裂??。假設對Redis中的重要數據使用appendfsync always
策略。如果這個Redis實例因為網絡問題等性能變差,會被負載均衡器將其標記為不健康,把流量轉向備份實例。網絡恢復后,會得到兩個包含不同數據的Redis實例。
2.3 混合持久化(RDB + AOF)
Redis 4.0 引入混合持久化模式:在重寫 AOF 文件時,先寫入 RDB 快照,再追加從快照開始到當前的 AOF 增量日志,融合了二者優點。
配置參數:
aof-use-rdb-preamble yes
注意:混合持久化的 AOF 文件前段為 RDB 格式,老版本 Redis 不兼容。
優點:
- 恢復效率高,RDB 快照 + 小量 AOF 日志。
- 兼具 AOF 的數據完整性與 RDB 的恢復速度。
缺點:
- 文件結構復雜,可讀性差。
- 4.0 以下版本不支持。
3. 持久化監控信息
Redis的INFO
命令能顯示持久化狀態,但信息并不完整。
# INFO顯示內容
rdb_last_save_time:1678889001
rdb_last_bgsave_status:ok
aof_enabled:1
aof_last_rewrite_time_sec:45# 未顯示內容
# - Fork失敗率
# - 磁盤空間趨勢
# - 損壞檢測
# - 性能影響
以下是一個設置額外的監控數據的示例。
#!/bin/bash
# 檢查RDB保存失敗
redis-cli LASTSAVE | awk '{last_save = $1;now = systime();diff = now - last_save;if (diff > 3600) { # 1小時未保存則告警print "警告:RDB已" diff "秒未保存";}
}'# 檢查AOF健康狀態
redis-cli INFO persistence | grep aof_last_write_status | grep -v ok && echo "AOF寫入失敗"# 監控持久化磁盤空間
df -h /var/lib/redis | awk 'NR==2 {if (int($5) > 80) {print "警告:Redis磁盤使用" $5 "已滿";}
}'
4. 恢復策略
1. AOF損壞恢復參考示例
# 步驟1:備份損壞文件
cp appendonly.aof appendonly.aof.corrupted# 步驟2:嘗試自動修復
redis-check-aof --fix appendonly.aof# 步驟3:檢查丟失內容
redis-check-aof appendonly.aof.corrupted > corruption_report.txt# 步驟4:自動修復失敗時人工干預
# 編輯AOF文件,移除末尾不完整命令
tail -20 appendonly.aof.corrupted # 查找不完整命令
head -n -5 appendonly.aof.corrupted > appendonly.aof # 移除最后5行
2 RDB損壞恢復參考示例
# 步驟1:檢查RDB是否可修復
redis-check-rdb dump.rdb# 步驟2:不可修復則從備份恢復
aws s3 cp s3://backup-bucket/redis/dump.rdb.gz .
gunzip dump.rdb.gz# 步驟3:無備份則重建并重載應用數據
5. 完整配置參考
1 Redis配置
# redis.conf - 生產環境配置# RDB配置
# 更頻繁保存,多條件觸發
save 900 1 # 15分鐘內任何變更
save 300 10 # 5分鐘內10+變更
save 60 100 # 1分鐘內100+變更# RDB失敗時停止接受寫入
stop-writes-on-bgsave-error yes# 壓縮RDB文件
rdbcompression yes# AOF配置
appendonly yes
appendfilename "appendonly.aof"# 每秒同步(良好的持久性/性能平衡)
appendfsync everysec# 啟用AOF重寫控制文件大小
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb# AOF損壞但可讀時不丟失數據
aof-load-truncated yes# 使用RDB-AOF混合加速重啟
aof-use-rdb-preamble yes# 內存管理
maxmemory 6gb # 為fork期間的COW預留空間
maxmemory-policy allkeys-lru# 禁用內存過量使用
vm-enabled no
2 自動備份配置
#!/bin/bash
# redis-backup.sh - 每小時執行DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/redis"
S3_BUCKET="company-redis-backups"# 創建備份目錄
mkdir -p $BACKUP_DIR/$DATE# 觸發RDB保存
redis-cli BGSAVE
sleep 30 # 等待保存完成# 復制文件
cp /var/lib/redis/dump.rdb $BACKUP_DIR/$DATE/
cp /var/lib/redis/appendonly.aof $BACKUP_DIR/$DATE/# 壓縮上傳
tar -czf $BACKUP_DIR/$DATE.tar.gz $BACKUP_DIR/$DATE/
aws s3 cp $BACKUP_DIR/$DATE.tar.gz s3://$S3_BUCKET/# 清理舊備份(本地保留48小時,S3保留30天)
find $BACKUP_DIR -name "*.tar.gz" -mtime +2 -delete
aws s3 ls s3://$S3_BUCKET/ | awk '$1 < "'$(date -d '30 days ago' '+%Y-%m-%d')'" {print $4}' | xargs -I {} aws s3 rm s3://$S3_BUCKET/{}
6. 常用持久化相關命令
命令 | 說明 |
---|---|
save | 阻塞生成 RDB 快照 |
bgsave | 后臺生成 RDB 快照 |
bgrewriteaof | 重寫 AOF 文件 |
info Persistence | 查看持久化信息 |
redis-check-aof | 檢查 / 修復 AOF 文件 |
redis-check-rdb | 檢查 RDB 文件 |
shutdown | 安全關閉,自動保存 RDB |
kill -9 | 強制關閉,可能導致數據丟失 |