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