Redis持久化 - RDB和AOF

點(diǎn)擊上方「藍(lán)字」關(guān)注我們

一、持久化的作用
1. 什么是持久化
持久化(Persistence),即把數(shù)據(jù)(如內(nèi)存中的對(duì)象)保存到可永久保存的存儲(chǔ)設(shè)備中(如磁盤)。
持久化Redis所有數(shù)據(jù)保持在內(nèi)存中,對(duì)數(shù)據(jù)的更新將異步地保存到磁盤上。

2. 持久化的實(shí)現(xiàn)方式
快照方式持久化
快照方式持久化就是在某時(shí)刻把所有數(shù)據(jù)進(jìn)行完整備份。
例:Mysql的Dump方式、Redis的RDB方式。
寫日志方式持久化
寫日志方式持久化就是把用戶執(zhí)行的所有寫指令(增刪改)備份到文件中,還原數(shù)據(jù)時(shí)只需要把備份的所有指令重新執(zhí)行一遍即可。
例:Mysql的Binlog、Redis的AOF、Hbase的HLog。
二、RDB
1. 什么是RDB
RDB簡介

RDB持久化方式能夠在指定的時(shí)間間隔能對(duì)你的數(shù)據(jù)進(jìn)行快照存儲(chǔ)。
在默認(rèn)情況下, Redis 將數(shù)據(jù)庫快照保存在名字為 dump.rdb的二進(jìn)制文件中。
在 Redis 運(yùn)行時(shí), RDB 程序?qū)?dāng)前內(nèi)存中的數(shù)據(jù)庫快照保存到磁盤文件中, 在 Redis 重啟動(dòng)時(shí), RDB 程序可以通過載入 RDB 文件來還原數(shù)據(jù)庫的狀態(tài)。
工作方式
當(dāng) Redis 需要保存 dump.rdb 文件時(shí), 服務(wù)器執(zhí)行以下操作:
Redis 調(diào)用forks。同時(shí)擁有父進(jìn)程和子進(jìn)程。
子進(jìn)程將數(shù)據(jù)集寫入到一個(gè)臨時(shí) RDB 文件中。
當(dāng)子進(jìn)程完成對(duì)新 RDB 文件的寫入時(shí),Redis 用新 RDB 文件替換原來的 RDB 文件,并刪除舊的 RDB 文件。
這種工作方式使得 Redis 可以從寫時(shí)復(fù)制(copy-on-write)機(jī)制中獲益。
2. RDB的三種主要觸發(fā)機(jī)制
save命令(同步數(shù)據(jù)到磁盤上)
save?命令執(zhí)行一個(gè)同步操作,以RDB文件的方式保存所有數(shù)據(jù)的快照。
127.0.0.1:6379> save
OK

由于?save?命令是同步命令,會(huì)占用Redis的主進(jìn)程。若Redis數(shù)據(jù)非常多時(shí),save命令執(zhí)行速度會(huì)非常慢,阻塞所有客戶端的請(qǐng)求。
因此很少在生產(chǎn)環(huán)境直接使用SAVE 命令,可以使用BGSAVE 命令代替。如果在BGSAVE命令的保存數(shù)據(jù)的子進(jìn)程發(fā)生錯(cuò)誤的時(shí),用 SAVE命令保存最新的數(shù)據(jù)是最后的手段。

bgsave命令(異步保存數(shù)據(jù)到磁盤上)
bgsave?命令執(zhí)行一個(gè)異步操作,以RDB文件的方式保存所有數(shù)據(jù)的快照。
127.0.0.1:6379> bgsave
Background saving started
Redis使用Linux系統(tǒng)的fock()生成一個(gè)子進(jìn)程來將DB數(shù)據(jù)保存到磁盤,主進(jìn)程繼續(xù)提供服務(wù)以供客戶端調(diào)用。
如果操作成功,可以通過客戶端命令LASTSAVE來檢查操作結(jié)果。

save?與?bgsave?對(duì)比
| 命令 | save | bgsave |
|---|---|---|
| IO類型 | 同步 | 異步 |
| 阻塞? | 是 | 是(阻塞發(fā)生在fock(),通常非常快) |
| 復(fù)雜度 | O(n) | O(n) |
| 優(yōu)點(diǎn) | 不會(huì)消耗額外的內(nèi)存 | 不阻塞客戶端命令 |
| 缺點(diǎn) | 阻塞客戶端命令 | 需要fock子進(jìn)程,消耗內(nèi)存 |
自動(dòng)生成RDB
除了手動(dòng)執(zhí)行?save?和?bgsave?命令實(shí)現(xiàn)RDB持久化以外,Redis還提供了自動(dòng)自動(dòng)生成RDB的方式。
你可以通過配置文件對(duì) Redis 進(jìn)行設(shè)置, 讓它在“ N 秒內(nèi)數(shù)據(jù)集至少有 M 個(gè)改動(dòng)”這一條件被滿足時(shí), 自動(dòng)進(jìn)行數(shù)據(jù)集保存操作。
比如說, 以下設(shè)置會(huì)讓 Redis 在滿足“ 60 秒內(nèi)有至少有 1000 個(gè)鍵被改動(dòng)”這一條件時(shí), 自動(dòng)進(jìn)行數(shù)據(jù)集保存操作:
save 60 1000

3. RDB相關(guān)配置
# RDB自動(dòng)持久化規(guī)則
# 當(dāng) 900 秒內(nèi)有至少有 1 個(gè)鍵被改動(dòng)時(shí),自動(dòng)進(jìn)行數(shù)據(jù)集保存操作
save 900 1
# 當(dāng) 300 秒內(nèi)有至少有 10 個(gè)鍵被改動(dòng)時(shí),自動(dòng)進(jìn)行數(shù)據(jù)集保存操作
save 300 10
# 當(dāng) 60 秒內(nèi)有至少有 10000 個(gè)鍵被改動(dòng)時(shí),自動(dòng)進(jìn)行數(shù)據(jù)集保存操作
save 60 10000
# RDB持久化文件名
dbfilename dump-.rdb
# 數(shù)據(jù)持久化文件存儲(chǔ)目錄
dir /var/lib/redis
# bgsave發(fā)生錯(cuò)誤時(shí)是否停止寫入,通常為yes
stop-writes-on-bgsave-error yes
# rdb文件是否使用壓縮格式
rdbcompression yes
# 是否對(duì)rdb文件進(jìn)行校驗(yàn)和檢驗(yàn),通常為yes
rdbchecksum yes4. RDB的優(yōu)點(diǎn)
RDB是一個(gè)非常緊湊的文件,它保存了某個(gè)時(shí)間點(diǎn)的數(shù)據(jù)集,非常適用于數(shù)據(jù)集的備份,比如你可以在每個(gè)小時(shí)報(bào)保存一下過去24小時(shí)內(nèi)的數(shù)據(jù),同時(shí)每天保存過去30天的數(shù)據(jù),這樣即使出了問題你也可以根據(jù)需求恢復(fù)到不同版本的數(shù)據(jù)集。
RDB是一個(gè)緊湊的單一文件,很方便傳送到另一個(gè)遠(yuǎn)端數(shù)據(jù)中心或者亞馬遜的S3(可能加密),非常適用于災(zāi)難恢復(fù)。
RDB在保存RDB文件時(shí)父進(jìn)程唯一需要做的就是fork出一個(gè)子進(jìn)程,接下來的工作全部由子進(jìn)程來做,父進(jìn)程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。
與AOF相比,在恢復(fù)大的數(shù)據(jù)集的時(shí)候,RDB方式會(huì)更快一些。
5. RDB的缺點(diǎn)
耗時(shí)、耗性能。RDB 需要經(jīng)常fork子進(jìn)程來保存數(shù)據(jù)集到硬盤上,當(dāng)數(shù)據(jù)集比較大的時(shí)候,fork的過程是非常耗時(shí)的,可能會(huì)導(dǎo)致Redis在一些毫秒級(jí)內(nèi)不能響應(yīng)客戶端的請(qǐng)求。如果數(shù)據(jù)集巨大并且CPU性能不是很好的情況下,這種情況會(huì)持續(xù)1秒,AOF也需要fork,但是你可以調(diào)節(jié)重寫日志文件的頻率來提高數(shù)據(jù)集的耐久度。
不可控、丟失數(shù)據(jù)。如果你希望在redis意外停止工作(例如電源中斷)的情況下丟失的數(shù)據(jù)最少的話,那么RDB不適合你。雖然你可以配置不同的save時(shí)間點(diǎn)(例如每隔5分鐘并且對(duì)數(shù)據(jù)集有100個(gè)寫的操作),是Redis要完整的保存整個(gè)數(shù)據(jù)集是一個(gè)比較繁重的工作,你通常會(huì)每隔5分鐘或者更久做一次完整的保存,萬一在Redis意外宕機(jī),你可能會(huì)丟失幾分鐘的數(shù)據(jù)。
三、AOF
1. 什么是AOF
快照功能(RDB)并不是非常耐久(durable):如果 Redis 因?yàn)槟承┰蚨斐晒收贤C(jī), 那么服務(wù)器將丟失最近寫入、且仍未保存到快照中的那些數(shù)據(jù)。從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式:AOF 持久化。
你可以在配置文件中打開AOF方式:
appendonly yes
打開AOF后, 每當(dāng) Redis 執(zhí)行一個(gè)改變數(shù)據(jù)集的命令時(shí)(比如 SET), 這個(gè)命令就會(huì)被追加到 AOF 文件的末尾。這樣的話, 當(dāng) Redis 重新啟時(shí), 程序就可以通過重新執(zhí)行 AOF 文件中的命令來達(dá)到重建數(shù)據(jù)集的目的。
AOF運(yùn)行原理 - 創(chuàng)建

AOF運(yùn)行原理 - 恢復(fù)

2. AOF持久化的三種策略
你可以通過配置文件配置 Redis 多久才將數(shù)據(jù) fsync 到磁盤一次。
always
每次有新命令追加到 AOF 文件時(shí)就執(zhí)行一次 fsync :非常慢,也非常安全。

everysec
每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多),并且在故障時(shí)只會(huì)丟失 1 秒鐘的數(shù)據(jù)。
推薦(并且也是默認(rèn))的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。

no
從不 fsync :將數(shù)據(jù)交給操作系統(tǒng)來處理,由操作系統(tǒng)來決定什么時(shí)候同步數(shù)據(jù)。更快,也更不安全的選擇。

always、everysec、no對(duì)比
| 命令 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|
| always | 不丟失數(shù)據(jù) | IO開銷大,一般SATA磁盤只有幾百TPS |
| everysec | 每秒進(jìn)行與fsync,最多丟失1秒數(shù)據(jù) | 可能丟失1秒數(shù)據(jù) |
| no | 不用管 | 不可控 |
推薦(并且也是默認(rèn))的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。
3. AOF重寫
因?yàn)?AOF 的運(yùn)作方式是不斷地將命令追加到文件的末尾, 所以隨著寫入命令的不斷增加, AOF 文件的體積也會(huì)變得越來越大。舉個(gè)例子, 如果你對(duì)一個(gè)計(jì)數(shù)器調(diào)用了 100 次 INCR , 那么僅僅是為了保存這個(gè)計(jì)數(shù)器的當(dāng)前值, AOF 文件就需要使用 100 條記錄(entry)。然而在實(shí)際上, 只使用一條 SET 命令已經(jīng)足以保存計(jì)數(shù)器的當(dāng)前值了, 其余 99 條記錄實(shí)際上都是多余的。
為了處理這種情況, Redis 支持一種有趣的特性:可以在不打斷服務(wù)客戶端的情況下, 對(duì) AOF 文件進(jìn)行重建(rebuild)。執(zhí)行 bgrewriteaof 命令, Redis 將生成一個(gè)新的 AOF 文件, 這個(gè)文件包含重建當(dāng)前數(shù)據(jù)集所需的最少命令。
Redis 2.2 需要自己手動(dòng)執(zhí)行 bgrewriteaof 命令;Redis 2.4 則可以通過配置自動(dòng)觸發(fā) AOF 重寫。

AOF重寫的作用
減少磁盤占用量
加速數(shù)據(jù)恢復(fù)
AOF重寫的實(shí)現(xiàn)方式
bgrewriteaof 命令
Redis bgrewriteaof 命令用于異步執(zhí)行一個(gè) AOF(AppendOnly File)文件重寫操作。重寫會(huì)創(chuàng)建一個(gè)當(dāng)前AOF文件的體積優(yōu)化版本。
即使 bgrewriteaof 執(zhí)行失敗,也不會(huì)有任何數(shù)據(jù)丟失,因?yàn)榕f的AOF文件在 bgrewriteaof 成功之前不會(huì)被修改。
AOF 重寫由 Redis 自行觸發(fā),bgrewriteaof 僅僅用于手動(dòng)觸發(fā)重寫操作。
具體內(nèi)容:如果一個(gè)子Redis是通過磁盤快照創(chuàng)建的,AOF重寫將會(huì)在RDB終止后才開始保存。這種情況下BGREWRITEAOF仍然會(huì)返回OK狀態(tài)碼。從Redis 2.6起你可以通過INFO命令查看AOF重寫執(zhí)行情況。
如果只在執(zhí)行的AOF重寫返回一個(gè)錯(cuò)誤,AOF重寫將會(huì)在稍后一點(diǎn)的時(shí)間重新調(diào)用。

AOF重寫配置
| 配置名 | 含義 |
|---|---|
| auto-aof-rewrite-min-size | 觸發(fā)AOF文件執(zhí)行重寫的最小尺寸 |
| auto-aof-rewrite-percentage | 觸發(fā)AOF文件執(zhí)行重寫的增長率 |
| 統(tǒng)計(jì)名 | 含義 |
|---|---|
| aof_current_size | AOF文件當(dāng)前尺寸(字節(jié)) |
| aof_base_size | AOF文件上次啟動(dòng)和重寫時(shí)的尺寸(字節(jié)) |
AOF重寫自動(dòng)觸發(fā)機(jī)制,需要同時(shí)滿足下面兩個(gè)條件:
aof_current_size > auto-aof-rewrite-min-size
(aof_current_size - aof_base_size) * 100 / aof_base_size > auto-aof-rewrite-percentage
假設(shè) Redis 的配置項(xiàng)為:
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage 100當(dāng)AOF文件的體積大于64Mb,并且AOF文件的體積比上一次重寫之久的體積大了至少一倍(100%)時(shí),Redis將執(zhí)行 bgrewriteaof 命令進(jìn)行重寫。
AOF重寫的流程

3. AOF相關(guān)配置
# 開啟AOF持久化方式
appendonly yes
# AOF持久化文件名
appendfilename appendonly-.aof
# 每秒把緩沖區(qū)的數(shù)據(jù)同步到磁盤
appendfsync everysec
# 數(shù)據(jù)持久化文件存儲(chǔ)目錄
dir /var/lib/redis
# 是否在執(zhí)行重寫時(shí)不同步數(shù)據(jù)到AOF文件
# 這里的 yes,就是執(zhí)行重寫時(shí)不同步數(shù)據(jù)到AOF文件
no-appendfsync-on-rewrite yes
# 觸發(fā)AOF文件執(zhí)行重寫的最小尺寸
auto-aof-rewrite-min-size 64mb
# 觸發(fā)AOF文件執(zhí)行重寫的增長率
auto-aof-rewrite-percentage 1004. AOF的優(yōu)點(diǎn)
使用AOF 會(huì)讓你的Redis更加耐久: 你可以使用不同的fsync策略:無fsync,每秒fsync,每次寫的時(shí)候fsync。使用默認(rèn)的每秒fsync策略,Redis的性能依然很好(fsync是由后臺(tái)線程進(jìn)行處理的,主線程會(huì)盡力處理客戶端請(qǐng)求),一旦出現(xiàn)故障,你最多丟失1秒的數(shù)據(jù)。
AOF文件是一個(gè)只進(jìn)行追加的日志文件,所以不需要寫入seek,即使由于某些原因(磁盤空間已滿,寫的過程中宕機(jī)等等)未執(zhí)行完整的寫入命令,你也也可使用redis-check-aof工具修復(fù)這些問題。
Redis 可以在 AOF 文件體積變得過大時(shí),自動(dòng)地在后臺(tái)對(duì) AOF 進(jìn)行重寫:重寫后的新 AOF 文件包含了恢復(fù)當(dāng)前數(shù)據(jù)集所需的最小命令集合。整個(gè)重寫操作是絕對(duì)安全的,因?yàn)?Redis 在創(chuàng)建新 AOF 文件的過程中,會(huì)繼續(xù)將命令追加到現(xiàn)有的 AOF 文件里面,即使重寫過程中發(fā)生停機(jī),現(xiàn)有的 AOF 文件也不會(huì)丟失。而一旦新 AOF 文件創(chuàng)建完畢,Redis 就會(huì)從舊 AOF 文件切換到新 AOF 文件,并開始對(duì)新 AOF 文件進(jìn)行追加操作。
AOF 文件有序地保存了對(duì)數(shù)據(jù)庫執(zhí)行的所有寫入操作, 這些寫入操作以 Redis 協(xié)議的格式保存, 因此 AOF 文件的內(nèi)容非常容易被人讀懂, 對(duì)文件進(jìn)行分析(parse)也很輕松。導(dǎo)出(export) AOF 文件也非常簡單:舉個(gè)例子, 如果你不小心執(zhí)行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那么只要停止服務(wù)器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重啟 Redis , 就可以將數(shù)據(jù)集恢復(fù)到 FLUSHALL 執(zhí)行之前的狀態(tài)。
5. AOF的缺點(diǎn)
對(duì)于相同的數(shù)據(jù)集來說,AOF 文件的體積通常要大于 RDB 文件的體積。
根據(jù)所使用的 fsync 策略,AOF 的速度可能會(huì)慢于 RDB 。在一般情況下, 每秒 fsync 的性能依然非常高, 而關(guān)閉 fsync 可以讓 AOF 的速度和 RDB 一樣快, 即使在高負(fù)荷之下也是如此。不過在處理巨大的寫入載入時(shí),RDB 可以提供更有保證的最大延遲時(shí)間(latency)。
四、RDB和AOF的抉擇
1. RDB 和 AOF 對(duì)比
| - | RDB | AOF |
|---|---|---|
| 啟動(dòng)優(yōu)先級(jí) | 低 | 高 |
| 體積 | 小 | 大 |
| 恢復(fù)速度 | 快 | 慢 |
| 數(shù)據(jù)安全性 | 丟數(shù)據(jù) | 根據(jù)策略決定 |
2. 如何選擇使用哪種持久化方式?
一般來說, 如果想達(dá)到足以媲美 PostgreSQL 的數(shù)據(jù)安全性, 你應(yīng)該同時(shí)使用兩種持久化功能。
如果你非常關(guān)心你的數(shù)據(jù), 但仍然可以承受數(shù)分鐘以內(nèi)的數(shù)據(jù)丟失, 那么你可以只使用 RDB 持久化。
有很多用戶都只使用 AOF 持久化, 但并不推薦這種方式:因?yàn)槎〞r(shí)生成 RDB 快照(snapshot)非常便于進(jìn)行數(shù)據(jù)庫備份, 并且 RDB 恢復(fù)數(shù)據(jù)集的速度也要比 AOF 恢復(fù)的速度要快。
source:https://segmentfault.com/a/1190000016021217

掃碼二維碼
獲取更多精彩
Java樂園

