配置方案:Redis持久化RDB和AOF

安全劍客發表於2019-02-19
Redis持久化方案

Redis是記憶體資料庫,資料都是儲存在記憶體中,為了避免程式退出導致資料的永久丟失,需要定期將Redis中的資料以某種形式(資料或命令)從記憶體儲存到硬碟。當下次Redis重啟時,利用持久化檔案實現資料恢復。除此之外,為了進行災難備份,可以將持久化檔案複製到一個遠端位置。

Redis提供了多種不同級別的持久化方式:一種是RDB,另一種是AOF。

RDB持久化可以在指定的時間間隔內生成資料集的時間點快照(point-in-time snapshot),將資料庫的快照(snapshot)以二進位制的方式儲存到磁碟中。

AOF持久化記錄伺服器執行的所有更改操作命令,AOF檔案中的命令全部以Redis協議的格式來儲存,新命令會被追加到檔案的末尾。Redis還可以在後臺對AOF檔案進行重寫(rewrite),使得AOF檔案的體積不會超出儲存資料集狀態所需的實際大小。

Redis可以同時使用AOF持久化和RDB持久化。在這種情況下,當Redis重啟時,它會優先使用AOF檔案來還原資料集,因為AOF檔案儲存的資料集通常比RDB檔案所儲存的資料集更完整。你甚至可以關閉持久化功能,讓資料只在伺服器執行時存在。

瞭解RDB持久化和AOF持久化之間的異同是非常重要的,以下幾個小節將詳細地介紹這這兩種持久化功能,並對它們的相同和不同之處進行說明。

RDB快照

下面我們說一下Redis的第一個持久化策略,RDB快照。Redis支援將當前記憶體資料的快照存成一個資料檔案的持久化機制,而一個持續寫入的資料庫如何生成快照呢?Redis巧妙地藉助了fork命令的寫時複製(copy on write)機制,將當前程式fork出一個子程式,子程式根據記憶體快照,迴圈將資料持久化為RDB檔案。

在預設情況下, Redis將資料庫快照儲存在根目錄下,名字為dump.rdb的二進位制檔案中。可透過引數dir配置指定儲存目錄,dbfilename指定檔名。你可以對Redis進行設定,如“save N M”,表示N秒內資料項中有M個改動時這一條件被滿足時,自動儲存一次資料集。比如你可以配置當10分鐘以內有100次寫入就生成快照,也可以配置當1分鐘內有1000次寫入就生成快照,支援可以多個規則一起生效,當匹配到哪個就哪個規則生效。這些規則的定義就在Redis的配置檔案中,你也可以透過Redis的CONFIG SET命令在Redis執行時設定規則,不需要重啟Redis。

比如說,以下設定會讓Redis在滿足“60秒內有至少有1000個鍵被改動”這一條件時,自動儲存一次資料集:

save 60 1000

你也可以透過呼叫SAVE或者BGSAVE,手動讓Redis進行資料集儲存操作。SAVE命令執行一個同步操作,以RDB檔案的方式儲存所有資料的快照,很少在生產環境直接使用SAVE命令,因為它會阻塞所有的客戶端的請求,不要在生產環境使用,可以使用BGSAVE命令代替。BGSAVE命令執行過程中是透過fork一個子程式來完成的,所以不會阻塞客戶端請求,只有fork子程式時會阻塞伺服器。另外,在自動觸發RDB持久化時,Redis也會選擇BGSAVE而不是SAVE來進行持久化。

Redis自動RDB持久化在其內部是透過serverCron週期性操作函式、dirty計數器、和lastsave時間戳來實現的。其中serverCron每100ms執行一次,檢查伺服器狀態,其中就包括檢查“save N M”是否滿足條件,如果滿足就執行BGSAVE;當然也包括AOF重寫檢查。dirty計數器是Redis伺服器維持的一個狀態,記錄了上一次執行BGSAVE/SAVE命令後,伺服器狀態進行了多少次修改(包括增刪改),而當BGSAVE/SAVE執行完成後,會將dirty重新置為0。lastsave時間戳也是Redis伺服器維持的一個狀態,記錄的是上一次成功執行BGSAVE/SAVE的時間,當前時間減去lastsave需滿足M。

除了手動和自動以外,還有一些其他情況會觸發BGSAVE:

在主從複製場景下,如果從節點執行全量複製操作,則主節點會執行BGSAVE命令,並將rdb檔案傳送給從節點。
執行shutdown命令時,自動執行rdb持久化。
另外需要了解的,因為其寫操作是在一個新程式中進行的,當生成一個新的RDB檔案時,Redis生成的子程式會先將資料寫到一個臨時檔案中,然後透過原子性rename系統呼叫將臨時檔案重新命名為RDB檔案,這樣在任何時候出現故障,Redis的RDB檔案都總是可用的。

這種持久化方式被稱為快照(snapshot)。但是,我們可以很明顯的看到,RDB有他的不足,就是一旦資料庫出現問題,那麼我們的RDB檔案中儲存的資料並不是全新的,從上次RDB檔案生成到Redis停機這段時間的資料全部丟掉了。在某些業務下,如果可以忍受間隔內資料丟失,我們也推薦這些業務使用RDB的方式進行持久化,因為開啟RDB的代價並不高。但是對於另外一些對資料安全性要求極高的應用,無法容忍資料丟失的應用,RDB就無能為力了,所以Redis引入了另一個重要的持久化機制,AOF日誌方式持久化。

為了儘可能使RDB檔案體積減小,Redis預設採用LZF演算法對RDB檔案進行壓縮。雖然壓縮耗時,但是可以大大減小RDB檔案的體積,因此壓縮預設開啟,引數為rdbcompression。需要注意的是,RDB檔案的壓縮並不是針對整個檔案進行的,而是對資料庫中的字串進行的,且只有在字串達到一定長度(20位元組)時才會進行。

除了壓縮,你也可以檢驗RDB檔案,透過引數rdbchecksum設定,預設為yes。在寫入檔案和讀取檔案時都起作用,關閉checksum在寫入檔案和啟動檔案時大約能帶來10%的效能提升,但是資料損壞時無法發現。

另外,當bgsave出現錯誤時,Redis是否停止執行寫命令。Redis提供了一個引數stop-writes-on-bgsave-error,設定為yes,則當硬碟出現問題時,可以及時發現,避免資料的大量丟失;設定為no,則Redis無視bgsave的錯誤繼續執行寫命令,當對Redis伺服器的系統(尤其是硬碟)使用了監控時,該選項考慮設定為no。

說說FORK的開銷?

父程式透過fork操作可以建立子程式,第一代Unix系統實現了一種傻瓜式的程式建立:當執行fork系統呼叫時,核心複製父程式的整個使用者空間並把複製得到的那一份分配給子程式。這種行為時非常耗時的,因為它需要完成以下幾項任務:為子程式的頁表分配頁面、為子程式的頁分配頁面、初始化子程式的頁表、把父程式的頁複製到子程式對應的頁中。

現在 的fork()使用寫時複製(copy-on-write)頁實現。寫時複製是一種可以推遲甚至免除複製資料的技術。核心此時並不複製整個程式地址空間,而是讓父程式和子程式共享同一個複製。只有在需要寫入的時候,資料才會被複制,從而使各個程式擁有各自的複製。也就是說,資源的複製只有在需要寫入的時候才進行,在此之前,只是以只讀方式共享。這種技術使地址空間上的頁的複製被推遲到實際發生寫入的時候。所以就算fork很大記憶體的程式,對記憶體的消耗和耗時都很小。

現在雖然fork時,子程式不會複製父程式的資料空間,但是會複製記憶體頁表(頁表相當於記憶體的索引、目錄);父程式的資料空間越大,記憶體頁表越大,fork時複製耗時也會越多。這個問題也是導致Redis記憶體不宜過大的原因之一,當然還有導致故障恢復時間延長也是Redis記憶體不宜過大的原因。

AOF日誌

透過上面的分析,我們知道RDB快照有大機率丟失最近寫入、且仍未儲存到快照中的那些資料。儘管對於某些程式來說,資料安全並不是最重要的考慮因素,但是對於那些追求資料安全的程式來說,快照功能就不太適用了。從1.1版本開始,Redis增加了一種實時性更好的持久化方式,即AOF持久化。AOF日誌的全稱是append only file,從名字上我們就能看出來,它是一個追加寫入的日誌檔案。與RDB相比,AOF的實時性更好,因此已成為主流的持久化方案。

AOF檔案與MySQL資料庫的binlog不同的是,AOF是一種純文字格式,具有相容性好、可讀性強、容易處理、操作簡單避免二次開銷等優點,它記錄的內容就是一個個的Redis標準命令。開啟AOF持久化命令如下:

appendonly yes
appendfilename "appendonly.aof"

從現在開始,每當Redis執行一個改變資料集的命令時(比如SET),這個命令就會被追加到AOF檔案的末尾。這樣的話,當Redis重新啟時,程式就可以透過重新執行AOF檔案中的命令來達到重建資料集的目的。

由於需要記錄Redis的每條寫命令,因此AOF不需要觸發,下面介紹AOF的執行流程:

命令追加(append)

Redis先將寫命令追加到緩衝區,而不是直接寫入檔案,主要是為了避免每次有寫命令都直接寫入硬碟,導致硬碟IO成為Redis負載的瓶頸。

檔案寫入(write)和檔案同步(sync)

Redis提供了多種AOF快取區的同步檔案策略,策略涉及到作業系統的write函式和fsync函式,說明如下:

為了提高檔案寫入效率,在現代作業系統中,當使用者呼叫write函式將資料寫入檔案時,作業系統通常會將資料暫存到一個記憶體緩衝區裡,當緩衝區被填滿或超過了指定時限後,才真正將緩衝區的資料寫入到硬碟裡。這樣的操作雖然提高了效率,但也帶來了安全問題:如果計算機停機,記憶體緩衝區中的資料會丟失;因此係統同時提供了fsync、fdatasync等同步函式,可以強制作業系統立刻將緩衝區中的資料寫入到硬碟裡,從而確保資料的安全性。

AOF快取區的同步檔案策略由引數appendfsync控制,各個值的含義如下:

always:命令寫入aof_buf後立即呼叫系統fsync操作同步到AOF檔案,fsync完成後執行緒返回。這種情況下,每次有寫命令都要同步到AOF檔案,硬碟IO成為效能瓶頸,Redis只能支援大約幾百TPS寫入,嚴重降低了Redis的效能;即便是使用固態硬碟(SSD),每秒大約也只能處理幾萬個命令,而且會大大降低SSD的壽命。

no:命令寫入aof_buf後呼叫系統write操作,不對AOF檔案做fsync同步;同步由作業系統負責,通常同步週期為30秒。這種情況下,檔案同步的時間不可控,且緩衝區中堆積的資料會很多,資料安全性無法保證。
everysec:命令寫入aof_buf後呼叫系統write操作,write完成後執行緒返回;fsync同步檔案操作由專門的執行緒每秒呼叫一次。everysec是前述兩種策略的折中,是效能和資料安全性的平衡,因此是Redis的預設配置,也是我們推薦的配置。

檔案重寫(rewrite)

因為AOF的運作方式是不斷地將命令追加到檔案的末尾,所以隨著寫入命令的不斷增加,AOF檔案的體積也會變得越來越大。舉個例子,如果你對一個計數器呼叫了100次INCR,那麼僅僅是為了儲存這個計數器的當前值,AOF檔案就需要使用100條記錄(entry)。然而在實際上,只使用一條SET命令已經足以儲存計數器的當前值了,其餘99條記錄實際上都是多餘的。另外還有一些過期的資料,無效的資料也都是可以去除。

過大的AOF檔案不僅會影響伺服器的正常執行,也會導致資料恢復需要的時間過長。為了處理這種情況,Redis支援一種有趣的特性,可以在不打斷服務客戶端的情況下,對AOF檔案進行重建(rebuild)。執行BGREWRITEAOF命令, Redis將生成一個新的AOF檔案, 這個檔案包含重建當前資料集所需的最少命令。

AOF REWRITE(重寫)生成過程和RDB快照類似,都巧妙地利用了寫時複製機制。同樣也是fork一個子程式(此時主執行緒是阻塞的),子程式根據記憶體快照,按照命令合併規則寫入到新的AOF檔案。當主程式fork完子執行緒後繼續接受請求,所有寫命令依然寫入AOF緩衝區(aof_buf),並根據appendfsync策略同步到硬碟,保證原有AOF機制的正確。但由於fork操作使用寫時複製技術,子程式只能共享fork操作時的記憶體資料。由於父程式依然在響應命令,因此Redis使用AOF重寫緩衝區(aof_rewrite_buf)儲存這部分新日誌,防止新AOF檔案生成期間丟失這部分資料。也就是說,bgrewriteaof執行期間,Redis的寫命令同時追加到aof_buf和aof_rewirte_buf兩個緩衝區。

當子程式寫完新的AOF檔案後,向父程式發訊號,父程式更新統計資訊,具體可以透過info persistence檢視。然後父程式把AOF重寫緩衝區的資料寫入到新的AOF檔案,這樣就保證了新AOF檔案所儲存的資料庫狀態和伺服器當前狀態一致。然後呼叫原子性的rename命令用新的AOF檔案取代老的AOF檔案,完成AOF重寫。

這裡需要注意,因為由主程式把aof_rewrite_buf快取追加到新日誌檔案。主程式追加日誌時,不會處理其他請求,如果aof_rewrite_buf特別大,例如幾百M,也可能造成Redis幾秒甚至幾十秒不響應。

從上面的流程我們能夠看到,RDB和AOF操作都是順序IO操作,效能都很高。而在透過RDB檔案或者AOF日誌進行資料庫恢復的時候,也是順序的讀取資料載入到記憶體中。所以也不會造成磁碟的隨機讀。

檔案重寫的觸發,分為手動觸發和自動觸發:

手動觸發:直接呼叫bgrewriteaof命令,該命令的執行與bgsave有些類似:都是fork子程式進行具體的工作,且都只有在fork時阻塞。

自動觸發:根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage引數,以及aof_current_size和aof_base_size狀態確定觸發時機。

auto-aof-rewrite-min-size表示執行AOF重寫時,檔案的最小體積,預設值為64MB。

auto-aof-rewrite-percentage表示執行AOF重寫時,當前AOF大小(即aof_current_size)和上一次重寫時AOF大小(aof_base_size)的比值,即增長比例達到設定值。

只有當auto-aof-rewrite-min-size和auto-aof-rewrite-percentage兩個引數同時滿足時,才會自動觸發AOF重寫,即bgrewriteaof操作。

其中,引數可以透過config get命令檢視:

127.0.0.1:6391> CONFIG GET auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "64000000"
127.0.0.1:6391> CONFIG GET auto-aof-rewrite-percentage
1) "auto-aof-rewrite-percentage"
2) "100"

狀態可以透過info persistence檢視:

127.0.0.1:6379> info persistence
# Persistence
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:0
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_current_size:40876638
aof_base_size:2217565
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0

另外在aof rewrite過程中,是否採取增量”檔案同步”策略,由引數aof-rewrite-incremental-fsync控制,預設為”yes”,而且必須為yes。rewrite過程中,每32M資料進行一次檔案同步,這樣可以減少”aof大檔案”寫入對磁碟的操作次數。

bgrewriteaof機制,在一個子程式中進行aof的重寫,從而不阻塞主程式對其餘命令的處理,同時解決了aof檔案過大問題。現在問題出現了,同時在執行bgrewriteaof操作和主程式寫aof檔案的操作,兩者都會操作磁碟,而bgrewriteaof往往會涉及大量磁碟操作,這樣就會造成主程式在寫aof檔案的時候出現阻塞的情形,現在no-appendfsync-on-rewrite引數出場了。

如果該引數設定為no,是最安全的方式,不會丟失資料,但是要忍受阻塞的問題。如果設定為yes呢?這就相當於將appendfsync設定為no,這說明並沒有執行磁碟操作,只是寫入了緩衝區,因此這樣並不會造成阻塞(因為沒有競爭磁碟),但是如果這個時候Redis掛掉,就會丟失資料。丟失多少資料呢?在Linux的作業系統的預設設定下,最多會丟失30s的資料。因此,如果應用系統無法忍受延遲,而可以容忍少量的資料丟失,則設定為yes。如果應用系統無法忍受資料丟失,則設定為no。

AOF重新整理策略?

前面提到過,在AOF中,如果AOF緩衝區的檔案同步策略為everysec,則:在主執行緒中,命令寫入aof_buf後呼叫系統write操作,write完成後主執行緒返回;fsync同步檔案操作由專門的檔案同步執行緒每秒呼叫一次。這種做法的問題在於,如果硬碟負載過高,那麼fsync操作可能會超過1s;如果Redis主執行緒持續高速向aof_buf寫入命令,硬碟的負載可能會越來越大,IO資源消耗更快;如果此時Redis程式異常退出,丟失的資料也會越來越多,可能遠超過1s。

為此,Redis的處理策略是這樣的:主執行緒每次進行AOF會對比上次fsync成功的時間;如果距上次不到2s(也就是延遲了1s),主執行緒直接返回;如果超過2s,則主執行緒阻塞直到上一次fsync同步完成。因此,如果系統硬碟負載過大導致fsync速度太慢,會導致Redis主執行緒的阻塞;此外,使用everysec配置,AOF最多可能丟失2s的資料,而不是1s。具體看Redis AOF重新整理策略分析

AOF追加阻塞問題定位的方法,監控info Persistence中的aof_delayed_fsync,當AOF追加阻塞發生時(即主執行緒等待fsync而阻塞),該指標累加。另外,AOF阻塞時的Redis日誌:Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.

如果AOF追加阻塞頻繁發生,說明系統的硬碟負載太大;可以考慮更換IO速度更快的硬碟,或者透過IO監控分析工具對系統的IO負載進行分析。

對於pipelining有什麼不同?

對於pipelining的操作,其具體過程是客戶端一次性傳送N個命令,然後等待這N個命令的返回結果被一起返回。透過採用pipilining就意味著放棄了對每一個命令的返回值確認。由於在這種情況下,N個命令是在同一個執行過程中執行的。所以當設定appendfsync為everysec時,可能會有一些偏差,因為這N個命令可能執行時間超過1秒甚至2秒。但是可以保證的是,最長時間不會超過這N個命令的執行時間和。

如果AOF檔案出錯了,怎麼辦?

伺服器可能在程式正在對AOF檔案進行寫入時停機,如果停機造成了 AOF 檔案出錯(corrupt),那麼Redis在重啟時會拒絕載入這個AOF檔案, 從而確保資料的一致性不會被破壞。當發生這種情況時,可以用以下方法來修復出錯的 AOF 檔案:為現有的AOF檔案建立一個備份。然後使用Redis附帶的redis-check-aof --fix程式對原來的AOF檔案進行修復。

然後可選使用 diff -u 對比修復後的 AOF 檔案和原始 AOF 檔案的備份,檢視兩個檔案之間的不同之處。再次重啟Redis伺服器,等待伺服器載入修復後的AOF檔案,並進行資料恢復。

但如果是AOF檔案結尾不完整(機器突然當機等容易導致檔案尾部不完整),且aof-load-truncated引數開啟,則日誌中會輸出警告,Redis忽略掉AOF檔案的尾部,啟動成功。aof-load-truncated引數預設是開啟的。

RDB和AOF優缺點
RDB的優點?

RDB是一個非常緊湊(compact)的檔案,體積小,網路傳輸快,它儲存了Redis在某個時間點上的資料集。這種檔案非常適合用於進行備份,恢復速度比AOF快很多。當然,與AOF相比,RDB最重要的優點之一是對效能的影響相對較小。父程式在儲存RDB檔案時唯一要做的就是fork出一個子程式,然後這個子程式就會處理接下來的所有儲存工作,父程式無須執行任何磁碟 I/O 操作。

RDB的缺點?

RDB檔案的致命缺點在於其資料快照的持久化方式決定了必然做不到實時持久化,而在資料越來越重要的今天,資料的大量丟失很多時候是無法接受的,因此AOF持久化成為主流。此外,RDB檔案需要滿足特定格式,相容性差(如老版本的Redis不相容新版本的RDB檔案)。

AOF的優點?

與RDB持久化相對應,AOF的優點在於支援秒級持久化、相容性好。你可以設定不同的fsync策略,比如無fsync,每秒鐘一次fsync,或者每次執行寫入命令時fsync。AOF的預設策略為每秒鐘fsync一次,在這種配置下,Redis仍然可以保持良好的效能,並且就算發生故障停機,也最多隻會丟失一秒鐘的資料。AOF檔案是一個只進行追加操作的日誌檔案(append only log),因此對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執行之前的狀態。

AOF的缺點?

AOF檔案的體積通常要大於RDB檔案的體積、且恢復速度慢。對於相同的資料集來說,根據所使用的fsync策略,AOF的速度可能會慢於RDB。在一般情況下,每秒fsync的效能依然非常高,而關閉fsync可以讓AOF的速度和RDB一樣快。另外,AOF在過去曾經發生過這樣的bug,因為個別命令的原因,導致AOF檔案在重新載入時,無法將資料集恢復成儲存時的原樣。雖然這種bug在AOF檔案中並不常見,但是對比來說,RDB幾乎是不可能出現這種bug的。

RDB和AOF,我應該用哪一個?

首先要明白無論是RDB還是AOF,持久化的開啟都是要付出效能方面代價的:對於RDB持久化,一方面是bgsave在進行fork操作時Redis主程式會阻塞,另一方面,子程式向硬碟寫資料也會帶來IO壓力。但如果業務能容忍幾分鐘到10幾分鐘的資料丟失(且不使用備庫),RDB是一個不錯的選擇;不然,就選擇AOF。

對於AOF持久化,向硬碟寫資料的頻率大大提高(everysec策略下為秒級),IO壓力更大,甚至可能造成AOF追加阻塞問題(後面會詳細介紹這種阻塞),此外,AOF檔案的重寫與RDB的bgsave類似,會有fork時的阻塞和子程式的IO壓力問題。相對來說,由於AOF向硬碟中寫資料的頻率更高,因此對Redis主程式效能的影響會更大。

在實際生產環境中,根據資料量、應用對資料的安全要求、預算限制等不同情況,會有各種各樣的持久化策略;如完全不使用任何持久化、使用RDB或AOF的一種,或同時開啟RDB和AOF持久化等。此外,持久化的選擇必須與Redis的主從策略一起考慮,因為主從複製與持久化同樣具有資料備份的功能,而且主機master和從機slave可以獨立的選擇持久化方案。比如完全關閉master持久化(包括RDB和AOF),這樣可以讓master的效能達到最好;而slave可以只開啟AOF。但這種情況下,如果master服務因為故障宕掉了,如果系統中有自動拉起機制(即檢測到服務停止後重啟該服務)將master自動重啟,由於沒有持久化檔案,那麼master重啟後資料是空的,slave同步資料也變成了空的,意味著資料丟失。所以儘量避免這種情況出現。

RDB和AOF之間的相互作用?

在版本號大於等於2.4的Redis中,BGSAVE執行的過程中,不可以執行BGREWRITEAOF。反過來說,在BGREWRITEAOF執行的過程中,也不可以執行BGSAVE。這可以防止兩個Redis後臺程式同時對磁碟進行大量的I/O操作。

如果BGSAVE正在執行,並且使用者顯示地呼叫BGREWRITEAOF命令,那麼伺服器將向使用者回覆一個OK狀態,並告知使用者,BGREWRITEAOF已經被預定執行: 一旦BGSAVE執行完畢,BGREWRITEAOF就會正式開始。當Redis啟動時,如果RDB持久化和AOF持久化都被開啟了,那麼程式會優先使用AOF檔案來恢復資料集,因為AOF檔案所儲存的資料通常是最完整的。

RDB和AOF資料匯入

這些持久化的資料有什麼用,當然是用於重啟後的資料恢復。Redis是一個記憶體資料庫,無論是RDB還是AOF,都只是其保證資料恢復的措施。所以Redis在利用RDB或AOF進行恢復的時候,會讀取RDB或AOF檔案,重新載入到記憶體中。相對於MySQL等資料庫的啟動時間來說,會長很多,因為MySQL本來是不需要將資料載入到記憶體中的。

但是相對來說,MySQL啟動後提供服務時,其被訪問的熱資料也會慢慢載入到記憶體中,通常我們稱之為預熱,而在預熱完成前,其效能都不會太高。而Redis的好處是一次性將資料載入到記憶體中,一次性預熱。這樣只要Redis啟動完成,那麼其提供服務的速度都是非常快的。

而在利用RDB和利用AOF啟動上,其啟動時間有一些差別。RDB的啟動時間會更短,原因有兩個,一是RDB檔案中每一條資料只有一條記錄,不會像AOF日誌那樣可能有一條資料的多次操作記錄。所以每條資料只需要寫一次就行了。另一個原因是RDB檔案的儲存格式和Redis資料在記憶體中的編碼格式是一致的,不需要再進行資料編碼工作。在CPU消耗上要遠小於AOF日誌的載入。

注意:當redis啟動時,如果rdb持久化和aof持久化都開啟了,那麼程式會優先使用aof方式來恢復資料集,因為aof方式所儲存的資料通常是最完整的。如果aof檔案丟失了,則啟動之後資料庫內容為空。

注意:如果想把正在執行的redis資料庫,從RDB切換到AOF,建議先使用動態切換方式,再修改配置檔案,重啟資料庫。(不能直接修改配置檔案,重啟資料庫,否則資料庫中資料就為空了。)
在Redis 2.2或以上版本,可以在不重啟的情況下,從RDB切換到AOF :

為最新的dump.rdb檔案建立一個備份,將備份放到一個安全的地方。執行以下兩條命令:

127.0.0.1:6379> CONFIG SET dir /apps/redis/data/redis-8836
127.0.0.1:6379> CONFIG SET appendonly yes
127.0.0.1:6379> CONFIG SET save ""

確保命令執行之後,資料庫的鍵的數量沒有改變。確保寫命令會被正確地追加到 AOF 檔案的末尾。

步驟2是開啟了AOF功能,Redis會阻塞直到初始AOF檔案建立完成為止,之後Redis會繼續處理命令請求,並開始將寫入命令追加到AOF檔案末尾。

步驟3用於關閉RDB功能,這一步是可選的,如果你願意的話,也可以同時使用RDB和AOF這兩種持久化功能。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2636324/,如需轉載,請註明出處,否則將追究法律責任。

相關文章