如果你認為Redis是1個key value store, 那可能會用它來代替MySQL;如果認為它是1個可以持久化的cache, 可能只是它保存1些頻繁訪問的臨時數據。
我們來假想1個問題,通過前面的介紹,我們知道了redis與memcached都可以當作緩存,提高訪問效力,那末如果對突然斷電或其他故障,那末是否是意味著我們的緩存數據要丟失?
redis是1個支持持久化的內存數據庫,也就是說redis需要常常將內存中的數據同步到磁盤來保證持久化。也就是說緩存和我們的數據庫之間有著交互,我們可以把緩存中的數據保存下來這也就是redis比其他緩存強大的地方:持久化。
redis支持兩種持久化方式,1種是 RDB(快照)也是默許方式,另外一種是Append-only file(縮寫aof)的方式。
RDB 持久化可以在指定的時間間隔內生成數據集的時間點快照(point-in-time snapshot)。
AOF 持久化記錄服務器履行的所有寫操作命令,并在服務器啟動時,通太重新履行這些命令來還原數據集。 AOF 文件中的命令全部以 Redis 協議的格式來保存,新命令會被追加到文件的末尾。 Redis 還可以在后臺對 AOF 文件進行重寫(rewrite),使得 AOF 文件的體積不會超越保存數據集狀態所需的實際大小。
Redis 還可以同時使用 AOF 持久化和 RDB 持久化。 在這類情況下, 當 Redis 重啟時, 它會優先使用 AOF 文件來還原數據集, 由于 AOF 文件保存的數據集通常比 RDB 文件所保存的數據集更完全。你乃至可以關閉持久化功能,讓數據只在服務器運行時存在。
快照是默許的持久化方式。這類方式是就是將內存中數據以快照的方式寫入到2進制文件中,默許的文件名為dump.rdb。可以通過配置設置自動做快照持久 化的方式。
我們可以配置redis在n秒內如果超過m個key被修改就自動做快照,下面是默許的快照保存配置
save 900 1 #900秒內如果超過1個key被修改,則發起快照保存
save 300 10 #300秒內容如超過10個key被修改,則發起快照保存
save 60 10000
在默許情況下, Redis 將數據庫快照保存在名字為 dump.rdb 的2進制文件中。你可以對 Redis 進行設置, 讓它在“ N 秒內數據集最少有 M 個改動”這1條件被滿足時, 自動保存1次數據集。
你也能夠通過調用 SAVE 或 BGSAVE , 手動讓 Redis 進行數據集保存操作。比如說, 以下設置會讓 Redis 在滿足“ 60 秒內有最少有 1000 個鍵被改動”這1條件時, 自動保存1次數據集:
save 60 1000
當 Redis 需要保存 dump.rdb 文件時, 服務器履行以下操作:
Redis 調用 fork() ,同時具有父進程和子進程。
子進程將數據集寫入到1個臨時 RDB 文件中。
當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,并刪除舊的 RDB 文件。
這類工作方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益。
只進行追加操作的文件(append-only file,AOF)
從 1.1 版本開始, Redis 增加了1種完全耐久的持久化方式: AOF 持久化。
你可以通過修改配置文件來打開 AOF 功能:
appendonly yes
從現在開始, 每當 Redis 履行1個改變數據集的命令時(比如 SET), 這個命令就會被追加到 AOF 文件的末尾。
這樣的話, 當 Redis 重新啟時, 程序就能夠通太重新履行 AOF 文件中的命令來到達重建數據集的目的。
另外一點需要注意的是,每次快照持久化都是將內存數據完全寫入到磁盤1次,其實不 是增量的只同步臟數據。如果數據量大的話,而且寫操作比較多,必定會引發大量的磁盤io操作,可能會嚴重影響性能。
另外由于快照方式是在1定間隔時間做1次的,所以如果redis意外down掉的話,就會丟失最后1次快照后的所有修改。如果利用要求不能丟失任何修改的話,可以采取aof持久化方式.
aof 比快照方式有更好的持久化性,是由于在使用aof持久化方式時,redis會將每個收到的寫命令都通過write函數追加到文件中(默許是 appendonly.aof)。
當redis重啟時會通太重新履行文件中保存的寫命令來在內存中重建全部數據庫的內容。固然由于os會在內核中緩存 write做的修改,所以可能不是立即寫到磁盤上。這樣aof方式的持久化也還是有可能會丟失部份修改。
不過我們可以通過配置文件告知redis我們想要 通過fsync函數強迫os寫入到磁盤的時機。有3種方式以下(默許是:每秒fsync1次)
# appendfsync always //每次收到寫命令就立即強迫寫入磁盤,最慢的,但是保證完全的持久化,不推薦使用
appendfsync everysec //每秒鐘強迫寫入磁盤1次,在性能和持久化方面做了很好的折衷,推薦
# appendfsync no //完全依賴os,性能最好,持久化沒保證
具體進程以下
1. redis調用fork ,現在有父子兩個進程
2. 子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令
3.父進程繼續處理client要求,除把寫命令寫入到原來的aof文件中。同時把收到的寫命令緩存起來。這樣就可以保證如果子進程重寫失敗的話其實不會出問題。
4.當子進程把快照內容寫入已命令方式寫到臨時文件中后,子進程發信號通知父進程。然后父進程把緩存的寫命令也寫入到臨時文件。
5.現在父進程可使用臨時文件替換老的aof文件,并重命名,后面收到的寫命令也開始往新的aof文件中追加。
需要注意到是重寫aof文件的操作,并沒有讀取舊的aof文件,而是將全部內存中的數據庫內容用命令的方式重寫了1個新的aof文件,這點和快照有點類似。
安裝Redis以后,我們會發現redis.conf文件,在這里面我們可以設置以上兩種持久化方式。
RDB 是1個非常緊湊(compact)的文件,它保存了 Redis 在某個時間點上的數據集。 這類文件非常合適用于進行備份: 比如說,你可以在最近的 24 小時內,每小時備份1次 RDB 文件,并且在每月的每天,也備份1個 RDB 文件。
這樣的話,即便遇上問題,也能夠隨時將數據集還原到不同的版本。RDB 非常適用于災害恢復(disaster recovery):它只有1個文件,并且內容都非常緊湊,可以(在加密后)將它傳送到別的數據中心,或亞馬遜 S3 中。
RDB 可以最大化 Redis 的性能:父進程在保存 RDB 文件時唯1要做的就是 fork 出1個子進程,然后這個子進程就會處理接下來的所有保存工作,父進程不必履行任何磁盤 I/O 操作。RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。
如果你需要盡可能避免在服務器故障時丟失數據,那末 RDB 不合適你。 雖然 Redis 允許你設置不同的保存點(save point)來控制保存 RDB 文件的頻率, 但是, 由于RDB 文件需要保存全部數據集的狀態, 所以它其實不是1個輕松的操作。 因此你可能會最少 5 分鐘才保存1次 RDB 文件。
在這類情況下, 1旦產生故障停機, 你便可能會丟失好幾分鐘的數據。每次保存 RDB 的時候,Redis 都要 fork() 出1個子進程,并由子進程來進行實際的持久化工作。
在數據集比較龐大時, fork() 可能會非常耗時,造成服務器在某某毫秒內停止處理客戶端; 如果數據集非常巨大,并且 CPU 時間非常緊張的話,那末這類停止時間乃至可能會長達整整1秒。 雖然 AOF 重寫也需要進行 fork() ,但不管 AOF 重寫的履行間隔有多長,數據的耐久性都不會有任何損失。
使用 AOF 持久化會讓 Redis 變得非常耐久(much more durable):你可以設置不同的 fsync 策略,比如無 fsync ,每秒鐘1次 fsync ,或每次履行寫入命令時 fsync 。
AOF 的默許策略為每秒鐘 fsync 1次,在這類配置下,Redis 依然可以保持良好的性能,并且就算產生故障停機,也最多只會丟失1秒鐘的數據( fsync 會在后臺線程履行,所以主線程可以繼續努力地處理命令要求)。
AOF 文件是1個只進行追加操作的日志文件(append only log), 因此對 AOF 文件的寫入不需要進行 seek , 即便日志由于某些緣由而包括了未寫入完全的命令(比如寫入時磁盤已滿,寫入中途停機,等等), redis-check-aof 工具也能夠輕易地修復這類問題。
Redis 可以在 AOF 文件體積變得過大時,自動地在后臺對 AOF 進行重寫: 重寫后的新 AOF 文件包括了恢復當前數據集所需的最小命令集合。 全部重寫操作是絕對安全的,由于 Redis 在創建新 AOF 文件的進程中,會繼續將命令追加到現有的 AOF 文件里面,即便重寫進程中產生停機,現有的 AOF 文件也不會丟失。 而1旦新 AOF 文件創建終了,Redis 就會從舊 AOF 文件切換到新 AOF 文件,并開始對新 AOF 文件進行追加操作。
AOF 文件有序地保存了對數據庫履行的所有寫入操作, 這些寫入操作以 Redis 協議的格式保存, 因此 AOF 文件的內容非常容易被人讀懂, 對文件進行分析(parse)也很輕松。 導出(export) AOF 文件也非常簡單: 舉個例子, 如果你不謹慎履行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那末只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重啟 Redis , 就能夠將數據集恢復到 FLUSHALL 履行之前的狀態。
對相同的數據集來講,AOF 文件的體積通常要大于 RDB 文件的體積。根據所使用的 fsync 策略,AOF 的速度可能會慢于 RDB 。
在1般情況下, 每秒 fsync 的性能仍然非常高, 而關閉 fsync 可讓 AOF 的速度和 RDB 1樣快, 即便在高負荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(latency)。
AOF 在過去曾產生過這樣的 bug : 由于個別命令的緣由,致使 AOF 文件在重新載入時,沒法將數據集恢復成保存時的原樣。 (舉個例子,阻塞命令 BRPOPLPUSH 就曾引發過這樣的 bug 。) 測試套件里為這類情況添加了測試: 它們會自動生成隨機的、復雜的數據集, 并通太重新載入這些數據來確保1切正常。 雖然這類 bug 在 AOF 文件中其實不常見, 但是對照來講, RDB 幾近是不可能出現這類 bug 的。
1般來講,如果想到達足以媲美 PostgreSQL 的數據安全性, 你應當同時使用兩種持久化功能。如果你非常關心你的數據,但依然可以承受數分鐘之內的數據丟失, 那末你可以只使用 RDB 持久化。有很多用戶都只使用 AOF 持久化, 但我們其實不推薦這類方式: 由于定時生成 RDB 快照(snapshot)非常便于進行數據庫備份, 并且 RDB 恢復數據集的速度也要比 AOF 恢復的速度要快, 除此以外, 使用 RDB 還可以免之條件到的 AOF 程序的 bug 。
下一篇 C語言運算符與表達式