閱讀本文大概須要 20 分鐘。redis
Redis 是一個開源( BSD 許可)的,內存中的數據結構存儲系統,它能夠用做數據庫、緩存和消息中間件。它支持的數據類型很豐富,如字符串、鏈表、集 合、以及散列等,而且還支持多種排序功能。
數據庫
用一句話能夠將持久化歸納爲:將數據(如內存中的對象)保存到可永久保存的存儲設備中。持久化的主要應用是將內存中的對象存儲在數據庫中,或者存儲在磁盤文件中、 XML 數據文件中等等。vim
從應用層與系統層理解持久化緩存
同時,也能夠從應用層和系統層這兩個層面來理解持久化:安全
應用層:若是關閉( Close
)你的應用而後從新啓動則先前的數據依然存在。服務器
系統層:若是關閉( Shutdown
)你的系統(電腦)而後從新啓動則先前的數據依然存在。數據結構
Redis 中的數據類型都支持 push/pop、add/remove 及取交集並集和差集及更豐富的操做,並且這些操做都是原子性的。在此基礎上,Redis 支持各類不一樣方式的排序。與 Memcached 同樣,爲了保證效率,數據都是緩存在內存中。app
對,數據都是緩存在內存中的,當你重啓系統或者關閉系統後,緩存在內存中的數據都會消失殆盡,再也找不回來了。因此,爲了讓數據可以長期保存,就要將 Redis 放在緩存中的數據作持久化存儲。異步
在設計之初,Redis 就已經考慮到了這個問題。官方提供了多種不一樣級別的數據持久化的方式:ide
一、RDB持久化方式可以在指定的時間間隔能對你的數據進行快照存儲。
二、AOF持久化方式記錄每次對服務器寫的操做,當服務器重啓的時候會從新執行這些命令來恢復原始的數據,AOF命令以redis協議追加保存每次寫的操做到文件末尾.Redis還能對AOF文件進行後臺重寫,使得AOF文件的體積不至於過大。
三、若是你只但願你的數據在服務器運行的時候存在,你也能夠不使用任何持久化方式。
四、你也能夠同時開啓兩種持久化方式, 在這種狀況下, 當redis重啓的時候會優先載入AOF文件來恢復原始的數據,由於在一般狀況下AOF文件保存的數據集要比RDB文件保存的數據集要完整。
若是你不知道該選擇哪個級別的持久化方式,那咱們就先來了解一下 AOF 方式和 RDB 方式有什麼樣的區別,而且它們各自有何優劣,學習完以後,再來考慮該選擇哪種級別。
首先咱們來看一看官方對於兩種方式的優勢描述,並作個對比,而後再看一看兩種方式的缺點描述。
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 方式的缺點
若是你但願在 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 慢一些,可是性能依舊很高。
AOF 重寫和 RDB 建立快照同樣,都巧妙地利用了寫時複製機制:
Redis 執行 fork() ,如今同時擁有父進程和子進程。
子進程開始將新 AOF 文件的內容寫入到臨時文件。
對於全部新執行的寫入命令,父進程一邊將它們累積到一個內存緩存中,一邊將這些改動追加到現有 AOF 文件的末尾,這樣樣即便在重寫的中途發生停機,現有的 AOF 文件也仍是安全的。
當子進程完成重寫工做時,它給父進程發送一個信號,父進程在接收到信號以後,將內存緩存中的全部數據追加到新 AOF 文件的末尾。
如今 Redis 原子地用新文件替換舊文件,以後全部命令都會直接追加到新 AOF 文件的末尾。
Redis 默認的持久化方式是 RDB ,而且默認是打開的。
RDB 的保存有方式分爲主動保存與被動保存。主動保存能夠在 redis-cli 中輸入 save
便可;被動保存須要知足配置文件中設定的觸發條件,目前官方默認的觸發條件能夠在 redis.conf
中看到:
save 900 1 save 300 10 save 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
是直接從官網下載的壓縮包,解壓後獲得的 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 1 OK 127.0.0.1:6379> set lcb 1 OK 127.0.0.1:6379> set lcc 1 OK 127.0.0.1:6379> set lcd 1 OK 127.0.0.1:6379> set lce 1 OK 127.0.0.1:6379> set lcf 1 OK 127.0.0.1:6379> set lcg 1 OK 127.0.0.1:6379> set lch 1 OK 127.0.0.1:6379> set lci 1 OK 127.0.0.1:6379> set lcj 1 OK 127.0.0.1:6379> set lck 1 OK 127.0.0.1:6379> set lcl 1 OK 127.0.0.1:6379> set lcm 1 OK
能夠看到,總共添加了 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 22552 22552:C 21 Oct 2018 16:52:44.066 * DB saved on disk 21971: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 的,若是想要啓用則須要到 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
文件中的記錄:
*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 *2 $3 del $3 edg
對比以前的記錄,新增了del edg
的操做記錄。這就印證了以前對 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
都還在,意味着持久化是生效的。
在 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 兩種方式;
若是你不打算耗費精力在這個地方,只須要保證數據完整性,那麼優先考慮使用 AOF 方式;
RDB 方式很是適合大規模的數據恢復,若是業務對數據完整性和一致性要求不高,RDB是很好的選擇。
確保你的數據有完整的備份,磁盤故障、節點失效等問題問題可能讓你的數據消失不見, 不進行備份是很是危險的。
Redis 對於數據備份是很是友好的, 由於你能夠在服務器運行的時候對 RDB 文件進行復制: RDB 文件一旦被建立, 就不會進行任何修改。 當服務器要建立一個新的 RDB 文件時, 它先將文件的內容保存在一個臨時文件裏面, 當臨時文件寫入完畢時, 程序才使用 rename(2)
原子地用臨時文件替換原來的 RDB 文件。
這也就是說,不管什麼時候,複製 RDB 文件都是絕對安全的。
建立一個按期任務( cron job ), 每小時將一個 RDB 文件備份到一個文件夾, 而且天天將一個 RDB 文件備份到另外一個文件夾。
確保快照的備份都帶有相應的日期和時間信息, 每次執行按期任務腳本時, 使用 find
命令來刪除過時的快照: 好比說, 你能夠保留最近 48 小時內的每小時快照, 還能夠保留最近一兩個月的每日快照。
至少天天一次, 將 RDB 備份到你的數據中心以外, 或者至少是備份到你運行 Redis 服務器的物理機器以外。
在 Redis 中數據須要持久化,密碼也要持久化。在客戶端經過命令:
config set requirepass zxc9527
能夠爲 Redis 設置值爲zxc9527
的密碼,可是當 Redis 關閉並從新啓動後,權限驗證功能就會失效,不再須要密碼。因此,密碼也須要在 redis.conf
中持久化。打開 redis.conf
找到 requirepass
配置項,取消其註釋並在後面設置密碼:
requirepass zxc9527
保存後重啓 Redis 服務,密碼持久化即生效。