深入理解Redis(六)----Redis主從復(fù)制

和Mysql主從復(fù)制的原因一樣,Redis雖然讀取寫入的速度都特別快,但是也會(huì)產(chǎn)生讀壓力特別大的情況。為了分擔(dān)讀壓力,Redis支持主從復(fù)制,Redis的主從結(jié)構(gòu)可以采用一主多從或者級(jí)聯(lián)結(jié)構(gòu),Redis主從復(fù)制可以根據(jù)是否是全量分為全量同步和增量同步。下圖為級(jí)聯(lián)結(jié)構(gòu)。


全量同步
Redis全量復(fù)制一般發(fā)生在Slave初始化階段,這時(shí)Slave需要將Master上的所有數(shù)據(jù)都復(fù)制一份。具體步驟如下:

  • 從服務(wù)器連接主服務(wù)器,發(fā)送SYNC命令;
  • 主服務(wù)器接收到SYNC命名后,開始執(zhí)行BGSAVE命令生成RDB文件并使用緩沖區(qū)記錄此后執(zhí)行的所有寫命令;
  • 主服務(wù)器BGSAVE執(zhí)行完后,向所有從服務(wù)器發(fā)送快照文件,并在發(fā)送期間繼續(xù)記錄被執(zhí)行的寫命令;
  • 從服務(wù)器收到快照文件后丟棄所有舊數(shù)據(jù),載入收到的快照;
  • 主服務(wù)器快照發(fā)送完畢后開始向從服務(wù)器發(fā)送緩沖區(qū)中的寫命令;
  • 從服務(wù)器完成對(duì)快照的載入,開始接收命令請(qǐng)求,并執(zhí)行來自主服務(wù)器緩沖區(qū)的寫命令;

完成上面幾個(gè)步驟后就完成了從服務(wù)器數(shù)據(jù)初始化的所有操作,從服務(wù)器此時(shí)可以接收來自用戶的讀請(qǐng)求。


增量同步
Redis增量復(fù)制是指Slave初始化后開始正常工作時(shí)主服務(wù)器發(fā)生的寫操作同步到從服務(wù)器的過程。
增量復(fù)制的過程主要是主服務(wù)器每執(zhí)行一個(gè)寫命令就會(huì)向從服務(wù)器發(fā)送相同的寫命令,從服務(wù)器接收并執(zhí)行收到的寫命令。


Redis主從同步策略
主從剛剛連接的時(shí)候,進(jìn)行全量同步;全同步結(jié)束后,進(jìn)行增量同步。當(dāng)然,如果有需要,slave 在任何時(shí)候都可以發(fā)起全量同步。redis 策略是,無論如何,首先會(huì)嘗試進(jìn)行增量同步,如不成功,要求重新2進(jìn)行全量同步。


注意點(diǎn)
如果多個(gè)Slave斷線了,需要重啟的時(shí)候,因?yàn)橹灰猄lave啟動(dòng),就會(huì)發(fā)送sync請(qǐng)求和主機(jī)全量同步,當(dāng)多個(gè)同時(shí)出現(xiàn)的時(shí)候,可能會(huì)導(dǎo)致Master IO劇增宕機(jī)。

Redis主從復(fù)制的配置十分簡(jiǎn)單,它可以使從服務(wù)器是主服務(wù)器的完全拷貝。需要清除Redis主從復(fù)制的幾點(diǎn)重要內(nèi)容:

1)Redis使用異步復(fù)制。但從Redis 2.8開始,從服務(wù)器會(huì)周期性的應(yīng)答從復(fù)制流中處理的數(shù)據(jù)量。
2)一個(gè)主服務(wù)器可以有多個(gè)從服務(wù)器。
3)從服務(wù)器也可以接受其他從服務(wù)器的連接。除了多個(gè)從服務(wù)器連接到一個(gè)主服務(wù)器之外,多個(gè)從服務(wù)器也可以連接到一個(gè)從服務(wù)器上,形成一個(gè)圖狀結(jié)構(gòu)。
4)Redis主從復(fù)制不阻塞主服務(wù)器端。也就是說當(dāng)若干個(gè)從服務(wù)器在進(jìn)行初始同步時(shí),主服務(wù)器仍然可以處理請(qǐng)求。
5)主從復(fù)制也不阻塞從服務(wù)器端。當(dāng)從服務(wù)器進(jìn)行初始同步時(shí),它使用舊版本的數(shù)據(jù)來應(yīng)對(duì)查詢請(qǐng)求,假設(shè)你在redis.conf配置文件是這么配置的。否則的話,你可以配置當(dāng)復(fù)制流關(guān)閉時(shí)讓從服務(wù)器給客戶端返回一個(gè)錯(cuò)誤。但是,當(dāng)初始同步完成后,需要?jiǎng)h除舊的數(shù)據(jù)集和加載新的數(shù)據(jù)集,在這個(gè)短暫的時(shí)間內(nèi),從服務(wù)器會(huì)阻塞連接進(jìn)來的請(qǐng)求。
6)主從復(fù)制可以用來增強(qiáng)擴(kuò)展性,使用多個(gè)從服務(wù)器來處理只讀的請(qǐng)求(比如,繁重的排序操作可以放到從服務(wù)器去做),也可以簡(jiǎn)單的用來做數(shù)據(jù)冗余。
7)使用主從復(fù)制可以為主服務(wù)器免除把數(shù)據(jù)寫入磁盤的消耗:在主服務(wù)器的redis.conf文件中配置“避免保存”(注釋掉所有“保存“命令),然后連接一個(gè)配置為“進(jìn)行保存”的從服務(wù)器即可。但是這個(gè)配置要確保主服務(wù)器不會(huì)自動(dòng)重啟(要獲得更多信息請(qǐng)閱讀下一段)


主從復(fù)制的一些特點(diǎn):

1)采用異步復(fù)制;
2)一個(gè)主redis可以含有多個(gè)從redis;
3)每個(gè)從redis可以接收來自其他從redis服務(wù)器的連接;
4)主從復(fù)制對(duì)于主redis服務(wù)器來說是非阻塞的,這意味著當(dāng)從服務(wù)器在進(jìn)行主從復(fù)制同步過程中,主redis仍然可以處理外界的訪問請(qǐng)求;
5)主從復(fù)制對(duì)于從redis服務(wù)器來說也是非阻塞的,這意味著,即使從redis在進(jìn)行主從復(fù)制過程中也可以接受外界的查詢請(qǐng)求,只不過這時(shí)候從redis返回的是以前老的數(shù)據(jù),如果你不想這樣,那么在啟動(dòng)redis時(shí),可以在配置文件中進(jìn)行設(shè)置,那么從redis在復(fù)制同步過程中來自外界的查詢請(qǐng)求都會(huì)返回錯(cuò)誤給客戶端;(雖然說主從復(fù)制過程中對(duì)于從redis是非阻塞的,但是當(dāng)從redis從主redis同步過來最新的數(shù)據(jù)后還需要將新數(shù)據(jù)加載到內(nèi)存中,在加載到內(nèi)存的過程中是阻塞的,在這段時(shí)間內(nèi)的請(qǐng)求將會(huì)被阻,但是即使對(duì)于大數(shù)據(jù)集,加載到內(nèi)存的時(shí)間也是比較多的);
6)主從復(fù)制提高了redis服務(wù)的擴(kuò)展性,避免單個(gè)redis服務(wù)器的讀寫訪問壓力過大的問題,同時(shí)也可以給為數(shù)據(jù)備份及冗余提供一種解決方案;
7)為了編碼主redis服務(wù)器寫磁盤壓力帶來的開銷,可以配置讓主redis不在將數(shù)據(jù)持久化到磁盤,而是通過連接讓一個(gè)配置的從redis服務(wù)器及時(shí)的將相關(guān)數(shù)據(jù)持久化到磁盤,不過這樣會(huì)存在一個(gè)問題,就是主redis服務(wù)器一旦重啟,因?yàn)橹鱮edis服務(wù)器數(shù)據(jù)為空,這時(shí)候通過主從同步可能導(dǎo)致從redis服務(wù)器上的數(shù)據(jù)也被清空;


Redis大概主從同步是怎么實(shí)現(xiàn)的?

全量同步:

master服務(wù)器會(huì)開啟一個(gè)后臺(tái)進(jìn)程用于將redis中的數(shù)據(jù)生成一個(gè)rdb文件,與此同時(shí),服務(wù)器會(huì)緩存所有接收到的來自客戶端的寫命令(包含增、刪、改),當(dāng)后臺(tái)保存進(jìn)程處理完畢后,會(huì)將該rdb文件傳遞給slave服務(wù)器,而slave服務(wù)器會(huì)將rdb文件保存在磁盤并通過讀取該文件將數(shù)據(jù)加載到內(nèi)存,在此之后master服務(wù)器會(huì)將在此期間緩存的命令通過redis傳輸協(xié)議發(fā)送給slave服務(wù)器,然后slave服務(wù)器將這些命令依次作用于自己本地的數(shù)據(jù)集上最終達(dá)到數(shù)據(jù)的一致性。

部分同步:

從redis 2.8版本以前,并不支持部分同步,當(dāng)主從服務(wù)器之間的連接斷掉之后,master服務(wù)器和slave服務(wù)器之間都是進(jìn)行全量數(shù)據(jù)同步,但是從redis 2.8開始,即使主從連接中途斷掉,也不需要進(jìn)行全量同步,因?yàn)閺倪@個(gè)版本開始融入了部分同步的概念。部分同步的實(shí)現(xiàn)依賴于在master服務(wù)器內(nèi)存中給每個(gè)slave服務(wù)器維護(hù)了一份同步日志和同步標(biāo)識(shí),每個(gè)slave服務(wù)器在跟master服務(wù)器進(jìn)行同步時(shí)都會(huì)攜帶自己的同步標(biāo)識(shí)和上次同步的最后位置。當(dāng)主從連接斷掉之后,slave服務(wù)器隔斷時(shí)間(默認(rèn)1s)主動(dòng)嘗試和master服務(wù)器進(jìn)行連接,如果從服務(wù)器攜帶的偏移量標(biāo)識(shí)還在master服務(wù)器上的同步備份日志中,那么就從slave發(fā)送的偏移量開始繼續(xù)上次的同步操作,如果slave發(fā)送的偏移量已經(jīng)不再master的同步備份日志中(可能由于主從之間斷掉的時(shí)間比較長(zhǎng)或者在斷掉的短暫時(shí)間內(nèi)master服務(wù)器接收到大量的寫操作),則必須進(jìn)行一次全量更新。在部分同步過程中,master會(huì)將本地記錄的同步備份日志中記錄的指令依次發(fā)送給slave服務(wù)器從而達(dá)到數(shù)據(jù)一致。


主從同步中需要注意幾個(gè)問題

1)在上面的全量同步過程中,master會(huì)將數(shù)據(jù)保存在rdb文件中然后發(fā)送給slave服務(wù)器,但是如果master上的磁盤空間有效怎么辦呢?那么此時(shí)全部同步對(duì)于master來說將是一份十分有壓力的操作了。此時(shí)可以通過無盤復(fù)制來達(dá)到目的,由master直接開啟一個(gè)socket將rdb文件發(fā)送給slave服務(wù)器。(無盤復(fù)制一般應(yīng)用在磁盤空間有限但是網(wǎng)絡(luò)狀態(tài)良好的情況下)

2)主從復(fù)制結(jié)構(gòu),一般slave服務(wù)器不能進(jìn)行寫操作,但是這不是死的,之所以這樣是為了更容易的保證主和各個(gè)從之間數(shù)據(jù)的一致性,如果slave服務(wù)器上數(shù)據(jù)進(jìn)行了修改,那么要保證所有主從服務(wù)器都能一致,可能在結(jié)構(gòu)上和處理邏輯上更為負(fù)責(zé)。不過你也可以通過配置文件讓從服務(wù)器支持寫操作。(不過所帶來的影響還得自己承擔(dān)哦。。。)

3)主從服務(wù)器之間會(huì)定期進(jìn)行通話,但是如果master上設(shè)置了密碼,那么如果不給slave設(shè)置密碼就會(huì)導(dǎo)致slave不能跟master進(jìn)行任何操作,所以如果你的master服務(wù)器上有密碼,那么也給slave相應(yīng)的設(shè)置一下密碼吧(通過設(shè)置配置文件中的masterauth);

4)關(guān)于slave服務(wù)器上過期鍵的處理,由master服務(wù)器負(fù)責(zé)鍵的過期刪除處理,然后將相關(guān)刪除命令已數(shù)據(jù)同步的方式同步給slave服務(wù)器,slave服務(wù)器根據(jù)刪除命令刪除本地的key。`


當(dāng)主服務(wù)器不進(jìn)行持久化時(shí)復(fù)制的安全性

在進(jìn)行主從復(fù)制設(shè)置時(shí),強(qiáng)烈建議在主服務(wù)器上開啟持久化,當(dāng)不能這么做時(shí),比如考慮到延遲的問題,應(yīng)該將實(shí)例配置為避免自動(dòng)重啟。

為什么不持久化的主服務(wù)器自動(dòng)重啟非常危險(xiǎn)呢?

為了更好的理解這個(gè)問題,看下面這個(gè)失敗的例子,其中主服務(wù)器和從服務(wù)器中數(shù)據(jù)庫(kù)都被刪除了。

設(shè)置節(jié)點(diǎn)A為主服務(wù)器,關(guān)閉持久化,節(jié)點(diǎn)B和C從節(jié)點(diǎn)A復(fù)制數(shù)據(jù)。
這時(shí)出現(xiàn)了一個(gè)崩潰,但Redis具有自動(dòng)重啟系統(tǒng),重啟了進(jìn)程,因?yàn)殛P(guān)閉了持久化,節(jié)點(diǎn)重啟后只有一個(gè)空的數(shù)據(jù)集。
節(jié)點(diǎn)B和C從節(jié)點(diǎn)A進(jìn)行復(fù)制,現(xiàn)在節(jié)點(diǎn)A是空的,所以節(jié)點(diǎn)B和C上的復(fù)制數(shù)據(jù)也會(huì)被刪除。
當(dāng)在高可用系統(tǒng)中使用Redis Sentinel,關(guān)閉了主服務(wù)器的持久化,并且允許自動(dòng)重啟,這種情況是很危險(xiǎn)的。
比如主服務(wù)器可能在很短的時(shí)間就完成了重啟,以至于Sentinel都無法檢測(cè)到這次失敗,那么上面說的這種失敗的情況就發(fā)生了。

如果數(shù)據(jù)比較重要,并且在使用主從復(fù)制時(shí)關(guān)閉了主服務(wù)器持久化功能的場(chǎng)景中,都應(yīng)該禁止實(shí)例自動(dòng)重啟。


Redis主從復(fù)制是如何工作的

如果設(shè)置了一個(gè)從服務(wù)器,在連接時(shí)它發(fā)送了一個(gè)SYNC命令,不管它是第一次連接還是再次連接都沒有關(guān)系。

然后主服務(wù)器開始后臺(tái)存儲(chǔ),并且開始緩存新連接進(jìn)來的修改數(shù)據(jù)的命令。當(dāng)后臺(tái)存儲(chǔ)完成后,主服務(wù)器把數(shù)據(jù)文件發(fā)送到從服務(wù)器,從服務(wù)器將其保存在磁盤上,然后加載到內(nèi)存中。然后主服務(wù)器把剛才緩存的命令發(fā)送到從服務(wù)器。這是作為命令流來完成的,并且和Redis協(xié)議本身格式相同。

你可以通過telnet自己嘗試一下。在Redis服務(wù)器工作時(shí)連接到Redis端口,發(fā)送SYNC命令,會(huì)看到一個(gè)批量的傳輸,并且主服務(wù)器接收的每一個(gè)命令都會(huì)通過telnet會(huì)話重新發(fā)送一遍。

當(dāng)主從服務(wù)器之間的連接由于某些原因斷開時(shí),從服務(wù)器可以自動(dòng)進(jìn)行重連接。當(dāng)有多個(gè)從服務(wù)器同時(shí)請(qǐng)求同步時(shí),主服務(wù)器只進(jìn)行一個(gè)后臺(tái)存儲(chǔ)。

當(dāng)連接斷開又重新連上之后,一般都會(huì)進(jìn)行一個(gè)完整的重新同步,但是從Redis2.8開始,只重新同步一部分也可以。


部分重新同步

從Redis 2.8開始,如果遭遇連接斷開,重新連接之后可以從中斷處繼續(xù)進(jìn)行復(fù)制,而不必重新同步。

它的工作原理是這樣:

主服務(wù)器端為復(fù)制流維護(hù)一個(gè)內(nèi)存緩沖區(qū)(in-memory backlog)。主從服務(wù)器都維護(hù)一個(gè)復(fù)制偏移量(replication offset)和master run id
當(dāng)連接斷開時(shí),從服務(wù)器會(huì)重新連接上主服務(wù)器,然后請(qǐng)求繼續(xù)復(fù)制,假如主從服務(wù)器的兩個(gè)master run id相同,并且指定的偏移量在內(nèi)存緩沖區(qū)中還有效,復(fù)制就會(huì)從上次中斷的點(diǎn)開始繼續(xù)。如果其中一個(gè)條件不滿足,就會(huì)進(jìn)行完全重新同步(在2.8版本之前就是直接進(jìn)行完全重新同步)。因?yàn)橹鬟\(yùn)行id不保存在磁盤中,如果從服務(wù)器重啟了的話就只能進(jìn)行完全同步了。

部分重新同步這個(gè)新特性內(nèi)部使用PSYNC命令,舊的實(shí)現(xiàn)中使用SYNC命令。Redis2.8版本可以檢測(cè)出它所連接的服務(wù)器是否支持PSYNC命令,不支持的話使用SYNC命令。


無磁盤復(fù)制

通常來講,一個(gè)完全重新同步需要在磁盤上創(chuàng)建一個(gè)RDB文件,然后加載這個(gè)文件以便為從服務(wù)器發(fā)送數(shù)據(jù)。

如果使用比較低速的磁盤,這種操作會(huì)給主服務(wù)器帶來較大的壓力。Redis從2.8.18版本開始嘗試支持無磁盤的復(fù)制。
使用這種設(shè)置時(shí),子進(jìn)程直接將RDB通過網(wǎng)絡(luò)發(fā)送給從服務(wù)器,不使用磁盤作為中間存儲(chǔ)。


配置

主從復(fù)制的配置十分簡(jiǎn)單:把下面這行加入到從服務(wù)器的配置文件中即可。
slaveof 192.168.1.1 6379

當(dāng)然你需要把其中的192.168.1.1 6379替換為你自己的主服務(wù)器IP(或者主機(jī)名hostname)和端口。另外你可以調(diào)用SLAVEOF命令,
主服務(wù)器就會(huì)開始與從服務(wù)器同步。

關(guān)于部分重新同步,還有一些針對(duì)復(fù)制內(nèi)存緩沖區(qū)的優(yōu)化參數(shù)。查看Redis介質(zhì)中的Redis.conf示例獲得更多信息。

使用repl-diskless-sync配置參數(shù)來啟動(dòng)無磁盤復(fù)制。使用repl-diskless-sync-delay 參數(shù)來配置傳輸開始的延遲時(shí)間,以便等待更多的從服務(wù)器連接上來。查看Redis介質(zhì)中的Redis.conf示例獲得更多信息。


只讀從服務(wù)器

從Redis 2.6開始,從服務(wù)器支持只讀模式,并且是默認(rèn)模式。這個(gè)行為是由Redis.conf文件中的slave-read-only 參數(shù)控制的,可以在運(yùn)行中通過CONFIG SET來啟用或者禁用。

只讀的從服務(wù)器會(huì)拒絕所有寫命令,所以對(duì)從服務(wù)器不會(huì)有誤寫操作。但這不表示可以把從服務(wù)器實(shí)例暴露在危險(xiǎn)的網(wǎng)絡(luò)環(huán)境下,因?yàn)橄馜EBUG或者CONFIG這樣的管理命令還是可以運(yùn)行的。不過你可以通過使用rename-command命令來為這些命令改名來增加安全性。

你可能想知道為什么只讀限制還可以被還原,使得從服務(wù)器還可以進(jìn)行寫操作。雖然當(dāng)主從服務(wù)器進(jìn)行重新同步或者從服務(wù)器重啟后,這些寫操作都會(huì)失效,還是有一些使用場(chǎng)景會(huì)想從服務(wù)器中寫入臨時(shí)數(shù)據(jù)的,但將來這個(gè)特性可能會(huì)被去掉。


限制有N個(gè)以上從服務(wù)器才允許寫入

從Redis 2.8版本開始,可以配置主服務(wù)器連接N個(gè)以上從服務(wù)器才允許對(duì)主服務(wù)器進(jìn)行寫操作。但是,因?yàn)镽edis使用的是異步主從復(fù)制,沒辦法確保從服務(wù)器確實(shí)收到了要寫入的數(shù)據(jù),所以還是有一定的數(shù)據(jù)丟失的可能性。

這一特性的工作原理如下:
1)從服務(wù)器每秒鐘ping一次主服務(wù)器,確認(rèn)處理的復(fù)制流數(shù)量。
2)主服務(wù)器記住每個(gè)從服務(wù)器最近一次ping的時(shí)間。
3)用戶可以配置最少要有N個(gè)服務(wù)器有小于M秒的確認(rèn)延遲。
4)如果有N個(gè)以上從服務(wù)器,并且確認(rèn)延遲小于M秒,主服務(wù)器接受寫操作。

還可以把這看做是CAP原則(一致性,可用性,分區(qū)容錯(cuò)性)不嚴(yán)格的一致性實(shí)現(xiàn),雖然不能百分百確保一致性,但至少保證了丟失的數(shù)據(jù)不會(huì)超過M秒內(nèi)的數(shù)據(jù)量。

如果條件不滿足,主服務(wù)器會(huì)拒絕寫操作并返回一個(gè)錯(cuò)誤。
1)min-slaves-to-write(最小從服務(wù)器數(shù))
2)min-slaves-max-lag(從服務(wù)器最大確認(rèn)延遲)


====== 通過redis實(shí)現(xiàn)服務(wù)器崩潰等數(shù)據(jù)恢復(fù) ======
由于redis存儲(chǔ)在內(nèi)存中且提供一般編程語言常用的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)類型,所以經(jīng)常被用于做服務(wù)器崩潰宕機(jī)的數(shù)據(jù)恢復(fù)處理。服務(wù)器可以在某些指定過程中將需要保存的數(shù)據(jù)以json對(duì)象等方式存儲(chǔ)到redis中,也就是我們常說的快照,當(dāng)服務(wù)器運(yùn)行時(shí)讀取redis來判斷是否有待需要恢復(fù)數(shù)據(jù)繼續(xù)處理的業(yè)務(wù)。當(dāng)一次業(yè)務(wù)處理結(jié)束后再刪除redis的數(shù)據(jù)即可。redis提供兩種將內(nèi)存數(shù)據(jù)導(dǎo)出到硬盤實(shí)現(xiàn)數(shù)據(jù)備份的方法

1)RDB方式(默認(rèn))
RDB方式的持久化是通過快照(snapshotting)完成的,當(dāng)符合一定條件時(shí)Redis會(huì)自動(dòng)將內(nèi)存中的所有數(shù)據(jù)進(jìn)行快照并存儲(chǔ)在硬盤上。進(jìn)行快照的條件可以由用戶在配置文件中自定義,由兩個(gè)參數(shù)構(gòu)成:時(shí)間和改動(dòng)的鍵的個(gè)數(shù)。當(dāng)在指定的時(shí)間內(nèi)被更改的鍵的個(gè)數(shù)大于指定的數(shù)值時(shí)就會(huì)進(jìn)行快照。RDB是redis默認(rèn)采用的持久化方式,在配置文件中已經(jīng)預(yù)置了3個(gè)條件:
save 900 1 #900秒內(nèi)有至少1個(gè)鍵被更改則進(jìn)行快照
save 300 10 #300秒內(nèi)有至少10個(gè)鍵被更改則進(jìn)行快照
save 60 10000 #60秒內(nèi)有至少10000個(gè)鍵被更改則進(jìn)行快照

可以存在多個(gè)條件,條件之間是"或"的關(guān)系,只要滿足其中一個(gè)條件,就會(huì)進(jìn)行快照。 如果想要禁用自動(dòng)快照,只需要將所有的save參數(shù)刪除即可。
Redis默認(rèn)會(huì)將快照文件存儲(chǔ)在當(dāng)前目錄(可CONFIG GET dir來查看)的dump.rdb文件中,可以通過配置dir和dbfilename兩個(gè)參數(shù)分別指定快照文件的存儲(chǔ)路徑和文件名。

Redis實(shí)現(xiàn)快照的過程

  • Redis使用fork函數(shù)復(fù)制一份當(dāng)前進(jìn)程(父進(jìn)程)的副本(子進(jìn)程);
  • 父進(jìn)程繼續(xù)接收并處理客戶端發(fā)來的命令,而子進(jìn)程開始將內(nèi)存中的數(shù)據(jù)寫入硬盤中的臨時(shí)文件;
  • 當(dāng)子進(jìn)程寫入完所有數(shù)據(jù)后會(huì)用該臨時(shí)文件替換舊的RDB文件,至此一次快照操作完成。
  • 在執(zhí)行fork的時(shí)候操作系統(tǒng)(類Unix操作系統(tǒng))會(huì)使用寫時(shí)復(fù)制(copy-on-write)策略,即fork函數(shù)發(fā)生的一刻父子進(jìn)程共享同一內(nèi)存數(shù)據(jù),當(dāng)父進(jìn)程要更改其中某片數(shù)據(jù)時(shí)(如執(zhí)行一個(gè)寫命令 ),操作系統(tǒng)會(huì)將該片數(shù)據(jù)復(fù)制一份以保證子進(jìn)程的數(shù)據(jù)不受影響,所以新的RDB文件存儲(chǔ)的是執(zhí)行fork一刻的內(nèi)存數(shù)據(jù)。

Redis在進(jìn)行快照的過程中不會(huì)修改RDB文件,只有快照結(jié)束后才會(huì)將舊的文件替換成新的,也就是說任何時(shí)候RDB文件都是完整的。這使得我們可以通過定時(shí)備份RDB文件來實(shí) 現(xiàn)Redis數(shù)據(jù)庫(kù)備份。RDB文件是經(jīng)過壓縮(可以配置rdbcompression參數(shù)以禁用壓縮節(jié)省CPU占用)的二進(jìn)制格式,所以占用的空間會(huì)小于內(nèi)存中的數(shù)據(jù)大小,更加利于傳輸。

除了自動(dòng)快照,還可以手動(dòng)發(fā)送SAVE或BGSAVE命令讓Redis執(zhí)行快照,兩個(gè)命令的區(qū)別在于,前者是由主進(jìn)程進(jìn)行快照操作,會(huì)阻塞住其他請(qǐng)求,后者會(huì)通過fork子進(jìn)程進(jìn)行快照操作。 Redis啟動(dòng)后會(huì)讀取RDB快照文件,將數(shù)據(jù)從硬盤載入到內(nèi)存。根據(jù)數(shù)據(jù)量大小與結(jié)構(gòu)和服務(wù)器性能不同,這個(gè)時(shí)間也不同。通常將一個(gè)記錄一千萬個(gè)字符串類型鍵、大小為1GB的快照文件載入到內(nèi) 存中需要花費(fèi)20~30秒鐘。 通過RDB方式實(shí)現(xiàn)持久化,一旦Redis異常退出,就會(huì)丟失最后一次快照以后更改的所有數(shù)據(jù)。這就需要開發(fā)者根據(jù)具體的應(yīng)用場(chǎng)合,通過組合設(shè)置自動(dòng)快照條件的方式來將可能發(fā)生的數(shù)據(jù)損失控制在能夠接受的范圍。如果數(shù)據(jù)很重要以至于無法承受任何損失,則可以考慮使用AOF方式進(jìn)行持久化。

2)AOF方式
默認(rèn)情況下Redis沒有開啟AOF(append only file)方式的持久化,可以在redis.conf中通過appendonly參數(shù)開啟:

appendonly yes
在啟動(dòng)時(shí)Redis會(huì)逐個(gè)執(zhí)行AOF文件中的命令來將硬盤中的數(shù)據(jù)載入到內(nèi)存中,載入的速度相較RDB會(huì)慢一些

開啟AOF持久化后每執(zhí)行一條會(huì)更改Redis中的數(shù)據(jù)的命令,Redis就會(huì)將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數(shù)設(shè)置的,默認(rèn)的文件名是appendonly.aof,可以通過appendfilename參數(shù)修改:

appendfilename appendonly.aof
配置redis自動(dòng)重寫AOF文件的條件

auto-aof-rewrite-percentage 100 # 當(dāng)目前的AOF文件大小超過上一次重寫時(shí)的AOF文件大小的百分之多少時(shí)會(huì)再次進(jìn)行重寫,如果之前沒有重寫過,則以啟動(dòng)時(shí)的AOF文件大小為依據(jù)

auto-aof-rewrite-min-size 64mb # 允許重寫的最小AOF文件大小
配置寫入AOF文件后,要求系統(tǒng)刷新硬盤緩存的機(jī)制

appendfsync always # 每次執(zhí)行寫入都會(huì)執(zhí)行同步,最安全也最慢

appendfsync everysec # 每秒執(zhí)行一次同步操作

appendfsync no # 不主動(dòng)進(jìn)行同步操作,而是完全交由操作系統(tǒng)來做(即每30秒一次),最快也最不安全

Redis允許同時(shí)開啟AOF和RDB,既保證了數(shù)據(jù)安全又使得進(jìn)行備份等操作十分容易。此時(shí)重新啟動(dòng)Redis后Redis會(huì)使用AOF文件來恢復(fù)數(shù)據(jù),因?yàn)锳OF方式的持久化可能丟失的數(shù)據(jù)更少


引用(本文章只供本人學(xué)習(xí)以及學(xué)習(xí)的記錄,如有侵權(quán),請(qǐng)聯(lián)系我刪除)

Redis主從復(fù)制原理總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容