一、概述
Redis的強大性能很大程度上都是因為所有數據都是存儲在內存中的,然而當Redis重啟后,所有存儲在內存中的數據將會丟失,在很多情況下是無法容忍這樣的事情的。所以,我們需要將內存中的數據持久化!典型的需要持久化數據的場景如下:
- 將Redis作為數據庫使用;
- 將Redis作為緩存服務器使用,但是緩存miss后會對性能造成很大影響,所有緩存同時失效時會造成服務雪崩,無法響應。
本文介紹Redis所支持的兩種數據持久化方式。
二、Redis數據持久化
Redis支持兩種數據持久化方式:RDB方式和AOF方式。前者會根據配置的規(guī)則定時將內存中的數據持久化到硬盤上,后者則是在每次執(zhí)行寫命令之后將命令記錄下來。兩種持久化方式可以單獨使用,但是通常會將兩者結合使用。
1、RDB方式
RDB方式的持久化是通過快照的方式完成的。當符合某種規(guī)則時,會將內存中的數據全量生成一份副本存儲到硬盤上,這個過程稱作”快照”,Redis會在以下幾種情況下對數據進行快照:
- 根據配置規(guī)則進行自動快照;
- 用戶執(zhí)行SAVE, BGSAVE命令;
- 執(zhí)行FLUSHALL命令;
- 執(zhí)行復制(replication)時。
執(zhí)行快照的場景
(1)根據配置自動快照
Redis允許用戶自定義快照條件,當滿足條件時自動執(zhí)行快照。缺省情況下,Redis把數據快照存放在磁盤上的二進制文件中,文件名為dump.rdb,此外,我們也可以通過配置文件來修改Redis服務器dump快照的頻率,在打開redis.windows.conf文件之后,我們搜索save,可以看到下面的配置信息:
![](/d/20211018/95d9b31395ce5149f63670190cb7a5cf.gif)
注意最后三行,分別表示:
在900秒(15分鐘)之后,如果至少有1個key發(fā)生變化,則dump內存快照;
在300秒(5分鐘)之后,如果至少有10個key發(fā)生變化,則dump內存快照;
在60秒(1分鐘)之后,如果至少有10000個key發(fā)生變化,則dump內存快照。
每個快照條件獨占一行,他們之間是或(||)關系,只要滿足任何一個就進行快照。上面配置save后的第一個參數T是時間,單位是秒,第二個參數M是更改的鍵的個數,含義是:當時間T內被更改的鍵的個數大于M時,自動進行快照。比如save 900 1
的含義是15分鐘內(900s)被更改的鍵的個數大于1時,自動進行快照操作。
(2)執(zhí)行SAVE或BGSAVE命令
除了讓Redis自動進行快照外,當我們需要重啟,遷移,備份Redis時,我們也可以手動執(zhí)行SAVE或BGSAVE命令主動進行快照操作。
SAVE命令:當執(zhí)行SAVE命令時,Redis同步進行快照操作,期間會阻塞所有來自客戶端的請求,所以放數據庫數據較多時,應該避免使用該命令;
BGSAVE命令:從命令名字就能看出來,這個命令與SAVE命令的區(qū)別就在于該命令的快照操作是在后臺異步進行的,進行快照操作的同時還能處理來自客戶端的請求。執(zhí)行BGSAVE命令后Redis會馬上返回OK表示開始進行快照操作,如果想知道快照操作是否已經完成,可以使用LASTSAVE命令返回最近一次成功執(zhí)行快照的時間,返回結果是一個Unix時間戳。
(3)執(zhí)行FLUSHALL命令
當執(zhí)行FLUSHALL命令時,Redis會清除數據庫中的所有數據。需要注意的是:不論清空數據庫的過程是否觸發(fā)了自動快照的條件,只要自動快照條件不為空,Redis就會執(zhí)行一次快照操作,當沒有定義自動快照條件時,執(zhí)行FLUSHALL命令不會進行快照操作。
(4)執(zhí)行復制
當設置了主從模式時,Redis會在復制初始化時進行自動快照。
快照原理
Redis默認會將快照文件存儲在Redis當前進程的工作目錄的dump.rdb文件中,可以通過配置文件中的dir和dbfilename兩個參數分別指定快照文件的存儲路徑和文件名,默認的存儲路徑和文件名如下圖所示:
![](/d/20211018/d66e240bbc7fd785107197a22b358626.gif)
快照執(zhí)行的過程如下:
(1)Redis使用fork函數復制一份當前進程(父進程)的副本(子進程);
(2)父進程繼續(xù)處理來自客戶端的請求,子進程開始將內存中的數據寫入硬盤中的臨時文件;
(3)當子進程寫完所有的數據后,用該臨時文件替換舊的RDB文件,至此,一次快照操作完成。
需要注意的是:
在執(zhí)行fork的時候操作系統(tǒng)(類Unix操作系統(tǒng))會使用寫時復制(copy-on-write)策略,即fork函數發(fā)生的一刻,父進程和子進程共享同一塊內存數據,當父進程需要修改其中的某片數據(如執(zhí)行寫命令)時,操作系統(tǒng)會將該片數據復制一份以保證子進程不受影響,所以RDB文件存儲的是執(zhí)行fork操作那一刻的內存數據。所以RDB方式理論上是會存在丟數據的情況的(fork之后修改的的那些沒有寫進RDB文件)。
通過上述的介紹可以知道,快照進行時是不會修改RDB文件的,只有完成的時候才會用臨時文件替換老的RDB文件,所以就保證任何時候RDB文件的都是完整的。這使得我們可以通過定時備份RDB文件來實現Redis數據的備份。RDB文件是經過壓縮處理的二進制文件,所以占用的空間會小于內存中數據的大小,更有利于傳輸。
Redis啟動時會自動讀取RDB快照文件,將數據從硬盤載入到內存,根據數量的不同,這個過程持續(xù)的時間也不盡相同,通常來講,一個記錄1000萬個字符串類型鍵,大小為1GB的快照文件載入到內存需要20-30秒的時間。
示例
下面演示RDB方式持久化,首先使用配置有如下快照規(guī)則:
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir ./
啟動Redis服務:
![](/d/20211018/8b388f640afb47ce8cf2e1f06a22f20f.gif)
然后通過客戶端設置一個鍵值:
![](/d/20211018/f53de33caee5bb58c38e426035ac2d65.gif)
現在強行kill Redis服務,執(zhí)行shutdown命令:
![](/d/20211018/faebbef3239d60f8fd291d939fe65d77.gif)
![](/d/20211018/2059d0b22cae291a5c679fe0c7465f7f.gif)
現在到D:\Redis_x64_321\目錄看,目錄下出現了Redis的快照文件dump.rdb:
![](/d/20211018/9756dcfc8507a6a69e8261e5b8c0bc2d.gif)
現在重新啟動Redis,然后再用客戶端連接,檢查之前設置的key是否還存在:
![](/d/20211018/408ce18dc91fc94f658b8a74dc1731d8.gif)
可以發(fā)現,之前設置的key在Redis重啟之后又通過快照文件dump.rdb恢復了。
2、AOF方式
在使用Redis存儲非臨時數據時,一般都需要打開AOF持久化來降低進程終止導致的數據丟失,AOF可以將Redis執(zhí)行的每一條寫命令追加到硬盤文件中,這一過程顯然會降低Redis的性能,但是大部分情況下這個影響是可以接受的,另外,使用較快的硬盤能提高AOF的性能。
開啟AOF
默認情況下,Redis沒有開啟AOF(append only file)持久化功能,可以通過在配置文件中作如下配置啟用:
![](/d/20211018/b2bfbcfbc35486fb0620a90c7b2344c8.gif)
開啟之后,Redis每執(zhí)行一條寫命令就會將該命令寫入硬盤中的AOF文件。AOF文件保存路徑和RDB文件路徑是一致的,都是通過dir參數配置,默認文件名是:appendonly.aof,可以通過配置appendonlyfilename參數修改,例如:
![](/d/20211018/e91707244c431672fdae7b841258f009.gif)
AOF持久化的實現
AOF以純文本的形式記錄了Redis執(zhí)行的寫命令,例如在開啟AOF持久化的情況下執(zhí)行如下命令:
![](/d/20211018/c14ffb1fe35f89bada994f0cd1d6e6f3.gif)
然后查看D:\Redis_x64_321\appendonly.aof
文件:
![](/d/20211018/2555b92b39d234290e75e5b447fff68f.gif)
文件中的內容正是Redis剛才執(zhí)行的命令的內容,內容的格式就先不展開敘述了。
AOF文件重寫
AOF文件是可識別的純文本,它的內容就是一個個的Redis標準命令,
AOF日志也不是完全按客戶端的請求來生成日志的,比如命令 INCRBYFLOAT 在記AOF日志時就被記成一條SET記錄,因為浮點數操作可能在不同的系統(tǒng)上會不同,所以為了避免同一份日志在不同的系統(tǒng)上生成不同的數據集,所以這里只將操作后的結果通過SET來記錄。
每一條寫命令都生成一條日志,AOF文件會很大。
AOF重寫是重新生成一份AOF文件,新的AOF文件中一條記錄的操作只會有一次,而不像一份老文件那樣,可能記錄了對同一個值的多次操作。其生成過程和RDB類似,也是fork一個進程,直接遍歷數據,寫入新的AOF臨時文件。在寫入新文件的過程中,所有的寫操作日志還是會寫到原來老的AOF文件中,同時還會記錄在內存緩沖區(qū)中。當重完操作完成后,會將所有緩沖區(qū)中的日志一次性寫入到臨時文件中。然后調用原子性的rename命令用新的 AOF文件取代老的AOF文件。
命令:BGREWRITEAOF, 我們應該經常調用這個命令來來重寫。
=============================================================================
假設Redis執(zhí)行了如下命令:
![](/d/20211018/ac20c748b2858593184985a43560ab55.gif)
如果這所有的命令都寫到AOF文件的話,將是一個比較蠢的行為,因為前面兩個命令會被第三個命令覆蓋,所以AOF文件完全不需要保存前面兩個命令,事實上Redis確實就是這么做的。刪除AOF文件中無用的命令的過程稱為"AOF重寫",AOF重寫可以在配置文件中做相應的配置,當滿足配置的條件時,自動進行AOF重寫操作。配置如下:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
第一行的意思是,目前的AOF文件的大小超過上一次重寫時的AOF文件的百分之多少時再次進行重寫,如果之前沒有重寫過,則以啟動時AOF文件大小為依據。
第二行的意思是,當AOF文件的大小大于64MB時才進行重寫,因為如果AOF文件本來就很小時,有幾個無效的命令也是無傷大雅的事情。
這兩個配置項通常一起使用。
我們還可以手動執(zhí)行BGREWRITEAOF命令主動讓Redis重寫AOF文件:
![](/d/20211018/f0dfc467851f2141dfdd7bce08b108cc.gif)
執(zhí)行重寫命令之后查看現在的AOF文件:
![](/d/20211018/cc3d1a37f27e48913466a19e7d11fc6a.gif)
可以看到,文件中并沒有再記錄set k v1
這樣的無效命令。
同步硬盤數據
雖然每次執(zhí)行更改數據庫的內容時,AOF都會記錄執(zhí)行的命令,但是由于操作系統(tǒng)本身的硬盤緩存的緣故,AOF文件的內容并沒有真正地寫入硬盤,在默認情況下,操作系統(tǒng)會每隔30s將硬盤緩存中的數據同步到硬盤,但是為了防止系統(tǒng)異常退出而導致丟數據的情況發(fā)生,我們還可以在Redis的配置文件中配置這個同步的頻率:
# appendfsync always
appendfsync everysec
# appendfsync no
第一行表示每次AOF寫入一個命令都會執(zhí)行同步操作,這是最安全也是最慢的方式;
第二行表示每秒鐘進行一次同步操作,一般來說使用這種方式已經足夠;
第三行表示不主動進行同步操作,這是最不安全的方式。
選項:
1、appendfsync no
當設置appendfsync為no的時候,Redis不會主動調用fsync去將AOF日志內容同步到磁盤,所以這一切就完全依賴于操作系統(tǒng)的調試了。對大多數Linux操作系統(tǒng),是每30秒進行一次fsync,將緩沖區(qū)中的數據寫到磁盤上。
2、appendfsync everysec
當設置appendfsync為everysec的時候,Redis會默認每隔一秒進行一次fsync調用,將緩沖區(qū)中的數據寫到磁盤。但是當這一次的fsync調用時長超過1秒時。Redis會采取延遲fsync的策略,再等一秒鐘。也就是在兩秒后再進行fsync,這一次的fsync就不管會執(zhí)行多長時間都會進行。這時候由于在fsync時文件描述符會被阻塞,所以當前的寫操作就會阻塞。所以,結論就是:在絕大多數情況下,Redis會每隔一秒進行一次fsync。在最壞的情況下,兩秒鐘會進行一次fsync操作。這一操作在大多數數據庫系統(tǒng)中被稱為group commit,就是組合多次寫操作的數據,一次性將日志寫到磁盤。
3、appednfsync always
當設置appendfsync為always時,每一次寫操作都會調用一次fsync,這時數據是最安全的,當然,由于每次都會執(zhí)行fsync,所以其性能也會受到影響。
建議采用appendfsync everysec(缺省方式)
快照模式可以和AOF模式同時開啟,互補影響。
三、二者的區(qū)別
RDB持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁盤,實際操作過程是fork一個子進程,先將數據集寫入臨時文件,寫入成功后,再替換之前的文件,用二進制壓縮存儲。
![](/d/20211018/7c5a6a3f408c88d7cf68cbc3cca4d816.gif)
AOF持久化以日志的形式記錄服務器所處理的每一個寫、刪除操作,查詢操作不會記錄,以文本的方式記錄,可以打開文件看到詳細的操作記錄。
![](/d/20211018/ed1a38e5b21a8f23ef3d2f94ef01b4c5.gif)
四、二者優(yōu)缺點
RDB存在哪些優(yōu)勢呢?
1). 一旦采用該方式,那么你的整個Redis數據庫將只包含一個文件,這對于文件備份而言是非常完美的。比如,你可能打算每個小時歸檔一次最近24小時的數據,同時還要每天歸檔一次最近30天的數據。通過這樣的備份策略,一旦系統(tǒng)出現災難性故障,我們可以非常容易的進行恢復。
2). 對于災難恢復而言,RDB是非常不錯的選擇。因為我們可以非常輕松的將一個單獨的文件壓縮后再轉移到其它存儲介質上。
3). 性能最大化。對于Redis的服務進程而言,在開始持久化時,它唯一需要做的只是fork出子進程,之后再由子進程完成這些持久化的工作,這樣就可以極大的避免服務進程執(zhí)行IO操作了。
4). 相比于AOF機制,如果數據集很大,RDB的啟動效率會更高。
RDB又存在哪些劣勢呢?
1). 如果你想保證數據的高可用性,即最大限度的避免數據丟失,那么RDB將不是一個很好的選擇。因為系統(tǒng)一旦在定時持久化之前出現宕機現象,此前沒有來得及寫入磁盤的數據都將丟失。
2). 由于RDB是通過fork子進程來協助完成數據持久化工作的,因此,如果當數據集較大時,可能會導致整個服務器停止服務幾百毫秒,甚至是1秒鐘。
AOF的優(yōu)勢有哪些呢?
1). 該機制可以帶來更高的數據安全性,即數據持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事實上,每秒同步也是異步完成的,其效率也是非常高的,所差的是一旦系統(tǒng)出現宕機現象,那么這一秒鐘之內修改的數據將會丟失。而每修改同步,我們可以將其視為同步持久化,即每次發(fā)生的數據變化都會被立即記錄到磁盤中??梢灶A見,這種方式在效率上是最低的。至于無同步,無需多言,我想大家都能正確的理解它。
2). 由于該機制對日志文件的寫入操作采用的是append模式,因此在寫入過程中即使出現宕機現象,也不會破壞日志文件中已經存在的內容。然而如果我們本次操作只是寫入了一半數據就出現了系統(tǒng)崩潰問題,不用擔心,在Redis下一次啟動之前,我們可以通過redis-check-aof工具來幫助我們解決數據一致性的問題。
3). 如果日志過大,Redis可以自動啟用rewrite機制。即Redis以append模式不斷的將修改數據寫入到老的磁盤文件中,同時Redis還會創(chuàng)建一個新的文件用于記錄此期間有哪些修改命令被執(zhí)行。因此在進行rewrite切換時可以更好的保證數據安全性。
4). AOF包含一個格式清晰、易于理解的日志文件用于記錄所有的修改操作。事實上,我們也可以通過該文件完成數據的重建。
AOF的劣勢有哪些呢?
1). 對于相同數量的數據集而言,AOF文件通常要大于RDB文件。RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。
2). 根據同步策略的不同,AOF在運行效率上往往會慢于RDB??傊?,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效。
二者選擇的標準,就是看系統(tǒng)是愿意犧牲一些性能,換取更高的緩存一致性(aof),還是愿意寫操作頻繁的時候,不啟用備份來換取更高的性能,待手動運行save的時候,再做備份(rdb)。rdb這個就更有些 eventually consistent的意思了。
五、常用配置
RDB持久化配置
Redis會將數據集的快照dump到dump.rdb文件中。此外,我們也可以通過配置文件來修改Redis服務器dump快照的頻率,在打開6379.conf文件之后,我們搜索save,可以看到下面的配置信息:
save 900 1 #在900秒(15分鐘)之后,如果至少有1個key發(fā)生變化,則dump內存快照。
save 300 10 #在300秒(5分鐘)之后,如果至少有10個key發(fā)生變化,則dump內存快照。
save 60 10000 #在60秒(1分鐘)之后,如果至少有10000個key發(fā)生變化,則dump內存快照。
AOF持久化配置
在Redis的配置文件中存在三種同步方式,它們分別是:
appendfsync always #每次有數據修改發(fā)生時都會寫入AOF文件。
appendfsync everysec #每秒鐘同步一次,該策略為AOF的缺省策略。
appendfsync no #從不同步。高效但是數據不會被持久化。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:- redis數據的兩種持久化方式對比
- 一篇文章揭秘Redis的磁盤持久化機制
- Redis做數據持久化的解決方案及底層原理
- Redis教程(十):持久化詳解
- Redis的持久化方案詳解
- Redis數據持久化方式技術解析