持久化策略(AOF與RDB)
- 持久化
- Redis如何實現數據不丟失?
- RDB 快照是如何實現的呢?
- 執行時機
- RDB原理
- 執行快照時,數據能被修改嗎?
- AOF持久化是怎么實現的?
- AOF原理
- 三種寫回策略
- AOF重寫機制
- RDB和AOF合體
持久化
Redis如何實現數據不丟失?
Redis 共有三種數據持久化的方式:
- AOF 日志:每執行一條寫操作命令,就把該命令以追加的方式寫入到一個文件里;
- RDB 快照:將某一時刻的內存數據,以二進制的方式寫入磁盤;
- 混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的優點;
RDB 快照是如何實現的呢?
RDB全稱Redis Database Backup file(Redis數據備份文件),也被叫做Redis數據快照。簡單來說就是把內存中的所有數據都記錄到磁盤中。當Redis實例故障重啟后,從磁盤讀取快照文件,恢復數據。快照文件稱為RDB文件,默認是保存在當前運行目錄。
執行時機
RDB持久化在四種情況下會執行:
- 執行save命令
- 執行bgsave命令
- Redis停機時
- 觸發RDB條件時
1)save命令
執行下面的命令,可以立即執行一次RDB:
save命令會導致主進程執行RDB,這個過程中其它所有命令都會被阻塞。只有在數據遷移時可能用到。
2)bgsave命令
下面的命令可以異步執行RDB:
會創建一個子進程來生成 RDB 文件,這樣可以避免主線程的阻塞;
3)停機時
Redis停機時會執行一次save命令,實現RDB持久化。
4)觸發RDB條件
Redis內部有觸發RDB的機制,可以在redis.conf文件中找到,格式如下:
# 900秒內,如果至少有1個key被修改,則執行bgsave , 如果是save "" 則表示禁用RDB
save 900 1
save 300 10
save 60 10000
RDB的其它配置也可以在redis.conf文件中設置:
# 是否壓縮 ,建議不開啟,壓縮也會消耗cpu,磁盤的話不值錢
rdbcompression yes# RDB文件名稱
dbfilename dump.rdb # 文件保存的路徑目錄
dir ./
RDB原理
執行快照時,數據能被修改嗎?
執行 bgsave 過程中,Redis 依然可以繼續處理操作命令的,也就是數據是能被修改的。關鍵的技術就在于**寫時復制技術(Copy-On-Write, COW)。**原理如下:
bgsave開始時會fork主進程得到子進程,子進程共享主進程的內存數據。完成fork后讀取內存數據并寫入 RDB 文件。
fork采用的是copy-on-write技術:
- 當主進程執行讀操作時,訪問共享內存;
- 當主進程執行寫操作時,則會拷貝一份數據,執行寫操作。
AOF持久化是怎么實現的?
AOF原理
AOF全稱為Append Only File(追加文件)。Redis處理的每一個寫命令都會記錄在AOF文件,可以看做是命令日志文件。
三種寫回策略
AOF默認是關閉的,需要修改redis.conf配置文件來開啟AOF:
# 是否開啟AOF功能,默認是no
appendonly yes
# AOF文件的名稱
appendfilename "appendonly.aof"
Redis 寫入 AOF 日志的過程,如下圖:

過程如下:
- Redis 執行完寫操作命令后,會將命令追加到
server.aof_buf
緩沖區; - 然后通過 write() 系統調用,將 aof_buf 緩沖區的數據寫入到 AOF 文件,此時數據并沒有寫入到硬盤,而是拷貝到了內核緩沖區 page cache,等待內核將數據寫入硬盤;
- 具體內核緩沖區的數據什么時候寫入到硬盤,由內核決定。
上面第三步AOF的命令記錄的頻率可以通過redis.conf文件來配:
# 表示每執行一次寫命令,立即記錄到AOF文件
appendfsync always
# 寫命令執行完先放入AOF緩沖區,然后表示每隔1秒將緩沖區數據寫到AOF文件,是默認方案
appendfsync everysec
# 寫命令執行完先放入AOF緩沖區,由操作系統決定何時將緩沖區內容寫回磁盤
appendfsync no
三種策略對比:
根據自己的業務場景進行選擇:
- 如果要高性能,就選擇 No 策略;
- 如果要高可靠,就選擇 Always 策略;
- 如果允許數據丟失一點,但又想性能高,就選擇 Everysec 策略。
深入到源碼后,你就會發現這三種策略只是在控制 fsync()
函數的調用時機。
AOF重寫機制
因為是記錄命令,AOF文件會比RDB文件大的多。而且AOF會記錄對同一個key的多次寫操作,但只有最后一次寫操作才有意義。通過執行bgrewriteaof命令,可以讓AOF文件執行重寫功能,用最少的命令達到相同效果。
如圖,AOF原本有三個命令,但是set num 123 和 set num 666
都是對num的操作,第二次會覆蓋第一次的值,因此第一個命令記錄下來沒有意義。
所以重寫命令后,AOF文件內容就是:mset name jack num 666
Redis也會在觸發閾值時自動去重寫AOF文件。閾值也可以在redis.conf中配置:
# AOF文件比上次文件 增長超過多少百分比則觸發重寫
auto-aof-rewrite-percentage 100
# AOF文件體積最小多大以上才觸發重寫
auto-aof-rewrite-min-size 64mb
RDB和AOF合體
RDB和AOF各有自己的優缺點,如果對數據安全性要求較高,在實際開發中往往會結合兩者來使用。
在 Redis 4.0 提出一個新的方法混合使用 AOF 日志和內存快照,也叫混合持久化。
如果想要開啟混合持久化功能,可以在 Redis 配置文件將下面這個配置項設置成 yes:
aof-use-rdb-preamble yes
混合持久化工作在 AOF 日志重寫過程。
當開啟了混合持久化時,在 AOF 重寫日志時,fork
出來的重寫子進程會先將與主線程共享的內存數據以 RDB 方式寫入到 AOF 文件,然后主線程處理的操作命令會被記錄在重寫緩沖區里,重寫緩沖區里的增量命令會以 AOF 方式寫入到 AOF 文件,寫入完成后通知主進程將新的含有 RDB 格式和 AOF 格式的 AOF文件替換舊的的 AOF 文件。
使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量數據,后半部分是 AOF 格式的增量數據。
這樣的好處在于,重啟 Redis 加載數據的時候,由于前半部分是 RDB 內容,這樣加載的時候速度會很快。
加載完 RDB 的內容后,才會加載后半部分的 AOF 內容,這里的內容是 Redis 后臺子進程重寫 AOF 期間,主線程處理的操作命令,可以使得數據更少的丟失。