Redis
的強勁性能很大程度上是由于其將所有數(shù)據(jù)都存儲在了內(nèi)存中,為了使
Redis數(shù)據(jù)庫
在重啟之后仍能保證數(shù)據(jù)不丟失,需要將數(shù)據(jù)從內(nèi)存中以某種形式同步到硬盤中,這一過程就是持久化。
Redis
支持兩種方式的持久化,一種是
RDB
方式,一種是
AOF
方式。可以單獨使用其中一種或?qū)⒍呓Y(jié)合使用。
1、RDB方式
RDB
方式的持久化是通過快照(
snapshotting
)完成的,當(dāng)符合一定條件時
Redis
會自動將內(nèi)存中的所有數(shù)據(jù)進(jìn)行快照并存儲在硬盤上。進(jìn)行快照的條件可以由用戶在配置文件中自定義,由兩個參數(shù)構(gòu)成:時間和改動的鍵的個數(shù)。當(dāng)在指定的時間內(nèi)被更改的鍵的個數(shù)大于指定的數(shù)值時就會進(jìn)行快照。
RDB
是
Redis
默認(rèn)采用的持久化方式,在配置文件中已經(jīng)預(yù)置了
3
個條件:
**save 900 1
save 300 10
save 60 10000**
save
參數(shù)指定了快照條件,可以存在多個條件,條件之間是
“
或
”
的關(guān)系。如上所說,
save900 1
的意思是在
15
分鐘(
900
秒鐘)內(nèi)有至少一個鍵被更改則進(jìn)行快照。如果想要禁用自動快照,只需要將所有的
save
參數(shù)刪除即可。
Redis
默認(rèn)會將快照文件存儲在當(dāng)前目錄的
dump.rdb
文件中,可以通過配置
dir
和
dbfilename
兩個參數(shù)分別指定快照文件的存儲路徑和文件名。
理清Redis
實現(xiàn)快照的過程對我們了解快照文件的特性有很大的幫助??煺盏倪^程如下。
(1
)
Redis
使用
fork
函數(shù)復(fù)制一份當(dāng)前進(jìn)程(父進(jìn)程)的副本(子進(jìn)程);
?。?/span>2
)父進(jìn)程繼續(xù)接收并處理客戶端發(fā)來的命令,而子進(jìn)程開始將內(nèi)存中的數(shù)據(jù)寫入硬盤中
的臨時文件;
(3
)當(dāng)子進(jìn)程寫入完所有數(shù)據(jù)后會用該臨時文件替換舊的
RDB
文件,至此一次快照操作完成。
在執(zhí)行fork
的時候操作系統(tǒng)(類
Unix
操作系統(tǒng))會使用寫時復(fù)制(
copy-on-write
)策略,即
fork
函數(shù)發(fā)生的一刻父子進(jìn)程共享同一內(nèi)存數(shù)據(jù),當(dāng)父進(jìn)程要更改其中某片數(shù)據(jù)時(如執(zhí)行一個寫命令),操作系統(tǒng)會將該片數(shù)據(jù)復(fù)制一份以保證子進(jìn)程的數(shù)據(jù)不受影響,所以新的
RDB
文件存儲的是執(zhí)行
fork
一刻的內(nèi)存數(shù)據(jù)。
通過上述過程可以發(fā)現(xiàn)Redis
在進(jìn)行快照的過程中不會修改
RDB
文件,只有快照結(jié)束后才會將舊的文件替換成新的,也就是說任何時候
RDB
文件都是完整的。這使得我們可以通過定時備份
RDB
文件來實現(xiàn)
Redis
數(shù)據(jù)庫備份。
RDB
文件是經(jīng)過壓縮(可以配置
rdbcompression
參數(shù)以禁用壓縮節(jié)省
CPU
占用)的二進(jìn)制格式,所以占用的空間會小于內(nèi)存中的數(shù)據(jù)大小,更加利于傳輸。
除了自動快照,還可以手動發(fā)送SAVE
或
BGSAVE
命令讓
Redis
執(zhí)行快照,兩個命令的區(qū)別在于,前者是由主進(jìn)程進(jìn)行快照操作,會阻塞住其他請求,后者會通過
fork
子進(jìn)程進(jìn)行快照操作。
Redis
啟動后會讀取
RDB
快照文件,將數(shù)據(jù)從硬盤載入到內(nèi)存。根據(jù)數(shù)據(jù)量大小與結(jié)構(gòu)和服務(wù)器性能不同,這個時間也不同。通常將一個記錄一千萬個字符串類型鍵、大小為
1GB
的快照文件載入到內(nèi)存中需要花費
20
~
30
秒鐘。
通過RDB
方式實現(xiàn)持久化,一旦
Redis
異常退出,就會丟失最后一次快照以后更改的所有數(shù)據(jù)。這就需要開發(fā)者根據(jù)具體的應(yīng)用場合,通過組合設(shè)置自動快照條件的方式來將可能發(fā)生的數(shù)據(jù)損失控制在能夠接受的范圍。如果數(shù)據(jù)很重要以至于無法承受任何損失,則可以考慮使用
AOF
方式進(jìn)行持久化。
2、AOF方式
默認(rèn)情況下Redis
沒有開啟
AOF
(
append only file
)方式的持久化,可以通過
appendonly
參數(shù)開啟:
appendonly yes
開啟AOF
持久化后每執(zhí)行一條會更改
Redis
中的數(shù)據(jù)的命令,
Redis
就會將該命令寫入硬盤中的
AOF
文件。
AOF
文件的保存位置和
RDB
文件的位置相同,都是通過
dir
參數(shù)設(shè)置的,默認(rèn)的文件名是
appendonly.aof
,可以通過
appendfilename
參數(shù)修改:
appendfilename appendonly.aof
下面講解AOF
持久化的具體實現(xiàn),假設(shè)在開啟
AOF
持久化的情況下執(zhí)行了如下
4
個命令:
SET foo 1
SET foo 2
SET foo 3
GET foo
Redis
會將前
3
條命令寫入
AOF
文件中,此時
AOF
文件中的內(nèi)容如下:
?。?/span>2
6
SELECT
1
0
*3
3
set
3
foo
1
1
?。?/span>3
3
set
3
foo
1
2
?。?/span>3
3
set
3
foo
1
3
可見AOF
文件是純文本文件,其內(nèi)容正是
Redis
客戶端向
Redis
發(fā)送的原始通信協(xié)議的內(nèi)容(
Redis
的通信協(xié)議會在
7.4
節(jié)中介紹,為了便于閱讀,這里將實際的命令部分以粗體顯示),從中可見
Redis
確實只記錄了前
3
條命令。然而這時有一個問題是前
2
條命令其實都是冗余的,因為這兩條的執(zhí)行結(jié)果會被第三條命令覆蓋。隨著執(zhí)行的命令越來越多,
AOF
文件的大小也會越來越大,即使內(nèi)存中實際的數(shù)據(jù)可能并沒有多少。很自然地,我們希望
Redis
可以自動優(yōu)化
AOF
文件,就上例而言,就是將前兩條無用的記錄刪除,只保留第三條。實際上
Redis
也正是這樣做的,每當(dāng)達(dá)到一定條件時
Redis
就會自動重寫
AOF
文件,這個條件可以在配置文件中設(shè)置:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage
參數(shù)的意義是當(dāng)目前的
AOF
文件大小超過上一次重寫時的
AOF
文件大小的百分之多少時會再次進(jìn)行重寫,如果之前沒有重寫過,則以啟動時的
AOF
文件大小為依據(jù)。
auto-aof-rewrite-min-size
參數(shù)限制了允許重寫的最小
AOF
文件大小,通常在
AOF
文件很小的情況下即使其中有很多冗余的命令我們也并不太關(guān)心。除了讓
Redis
自動執(zhí)行重寫外,我們還可以主動使用
BGREWRITEAOF
命令手動執(zhí)行
AOF
重寫。
上例中的AOF
文件重寫后的內(nèi)容為:
?。?/span>2
6
SELECT
1
0
?。?/span>3
3
SET
3
foo
1
3
可見冗余的命令已經(jīng)被刪除了。重寫的過程只和內(nèi)存中的數(shù)據(jù)有關(guān),和之前的AOF
文件無關(guān),這與
RDB
很相似,只不過二者的文件格式完全不同。
在啟動時Redis
會逐個執(zhí)行
AOF
文件中的命令來將硬盤中的數(shù)據(jù)載入到內(nèi)存中,載入的速度相較
RDB
會慢一些。需要注意的是雖然每次執(zhí)行更改數(shù)據(jù)庫內(nèi)容的操作時,
AOF
都會將命令記錄在
AOF
文件中,但是事實上,由于操作系統(tǒng)的緩存機制,數(shù)據(jù)并沒有真正地寫入硬盤,而是進(jìn)入了系統(tǒng)的硬盤緩存。在默認(rèn)情況下系統(tǒng)每
30
秒會執(zhí)行一次同步操作,以便將硬盤緩存中的內(nèi)容真正地
寫入硬盤,在這30
秒的過程中如果系統(tǒng)異常退出則會導(dǎo)致硬盤緩存中的數(shù)據(jù)丟失。一般來講啟用
AOF
持久化的應(yīng)用都無法容忍這樣的損失,這就需要
Redis
在寫入
AOF
文件后主動要求系統(tǒng)將緩存內(nèi)容同步到硬盤中。在
Redis
中我們可以通過
appendfsync
參數(shù)設(shè)置同步的時機:
# appendfsync always
appendfsync everysec
# appendfsync no
默認(rèn)情況下Redis
采用
everysec
規(guī)則,即每秒執(zhí)行一次同步操作。
always
表示每次執(zhí)行寫入都會執(zhí)行同步,這是最安全也是最慢的方式。
no
表示不主動進(jìn)行同步操作,而是完全交由操作系統(tǒng)來做(即每
30
秒一次),這是最快但最不安全的方式。一般情況下使用默認(rèn)值
everysec
就足夠了,既兼顧了性能又保證了安全。
Redis
允許同時開啟
AOF
和
RDB
,既保證了數(shù)據(jù)安全又使得進(jìn)行備份等操作十分容易。此時重新啟動
Redis
后
Redis
會使用
AOF
文件來恢復(fù)數(shù)據(jù),因為
AOF
方式的持久化可能丟失的數(shù)據(jù)更少。
來源:CSDN