柚子快報(bào)激活碼778899分享:數(shù)據(jù)庫(kù) 【Redis】持久化
柚子快報(bào)激活碼778899分享:數(shù)據(jù)庫(kù) 【Redis】持久化
對(duì)于Redis中間件來(lái)說(shuō),一般是作為內(nèi)存型數(shù)據(jù)庫(kù)或者緩存出現(xiàn)的。但是由于其數(shù)據(jù)是在內(nèi)存中,因此當(dāng)Redis所在的主機(jī)宕機(jī)之后,數(shù)據(jù)就會(huì)消失,再次重啟之后,沒有任何數(shù)據(jù)。這對(duì)于生產(chǎn)環(huán)境來(lái)說(shuō),是屬于P0級(jí)別的災(zāi)難了。
因此,對(duì)于Redis來(lái)說(shuō),不僅要將數(shù)據(jù)存在內(nèi)存中,還要將數(shù)據(jù)持久化到硬盤上。這樣當(dāng)Redis重啟之后,可以通過(guò)硬盤中的數(shù)據(jù)來(lái)恢復(fù)內(nèi)存中的數(shù)據(jù)。如果Redis是作為內(nèi)存數(shù)據(jù)庫(kù)的話,那么客戶端就可以繼續(xù)進(jìn)行訪問得到數(shù)據(jù);如果Redis是作為緩存的話,那么就可以減少M(fèi)ySQL的壓力,從而避免MySQL宕機(jī)。
Redis有兩種持久化方式:RDB和AOF。
?RDB
RDB是定期備份的持久化方式,即Redis定期會(huì)把內(nèi)存中的數(shù)據(jù)進(jìn)行備份,生成一個(gè)快照,保存在硬盤中。這樣,當(dāng)Redis重啟的時(shí)候,就可以讀取RDB文件來(lái)恢復(fù)內(nèi)存數(shù)據(jù)。
觸發(fā)方式
手動(dòng)觸發(fā)
程序猿在客戶端輸入特定的命令,來(lái)觸發(fā)Redis服務(wù)器快照的生成。
save:通過(guò)save命令,可以使Redis服務(wù)器觸發(fā)快照行為,進(jìn)行備份
bgsave:通過(guò)bgsave命令,同樣可以使Redis觸發(fā)快照行為,進(jìn)行備份。
對(duì)于save和bgsave兩個(gè)命令來(lái)說(shuō),最大的區(qū)別就是save會(huì)和其他客戶端命令一樣,在同一個(gè)進(jìn)程中執(zhí)行,因此就會(huì)影響其他客戶端命令的執(zhí)行;而對(duì)于bgsave命令來(lái)說(shuō),并不會(huì)在當(dāng)前進(jìn)程中執(zhí)行,而是fork一個(gè)子進(jìn)程,在子進(jìn)程中執(zhí)行,這樣就不會(huì)影響其他客戶端的請(qǐng)求。
?bgsave的執(zhí)行流程
1.? 客戶端發(fā)送bgsave命令之后,Redis服務(wù)器會(huì)判斷是否已經(jīng)正在執(zhí)行該命令。如果正在執(zhí)行,那么就會(huì)直接進(jìn)行返回。
2. 如果沒有執(zhí)行,那么Redis服務(wù)器就會(huì)通過(guò)fork命令,來(lái)創(chuàng)建出一個(gè)子進(jìn)程。
fork命令是Linux系統(tǒng)提供的一個(gè)創(chuàng)建子進(jìn)程的API。簡(jiǎn)單來(lái)說(shuō),fork命令就是將原來(lái)的進(jìn)程給簡(jiǎn)單粗暴的復(fù)制一份。復(fù)制完成之后,兩個(gè)進(jìn)程之間就沒有任何的關(guān)系,各自會(huì)執(zhí)行各自的內(nèi)容,不過(guò)由于后續(xù)的進(jìn)程,即子進(jìn)程是父進(jìn)程復(fù)制而來(lái),因此兩個(gè)進(jìn)程中的數(shù)據(jù)是完成相同的。這樣,讓子進(jìn)程生成一份快照,就相當(dāng)于讓父進(jìn)程生成一份快照。
對(duì)于fork命令來(lái)說(shuō),是不是有比較大的性能開銷?不會(huì),執(zhí)行fork命令進(jìn)行內(nèi)存拷貝的時(shí)候,并不是在內(nèi)存空間中把所有的數(shù)據(jù)全部復(fù)制一份,而是采用寫時(shí)拷貝的方式來(lái)完成。
所謂寫時(shí)拷貝,當(dāng)父子進(jìn)程的數(shù)據(jù)是完成相同時(shí),兩者指向的內(nèi)存空間還是同樣的位置。但是當(dāng)任一進(jìn)程發(fā)生改變時(shí),才會(huì)開辟一個(gè)新的內(nèi)存空間來(lái)記錄變化的數(shù)據(jù)。
綜上所述,使用fork命令生成父子進(jìn)程時(shí),并不會(huì)產(chǎn)生較大的性能開銷。畢竟Redis改變的數(shù)據(jù)并不是大多數(shù),而是一小部分,因此對(duì)于寫時(shí)拷貝來(lái)說(shuō)消耗并不是很大,整體來(lái)說(shuō)較快。
3. 父進(jìn)程繼續(xù)執(zhí)行客戶端的其他命令請(qǐng)求,而子進(jìn)程則是來(lái)生成快照,進(jìn)行備份。
4. 子進(jìn)程持久化完成之后,就會(huì)來(lái)通知父進(jìn)程。父進(jìn)程再更新一些統(tǒng)計(jì)信息之后,子進(jìn)程就可以銷毀了。
自動(dòng)觸發(fā)
1. 在Redis的配置文件中可以進(jìn)行配置,以來(lái)達(dá)到自動(dòng)觸發(fā)定期快照的操作;
2. 在主從模式中,給主節(jié)點(diǎn)加從節(jié)點(diǎn)時(shí),主節(jié)點(diǎn)會(huì)主動(dòng)生成快照,發(fā)送給從節(jié)點(diǎn);
3. 當(dāng)客戶端發(fā)送shutdown命令,進(jìn)程關(guān)閉服務(wù)器時(shí),會(huì)觸發(fā)快照的生成,但是如果是意外宕機(jī),例如掉電或者kill,那么此時(shí)就不會(huì)生成快照。
RDB文件
1. RDB文件的存放位置,是可以通過(guò)Redis的配置信息來(lái)設(shè)置的,默認(rèn)是放在/var/lib/redis中。
2. Redis文件是一個(gè)二進(jìn)制的文件。即把內(nèi)存中的數(shù)據(jù)通過(guò)壓縮的形式,保存到這個(gè)二進(jìn)制文件中。通過(guò)壓縮,可以節(jié)省空間,但是進(jìn)行操作時(shí)就會(huì)消耗一定的CPU資源。
3. Redis重啟時(shí),就會(huì)通過(guò)RDB文件來(lái)恢復(fù)內(nèi)存中的數(shù)據(jù)。但是如果RDB的數(shù)據(jù)內(nèi)容發(fā)生了變化,那么就有可能重啟失敗,也有可能重啟成功。因此,Redis還專門提供了檢查RDB文件的工具,可以在重啟服務(wù)器之前,先檢查RDB文件是否發(fā)生錯(cuò)誤。
4. 在快照生成RDB文件時(shí),會(huì)將生成的這些內(nèi)容存儲(chǔ)到一個(gè)臨時(shí)的文件中。當(dāng)快照生成完畢,就會(huì)使用新生成的RDB文件來(lái)代替舊的RDB文件,這樣硬盤中自始至終就只有一個(gè)文件了。
?5. 在bgsave命令的執(zhí)行流程中,雖然fork子進(jìn)程的性能消耗并不大,但是RDB文件的生成也有一個(gè)較高的性能開銷,因此RDB文件不是實(shí)時(shí)備份,而是定期備份。正是由于定期備份,因此在一次備份完成之后,Redis宕機(jī),再次重啟時(shí),備份之后操作的數(shù)據(jù)都不復(fù)存在。
RDB特點(diǎn)
1. RDB文件是一個(gè)二進(jìn)制格式的文件,因此非常適合用于備份、全量復(fù)制等場(chǎng)景。
2. Redis加載RDB恢復(fù)數(shù)據(jù)往往比加載AOF恢復(fù)數(shù)據(jù)要快。這是因?yàn)镽DB使用二進(jìn)制來(lái)組織數(shù)據(jù),而AOF則是使用文本格式來(lái)組織數(shù)據(jù),而計(jì)算機(jī)天然對(duì)二進(jìn)制好感度高。
3. Redis無(wú)法做到實(shí)時(shí)持久化,畢竟生成一次快照消耗的資源還是較多的,屬于重量級(jí)操作,頻繁執(zhí)行成本過(guò)高。
4. RDB使用二進(jìn)制格式保存,但是Redis不同的版本可能二進(jìn)制格式略有不同,因此可能存在兼容性問題(例如將5版本的RDB放到7版本的RDB文件中,就可能運(yùn)行不起來(lái))。
AOF
AOF(Append Only File)是實(shí)時(shí)備份的持久化方式。所謂實(shí)時(shí)備份,并不是將Redis服務(wù)器內(nèi)存中的數(shù)據(jù)進(jìn)行持久化,而是把用戶進(jìn)行的操作當(dāng)作日志記錄成文件。也就是說(shuō),當(dāng)用戶執(zhí)行某條操作時(shí),Redis就會(huì)進(jìn)行記錄,并且寫入到文件中。這樣,當(dāng)Redis服務(wù)器重新啟動(dòng)的時(shí)候,就回去讀取AOF文件,用來(lái)恢復(fù)數(shù)據(jù)。
對(duì)于RDB方式的持久化來(lái)說(shuō),最大的問題是不能實(shí)時(shí)持久化來(lái)保存數(shù)據(jù)。這就導(dǎo)致在某些突發(fā)情況發(fā)生后,Redis服務(wù)器重啟時(shí),Redis內(nèi)存中的數(shù)據(jù)可能會(huì)存在丟失的情況。
因此,AOF方式的持久化,就是用來(lái)解決RDB存在的問題。當(dāng)開啟AOF方式的持久化之后,Redis服務(wù)器重新啟動(dòng)時(shí),就會(huì)讀取AOF文件中的內(nèi)容來(lái)恢復(fù)內(nèi)存數(shù)據(jù),不會(huì)再讀取RDB文件的內(nèi)容。
?開啟AOF
默認(rèn)情況下,Redis服務(wù)器是使用RDB的方式來(lái)進(jìn)行持久化的。對(duì)于AOF來(lái)說(shuō),默認(rèn)則是關(guān)閉狀態(tài),要想使用AOF,就要在配置文件中進(jìn)行開啟:
?當(dāng)AOF方式的持久化開啟之后,RDB就會(huì)失效。并且對(duì)于AOF來(lái)說(shuō),其文件生成的位置和RDB文件生成的位置在同一目錄下。
AOF與Redis性能間的關(guān)系
引入AOF之后,既要操作內(nèi)存(Redis服務(wù)器需要對(duì)客戶端發(fā)送的請(qǐng)求進(jìn)行響應(yīng)),又要操作硬盤(Redis服務(wù)器需要把客戶端的操作當(dāng)成日志寫入文件),這是否對(duì)Redis的效率產(chǎn)生了很大的影響?答案是沒有。
AOF雖然是把客戶端的操作給記錄下來(lái),但是并不是直接讓工作線程把數(shù)據(jù)給寫入硬盤。而是先把數(shù)據(jù)寫入到內(nèi)存中的緩沖區(qū)中,當(dāng)積累一定數(shù)量之后(通過(guò)積累,可以降低寫硬盤的次數(shù),從而減少性能的消耗),統(tǒng)一寫入硬盤(寫入硬盤時(shí),采用了順序讀取的方式,相對(duì)隨機(jī)讀取來(lái)說(shuō)還是比較快的一種讀取方式)。
通過(guò)上述描述,我相信大家存在一個(gè)疑惑:把數(shù)據(jù)寫入緩沖區(qū),那不還是在內(nèi)存中,這些數(shù)據(jù)依然有丟失的風(fēng)險(xiǎn),因此AOF依舊沒解決RDB存在的問題。
其實(shí)不然,AOF的確解決了RDB存在的不能實(shí)時(shí)持久化的問題,這本質(zhì)上存在一個(gè)可靠和性能的矛盾性。當(dāng)數(shù)據(jù)特別可靠時(shí),其性能一定會(huì)有所損耗;當(dāng)性能非常好時(shí),其數(shù)據(jù)可靠性就會(huì)有所下降。例如MySQL中的隔離級(jí)別,當(dāng)隔離級(jí)別是可串行化時(shí),其數(shù)據(jù)基本上完全可靠,但是性能低下;當(dāng)隔離級(jí)別是讀未提交時(shí),其讀取到的數(shù)據(jù)不一定可靠,但是其性能一定非常高。
綜上,針對(duì)Redis的AOF來(lái)說(shuō),其官方也給出了不同的措施來(lái)解決不同業(yè)務(wù)場(chǎng)景下的問題,即程序員根據(jù)對(duì)系統(tǒng)的評(píng)估來(lái)取舍緩存區(qū)的刷新策略。刷新頻率越高,那么其性能影響也就越大,但是其數(shù)據(jù)的可靠性就越高;刷新頻率越低,性能影響就會(huì)越小,但是數(shù)據(jù)的可靠性就會(huì)降低。
在Redis中,使用appendfsync屬性來(lái)配置刷新策略,并且給出了三個(gè)配置值。
可配置值說(shuō)明性能與可靠性always 客戶端進(jìn)行操作之后,數(shù)據(jù)進(jìn)入緩存區(qū)之后,直接寫入AOF文件中。 性能最低,可靠性最高。 everysec 客戶端進(jìn)行操作之后,先寫入緩沖區(qū),然后每秒寫入一次文件。 性能適中,可靠性適中。 Redis默認(rèn)此刷新策略。 no 客戶端進(jìn)行操作之后,先寫入緩存區(qū),然后根據(jù)操作系統(tǒng)來(lái)控制寫入文件。 性能最高,可靠性最低。
重寫機(jī)制
在AOF文件中,記錄的是客戶端每次進(jìn)行的操作。但是在客戶端操作的過(guò)程中,可能某個(gè)變量會(huì)重復(fù)被操作,最后被刪除。這些操作如果記錄在AOF文件中,那么在Redis服務(wù)器重啟的時(shí)候,也會(huì)對(duì)這個(gè)變量進(jìn)行反復(fù)操作,最后刪除,那么就是消耗大量?jī)?nèi)存但是做了無(wú)用的事。
因此Redis就存在一個(gè)機(jī)制,能夠?qū)OF文件進(jìn)行整理操作,這個(gè)整理就能夠剔除其中的冗余操作,并且合并一些操作,達(dá)到給AOF文件瘦身的效果。這樣,當(dāng)Reids服務(wù)器進(jìn)行重啟的時(shí)候,就不會(huì)機(jī)械性的做一些無(wú)用的操作。
這個(gè)機(jī)制就被稱為Redis的重寫機(jī)制。
觸發(fā)方式
手動(dòng)觸發(fā)和自動(dòng)觸發(fā)兩種。
手動(dòng)觸發(fā)使用bgrewriteaof命令進(jìn)行操作;
自動(dòng)觸發(fā)則根據(jù)auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數(shù)確定自動(dòng)觸發(fā)時(shí)機(jī),auto-aof-rewrite-min-size表示觸發(fā)重寫時(shí)AOF的最小文件大小,默認(rèn)是64MB,auto-aof-rewrite-percentage代表當(dāng)前AOF占用大小相比較上次重寫時(shí)增加的比例。
重寫流程
① 當(dāng)Redis接收到了重寫操作時(shí),就會(huì)fork一個(gè)子進(jìn)程。如果此時(shí)Redis服務(wù)器已經(jīng)在重寫,那么就不會(huì)再次執(zhí)行命令,直接返回。
?② 父進(jìn)程仍然接收請(qǐng)求,子進(jìn)程負(fù)責(zé)針對(duì)AOF文件進(jìn)行重寫。在重寫的時(shí)候,并不關(guān)心AOF文件原來(lái)有啥內(nèi)容,只關(guān)心此時(shí)內(nèi)存中數(shù)據(jù)的最終狀態(tài)。因此,子進(jìn)程只需要把當(dāng)前的數(shù)據(jù)獲取出來(lái),以AOF文件的格式寫入到一個(gè)新的AOF文件中。
③ 子進(jìn)程在重寫AOF文件的同時(shí),父進(jìn)程還是會(huì)不停的接收客戶端的請(qǐng)求,并且把這些請(qǐng)求產(chǎn)生的AOF數(shù)據(jù)寫入到緩沖區(qū)中,再刷新到原來(lái)的AOF文件中。在執(zhí)行這些命令的同時(shí),父進(jìn)程還會(huì)準(zhǔn)備一個(gè)新的緩沖區(qū),把fork之后產(chǎn)生的AOF數(shù)據(jù)放入其中。
為啥要準(zhǔn)備這個(gè)新的緩沖區(qū)?
當(dāng)fork之后,子進(jìn)程中的內(nèi)存數(shù)據(jù)是父進(jìn)程fork之前的,因此對(duì)于fork之后的請(qǐng)求對(duì)內(nèi)存造成的修改,子進(jìn)程是不知道的。所以,當(dāng)Redis把子進(jìn)程的內(nèi)存數(shù)據(jù)整理完畢之后,如果直接代替之前的文件,那么整理文件過(guò)程中產(chǎn)生的數(shù)據(jù)會(huì)丟失。所以,要準(zhǔn)備這個(gè)緩沖區(qū)來(lái)接收f(shuō)ork之后的一些請(qǐng)求。
④ 子進(jìn)程整理完畢之后,會(huì)通知父進(jìn)程,父進(jìn)程把新緩沖區(qū)中的內(nèi)容加入到新AOF文件之中,就可以用新的文件來(lái)代替舊的AOF文件。
當(dāng)在重寫過(guò)程中,發(fā)現(xiàn)Redis正在備份。那么此時(shí),AOF重寫就會(huì)停止,等待RDB快照完成,再繼續(xù)進(jìn)行重寫的操作。
混合持久化
對(duì)于RDB來(lái)說(shuō),是沒法做到實(shí)時(shí)備份,存在數(shù)據(jù)丟失的風(fēng)險(xiǎn);對(duì)于AOF來(lái)說(shuō),是使用文本的格式來(lái)寫入數(shù)據(jù),導(dǎo)致后續(xù)加載文件的成本較高。
由于RBD和AOF各有優(yōu)缺點(diǎn),因此就又有了混合持久化的方式。正所謂,小孩子才做選擇,大人全都要。簡(jiǎn)單來(lái)說(shuō),混合持久化就是對(duì)于每一個(gè)操作,都會(huì)使用AOF的方式來(lái)寫入文件;當(dāng)執(zhí)行重寫操作時(shí),就會(huì)把當(dāng)前內(nèi)存的狀態(tài)按照RDB的格式寫入到新的AOF文件中。這樣,即可以保證所有數(shù)據(jù)的及時(shí)更新,又可以在讀取文件時(shí)采用較小的成本。
柚子快報(bào)激活碼778899分享:數(shù)據(jù)庫(kù) 【Redis】持久化
好文推薦
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。