什么叫持久化?
用一句話可以將持久化概括為:將數據(如內存中的對象)保存到可永久保存的存儲設備中。
持久化的主要應用是將內存中的對象存儲在數據庫中,或者存儲在磁盤文件中、 XML 數據文件中等等。
也可以從如下兩個層面來理解持久化:
應用層:如果關閉( Close )你的應用,然后重新啟動則先前的數據依然存在。
系統層:如果關閉( Shut Down )你的系統(電腦),然后重新啟動則先前的數據依然存在。
Redis 為什么要持久化?
Redis 中的數據類型都支持 Push/Pop、Add/Remove 及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。
在此基礎上,Redis 支持各種不同方式的排序。與 Memcached 一樣,為了保證效率,數據都是緩存在內存中。
因為數據都是緩存在內存中的,當你重啟系統或者關閉系統后,緩存在內存中的數據都會消失殆盡,再也找不回來了。
所以,為了讓數據能夠長期保存,就要將 Redis 放在緩存中的數據做持久化存儲。
Redis 怎么實現持久化?
在設計之初,Redis 就已經考慮到了這個問題。官方提供了多種不同級別的數據持久化的方式:
RDB 持久化方式能夠在指定的時間間隔對你的數據進行快照存儲。
AOF 持久化方式記錄每次對服務器寫的操作,當服務器重啟的時候會重新執行這些命令來恢復原始的數據,AOF 命令以 Redis 協議追加保存每次寫的操作到文件末尾。
Redis 還能對 AOF 文件進行后臺重寫,使得 AOF 文件的體積不至于過大。
如果你只希望你的數據在服務器運行的時候存在,你也可以不使用任何持久化方式。
你也可以同時開啟兩種持久化方式,在這種情況下,當 Redis 重啟的時候會優先載入 AOF 文件來恢復原始的數據,因為在通常情況下 AOF 文件保存的數據集要比 RDB 文件保存的數據集要完整。
如果你不知道該選擇哪一個級別的持久化方式,那我們就先來了解一下 AOF 方式和 RDB 方式有什么樣的區別,并且它們各自有何優劣,學習完之后,再來考慮該選擇哪一種級別。
RDB 方式與 AOF 方式的優勢對比
RDB 方式與 AOF 方式的優點對比
首先我們來看一看官方對于兩種方式的優點描述,并做個對比,然后再看一看兩種方式的缺點描述。
RDB 方式的優點:
RDB 是一個非常緊湊的文件,它保存了某個時間點的數據集,非常適用于數據集的備份。
比如你可以在每個小時保存一下過去 24 小時內的數據,同時每天保存過去 30 天的數據,這樣即使出了問題你也可以根據需求恢復到不同版本的數據集。
RDB 是一個緊湊的單一文件,很方便傳送到另一個遠端數據中心,非常適用于災難恢復。
RDB 在保存 RDB 文件時父進程唯一需要做的就是 Fork 出一個子進程,接下來的工作全部由子進程來做,父進程不需要再做其他 IO 操作,所以 RDB 持久化方式可以最大化 Redis 的性能。
與 AOF 相比,在恢復大的數據集的時候,RDB 方式會更快一些。
當 Redis 需要保存 dump.rdb 文件時, 服務器執行以下操作:
Redis 調用 Forks,同時擁有父進程和子進程。
子進程將數據集寫入到一個臨時 RDB 文件中。
當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,并刪除舊的 RDB 文件。
這種工作方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益。
AOF 方式的優點:
使用 AOF 會讓你的 Redis 更加耐久。
你可以使用不同的 Fsync 策略:無 Fsync、每秒 Fsync 、每次寫的時候 Fsync 使用默認的每秒 Fsync 策略。
Redis 的性能依然很好( Fsync 是由后臺線程進行處理的,主線程會盡力處理客戶端請求),一旦出現故障,你最多丟失 1 秒的數據。
AOF文件是一個只進行追加的日志文件,所以不需要寫入 Seek,即使由于某些原因(磁盤空間已滿,寫的過程中宕機等等)未執行完整的寫入命令,你也可使用 redis-check-aof 工具修復這些問題。
Redis 可以在 AOF 文件體積變得過大時,自動地在后臺對 AOF 進行重寫: 重寫后的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。
整個重寫操作是絕對安全的,因為 Redis 在創建新 AOF 文件的過程中,會繼續將命令追加到現有的 AOF 文件里面,即使重寫過程中發生停機,現有的 AOF 文件也不會丟失。
而一旦新 AOF 文件創建完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,并開始對新 AOF 文件進行追加操作。
AOF 文件有序地保存了對數據庫執行的所有寫入操作,這些寫入操作以 Redis 協議的格式保存。
因此 AOF 文件的內容非常容易被人讀懂, 對文件進行分析(parse)也很輕松。導出(export) AOF 文件也非常簡單。
舉個例子,如果你不小心執行了 FLUSHALL 命令,但只要 AOF 文件未被重寫,那么只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令,并重啟 Redis ,就可以將數據集恢復到 FLUSHALL 執行之前的狀態。
優點對比總結:
RDB 方式可以保存過去一段時間內的數據,并且保存結果是一個單一的文件,可以將文件備份到其他服務器,并且在回復大量數據的時候,RDB 方式的速度會比 AOF 方式的回復速度要快。
AOF 方式默認每秒鐘備份 1 次,頻率很高,它的操作方式是以追加的方式記錄日志而不是數據,并且它的重寫過程是按順序進行追加,所以它的文件內容非常容易讀懂。
可以在某些需要的時候打開 AOF 文件對其編輯,增加或刪除某些記錄,最后再執行恢復操作。
RDB 方式與 AOF 方式的缺點對比
RDB 方式的缺點:
如果你希望在 Redis 意外停止工作(例如電源中斷)的情況下丟失的數據最少的話,那么 RDB 不適合你。
雖然你可以配置不同的 Save 時間點(例如每隔 5 分鐘并且對數據集有 100 個寫的操作),但是 Redis 要完整的保存整個數據集是一個比較繁重的工作。
你通常會每隔 5 分鐘或者更久做一次完整的保存,萬一 Redis 意外宕機,你可能會丟失幾分鐘的數據。
RDB 需要經常 Fork 子進程來保存數據集到硬盤上,當數據集比較大的時,Fork 的過程是非常耗時的,可能會導致 Redis 在一些毫秒級內不能響應客戶端的請求。
如果數據集巨大并且 CPU 性能不是很好的情況下,這種情況會持續 1 秒,AOF 也需要 Fork,但是你可以調節重寫日志文件的頻率來提高數據集的耐久度。
AOF 方式的缺點:
對于相同的數據集來說,AOF 文件的體積通常要大于 RDB 文件的體積。
根據所使用的 Fsync 策略,AOF 的速度可能會慢于 RDB。在一般情況下,每秒 Fsync 的性能依然非常高,而關閉 Fsync 可以讓 AOF 的速度和 RDB 一樣快,即使在高負荷之下也是如此。
不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(Latency)。
缺點對比總結:
RDB 由于備份頻率不高,所以在回復數據的時候有可能丟失一小段時間的數據,而且在數據集比較大的時候有可能對毫秒級的請求產生影響。
AOF 的文件提及比較大,而且由于保存頻率很高,所以整體的速度會比 RDB 慢一些,但是性能依舊很高。
RDB 與 AOF 工作原理
AOF 重寫和 RDB 創建快照一樣,都巧妙地利用了寫時復制機制:
Redis 執行 fork() ,現在同時擁有父進程和子進程。
子進程開始將新 AOF 文件的內容寫入到臨時文件。
對于所有新執行的寫入命令,父進程一邊將它們累積到一個內存緩存中,一邊將這些改動追加到現有 AOF 文件的末尾,這樣即使在重寫的中途發生停機,現有的 AOF 文件也還是安全的。
當子進程完成重寫工作時,它給父進程發送一個信號,父進程在接收到信號之后,將內存緩存中的所有數據追加到新 AOF 文件的末尾。
現在 Redis 原子地用新文件替換舊文件,之后所有命令都會直接追加到新 AOF 文件的末尾。
付諸實踐,RDB 與 AOF 的實現
RDB 方式持久化的開啟與配置
Redis 默認的持久化方式是 RDB ,并且默認是打開的。RDB 的保存方式分為主動保存與被動保存。
主動保存可以在 redis-cli 中輸入 Save 即可;被動保存需要滿足配置文件中設定的觸發條件,目前官方默認的觸發條件可以在 redis.conf 中看到:
save 900 1save 300 10save 60 10000
其含義為:
服務器在900秒之內,對數據庫進行了至少1次修改。服務器在300秒之內,對數據庫進行了至少10次修改。服務器在60秒之內,對數據庫進行了至少10000次修改。
滿足觸發條件后,數據就會被保存為快照,正是因為這樣才說 RDB 的數據完整性是比不上 AOF 的。
觸發保存條件后,會在指定的目錄生成一個名為 dump.rdb 的文件,等到下一次啟動 Redis 時,Redis 會去讀取該目錄下的 dump.rdb 文件,將里面的數據恢復到 Redis。
這個目錄在哪里呢?我們可以在客戶端中輸入命令 config get dir 查看:
gannicus@$ src/redis-cli
127.0.0.1:6379> config get dir
1) "dir"
2) "/home/gannicus/Documents/redis-5.0.0"
127.0.0.1:6379>
返回結果中的"/home/gannicus/Documents/redis-5.0.0"就是存放 dump.rdb 的目錄。
在測試之前,說明一下前提:Redis 是直接從官網下載的壓縮包,解壓后得到 redis-x.x.x 文件夾。
比如我的是 redis-5.0.0,然后進入文件夾,在 redis-5.0.0 項目根目錄使用 make 命令安裝。
RDB 被動觸發保存測試
剛才提到它分為主動保存與被動觸發,現在我們來測試一下被動觸發。首先啟動 redis-server,然后再打開客戶端 redis-cli ,先增添幾條記錄:
127.0.0.1:6379> set lca 1OK127.0.0.1:6379> set lcb 1OK127.0.0.1:6379> set lcc 1OK127.0.0.1:6379> set lcd 1OK127.0.0.1:6379> set lce 1OK127.0.0.1:6379> set lcf 1OK127.0.0.1:6379> set lcg 1OK127.0.0.1:6379> set lch 1OK127.0.0.1:6379> set lci 1OK127.0.0.1:6379> set lcj 1OK127.0.0.1:6379> set lck 1OK127.0.0.1:6379> set lcl 1OK127.0.0.1:6379> set lcm 1OK
可以看到,總共添加了 13 條記錄:
127.0.0.1:6379> keys * 1) "lca" 2) "lcd" 3) "lcg" 4) "lce" 5) "lcb" 6) "lcm" 7) "lcf" 8) "lci" 9) "lcl"10) "lcc"11) "lck"12) "lcj"13) "lch"127.0.0.1:6379>
然后發現 redis-server 端的日志窗口中出現了如下的提示:
21971:M 21 Oct 2018 16:52:44.062 * 10 changes in 300 seconds. Saving...21971:M 21 Oct 2018 16:52:44.063 * Background saving started by pid 2255222552:C 21 Oct 2018 16:52:44.066 * DB saved on disk21971:M 21 Oct 2018 16:52:44.165 * Background saving terminated with success
從英文提示中可以大概讀懂這些內容,它檢測到 300 秒內有 10 條記錄被改動,剛才我們添加了 13 條數據記錄,滿足 redis.conf 中對于 RDB 數據保存的條件。
所以這里執行數據保存操作,并且提示開辟了一個 22552 的進程出來執行保存操作,最后提示保存成功。并且在目錄內看到有 dump.rdb 文件生成。
現在將 Redis 進程 Kill,哪些數據會被保存?通過命令 kill -9 pid ( pid 是進程編號)模擬 Redis 異常關閉,然后再啟動 Redis 。
我們來看一看,到底是只保存了 10 條記錄還是 13 條全都保存下來了?
127.0.0.1:6379> keys * 1) "lcb" 2) "lcj" 3) "lcd" 4) "lch" 5) "lci" 6) "lcc" 7) "lcf" 8) "lce" 9) "lca"10) "lcg"127.0.0.1:6379>
重啟后查看記錄,發現 13 條記錄中只有 10 條記錄會被保存,這也印證了之前所說,RDB 方式的數據完整性是不可靠的,除非斷掉的那一刻正好是滿足觸發條件的條數。
關閉 RDB
剛才提到了,它是默認啟用的,如果你不需要它可以在配置文件中將這 3 個配置注釋掉,并新增 save " " 即可:
save ""
# save 900 1
# save 300 10
# save 60 10000
保存配置文件后需要重新啟動 Redis 服務才會生效,然后繼續添加十幾條記錄:
127.0.0.1:6379> keys *
1) "lcb"
...
23) "lca"
24) "lcg"
127.0.0.1:6379>
在之前已有 10 條的基礎上我再增加了 14 條記錄,這次同樣要通過 kill 來模擬 Redis 異常關閉,再啟動服務看一看,數據是否還被保存:
127.0.0.1:6379> keys *
1) "lcb"
2) "lcj"
3) "lcd"
4) "lch"
5) "lci"
6) "lcc"
7) "lcf"
8) "lce"
9) "lca"
10) "lcg"
127.0.0.1:6379>
發現后面添加的 14 條記錄并沒有被保存,恢復數據的時候僅僅只是恢復了之前的 10 條。
并且觀察 Redis 服務端窗口日志,并未發現像之前一樣的觸發保存的提示,證明 RDB 方式已經被關閉。
RDB 主動保存測試
通過配置文件關閉被動觸發,那么主動關閉是否還會生效呢?
在 Redis 客戶端( redis-cli )通過 del 命令刪除幾條記錄,然后輸入 save 命令執行保存操作:
127.0.0.1:6379> keys *
1) "lcc"
2) "lch"
3) "lcb"
4) "lci"
5) "lce"
6) "lcj"
7) "lcg"
8) "lca"
9) "lcd"
10) "lcf"
127.0.0.1:6379> del lca lcb lcc
(integer) 3
127.0.0.1:6379> save
OK
127.0.0.1:6379>
可以看到 redis-server 的日志有新的提示:22598:M 21 Oct 2018 17:22:31.365 * DB saved on disk,它告訴我們數據已經保存。
那么繼續模擬異常關閉,再打開服務,看一看是否真的保存了這些操作:
127.0.0.1:6379> keys *
1) "lci"
2) "lcj"
3) "lcd"
4) "lcg"
5) "lcf"
6) "lce"
7) "lch"
127.0.0.1:6379>
果不其然,這幾個刪除操作都被保存了下來,恢復過來的數據中已經沒有那 3 條記錄了,證明主動關閉不受配置文件的影響。除了 Save 還有其他的保存方式么?
Save 和 Bgsave 保存
有的,Redis 提供了 Save 和 Bgsave 這兩種不同的保存方式,并且這兩個方式在執行的時候都會調用 rdbSave 函數。
但它們調用的方式各有不同:
Save 直接調用 rdbSave方法 ,阻塞 Redis 主進程,直到保存完成為止。在主進程阻塞期間,服務器不能處理客戶端的任何請求。
Bgsave 則 Fork 出一個子進程,子進程負責調用 rdbSave ,并在保存完成之后向主進程發送信號,通知保存已完成。
因為 rdbSave 在子進程被調用,所以 Redis 服務器在 Bgsave 執行期間仍然可以繼續處理客戶端的請求。
Save 是同步操作,Bgsave 是異步操作。Bgsave 命令的使用方法和 Save 命令的使用方法是一樣的:
127.0.0.1:6379> keys *
1) "lci"
2) "lcj"
3) "lcd"
4) "lcg"
5) "lcf"
6) "lce"
7) "lch"
127.0.0.1:6379> del lci lcj
(integer) 2
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> keys *
1) "lcd"
2) "lcg"
3) "lcf"
4) "lce"
5) "lch"
127.0.0.1:6379>
Shutdown 保存
事實上,Shutdown 命令也是可以保存數據的,驚不驚喜。它會在關閉前將數據保存下來,意不意外?
127.0.0.1:6379> set app 1
OK
127.0.0.1:6379> set apps 1
OK
127.0.0.1:6379> keys *
1) "apps"
2) "lcd"
3) "lcg"
4) "lcf"
5) "app"
6) "lce"
7) "lch"
127.0.0.1:6379> shutdown
not connected> quit
gannicus@$
然后 Redis 服務就被關閉掉了。我們需要重新啟動 Redis 服務,到客戶端中看一看是否生效:
gannicus@$ src/redis-cli
127.0.0.1:6379> keys *
1) "lce"
2) "lcf"
3) "lcd"
4) "lch"
5) "lcg"
竟然沒有生效,刺不刺激?這是為什么呢?明明官方文檔之 Shutdown 就說會保存了才退出的,你騙人~注意到,文檔中有一句:
恍然大悟,原來是要在持久化被打開的情況下,通過 Shutdown 命令關閉才不會丟失數據,那么就到配置文件中將那幾個 Save 的配置項打開吧:
# save ""save 900 1
save 300 10
save 60 10000
然后再開啟 Redis 服務,再嘗試一遍(過程為:添加 -> shutdown -> 重啟服務 -> 查看):
127.0.0.1:6379> set app 1
OK
127.0.0.1:6379> set apps 1
OK
127.0.0.1:6379> shutdown
not connected> quit
gannicus@$ src/redis-cli
127.0.0.1:6379> keys *
1) "lce"
2) "lch"
3) "app"
4) "lcf"
5) "apps"
6) "lcd"
7) "lcg"
127.0.0.1:6379>
這下終于弄明白了。
AOF 方式持久化的開啟與配置
開啟 AOF
默認是不開啟 AOF 的,如果想要啟用則需要到 redis.conf 配置文件中開啟,打開 redis.conf:
$ vim redis.conf
然后在文件中找到 appendonly 并將 no 改為 yes:
appendonly yes
即為開啟了 AOF 方式的持久化。
設置同步方式
AOF 還有支持幾種同步方式,它們分別是:
appendfsync always # 每次有數據修改發生時都會寫入AOF文件(安全但是費時)。
appendfsync everysec # 每秒鐘同步一次,該策略為AOF的缺省策略。
appendfsync no # 從不同步。高效但是數據不會被持久化。
默認配置是 everysec,你可以根據需求進行調整,這里我將配置改成 always:
appendfsync always
# appendfsync everysec
# appendfsync no
自定義 AOF 記錄文件的文件名
Redis 設置有默認的文件名,在配置中顯示為:
appendfilename "appendonly.aof"
你可以讓其保持默認名字,也可以指定其他的文件名,比如:
appendfilename "RNGLetme.aof"
將 appendonly、appendfsync 和 appendfilename 設置好并保存。重新啟動 Redis 服務:
$./redis-server
通過命令 ls 查看本地文件,可以看到新生成了一個名為 RNGLetme.aof 的文件,可以使用:
$cat RNGLetme.aof
來查看里面的內容,由于當前未進行數據的改動,所以是空白的。然后打開 Redis 的客戶端:
$./redis-cli
并且添加幾條數據記錄:
127.0.0.1:6379> set rng lpl
OK
127.0.0.1:6379> set ig lpl
OK
127.0.0.1:6379> set edg lpl
OK
127.0.0.1:6379> keys *
1) "edg"
2) "rng"
3) "ig"
127.0.0.1:6379>
可以看到,成功添加了 rng、edg、ig 這三條記錄,然后打開 RNGLetme.aof 文件,看看里面的記錄:
*2
$6
SELECT
$1
0
*3
$3
set
$3
rng
$3
lpl
*3
$3
set
$2
ig
$3
lpl
*3
$3
set
$3
edg
$3
lpl
每一次的數據添加都被記錄下來了。那如果是刪除操作呢,也會被記錄下來么?
127.0.0.1:6379> del edg
(integer) 1
127.0.0.1:6379> keys *
1) "rng"
2) "ig"
127.0.0.1:6379>
執行完刪除操作后,再看一看 RNGLetme.aof 文件中的記錄:
對比之前的記錄,新增了 del edg 的操作記錄。這就印證了之前對 AOF 的描述:以日志的方式將數據變動記錄下來。
AOF 恢復測試
下面同樣是通過 Kill 命令模擬 Redis 異常關閉:
gannicus@$ kill -9 22645
然后再重新啟動 Redis 服務:
$ src/redis-server redis.conf
接著通過客戶端看一看,那些數據是否都在:
$ src/redis-cli
127.0.0.1:6379> keys *
1) "ig"
2) "rng"
可以看到,rng 和 ig 都還在,意味著持久化是生效的。
怎樣從 RDB 方式切換為 AOF 方式
在 Redis 2.2 或以上版本,可以在不重啟的情況下,從 RDB 切換到 AOF :
為最新的 dump.rdb 文件創建一個備份、將備份放到一個安全的地方。
執行以下兩條命令:
redis-cli config set appendonly yes
redis-cli config set save “”
確保寫命令會被正確地追加到 AOF 文件的末尾。執行的第一條命令開啟了 AOF 功能:Redis 會阻塞直到初始 AOF 文件創建完成為止,之后 Redis 會繼續處理命令請求,并開始將寫入命令追加到 AOF 文件末尾。
執行的第二條命令用于關閉 RDB 功能。這一步是可選的,如果你愿意的話,也可以同時使用 RDB 和 AOF 這兩種持久化功能。
注意:別忘了在 redis.conf 中打開 AOF 功能!否則服務器重啟后,之前通過 CONFIG SET 命令設置的配置就會被遺忘,程序會按原來的配置來啟動服務器。
優先選擇 RDB 還是 AOF 呢?
分析對比兩種方式并做了測試后,發現這是兩種不同風格的持久化方式。那么應該如何選擇呢?
對于企業級的中大型應用,如果不想犧牲數據完整性但是又希望保持高效率,那么你應該同時使用 RDB 和 AOF 兩種方式。
如果你不打算耗費精力在這個地方,只需要保證數據完整性,那么優先考慮使用 AOF 方式。
RDB 方式非常適合大規模的數據恢復,如果業務對數據完整性和一致性要求不高,RDB 是很好的選擇。
備份 Redis 數據的建議
確保你的數據有完整的備份,磁盤故障、節點失效等問題可能讓你的數據消失不見, 不進行備份是非常危險的。
Redis 對于數據備份是非常友好的,因為你可以在服務器運行的時候對 RDB 文件進行復制:RDB 文件一旦被創建,就不會進行任何修改。
當服務器要創建一個新的 RDB 文件時,它先將文件的內容保存在一個臨時文件里面,當臨時文件寫入完畢時,程序才使用 rename(2) 原子地用臨時文件替換原來的 RDB 文件。
這也就是說,無論何時,復制 RDB 文件都是絕對安全的:
創建一個定期任務( cron job ),每小時將一個 RDB 文件備份到一個文件夾,并且每天將一個 RDB 文件備份到另一個文件夾。
在此我向大家推薦一個架構學習交流圈:830478757 幫助突破J瓶頸 提升思維能力
確??煺盏膫浞荻紟в邢鄳娜掌诤蜁r間信息,每次執行定期任務腳本時,使用 Find 命令來刪除過期的快照:比如說你可以保留最近 48 小時內的每小時快照,還可以保留最近一兩個月的每日快照。
至少每天一次,將 RDB 備份到你的數據中心之外,或者至少是備份到你運行 Redis 服務器的物理機器之外。
Redis 密碼持久化
在 Redis 中數據需要持久化,密碼也要持久化。在客戶端通過命令:
config set requirepass zxc9527
可以為 Redis 設置值為 zxc9527 的密碼,但是當 Redis 關閉并重新啟動后,權限驗證功能就會失效,再也不需要密碼。
所以,密碼也需要在 redis.conf 中持久化。打開 redis.conf 找到 requirepass 配置項,取消其注釋并在后面設置密碼:
requirepass zxc9527
保存后重啟 Redis 服務,密碼持久化即生效。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。