十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶(hù) + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂(yōu)售后,網(wǎng)站問(wèn)題一站解決
1. 單機(jī)故障

如果發(fā)生機(jī)器故障,例如磁盤(pán)損壞,主板損壞等,未能在短時(shí)間內(nèi)修復(fù)好,客戶(hù)端將無(wú)法連接redis。
當(dāng)然如果僅僅是redis節(jié)點(diǎn)掛掉了,可以進(jìn)行問(wèn)題排查然后重啟,姑且不考慮這段時(shí)間對(duì)外服務(wù)的可用性,那還是可以接受的。而發(fā)生機(jī)器故障,基本是無(wú)濟(jì)于事。除非把redis遷移到另一臺(tái)機(jī)器上,并且還要考慮數(shù)據(jù)同步的問(wèn)題。
2. 容量瓶頸
假如一臺(tái)機(jī)器是16G內(nèi)存,redis使用了12G內(nèi)存,而其他應(yīng)用還需要使用內(nèi)存,假設(shè)我們總共需要60G內(nèi)存要如何去做呢,是否有必要購(gòu)買(mǎi)64G內(nèi)存的機(jī)器呢?
3. QPS瓶頸
redis官方數(shù)據(jù)顯示可以達(dá)到10w的QPS,如果業(yè)務(wù)需要100w的QPS怎么去做呢?
關(guān)于容量瓶頸和QPS瓶頸是redis分布式需要解決的問(wèn)題,而機(jī)器故障就是高可用的問(wèn)題了。
2、單機(jī)故障解決方法在分布式系統(tǒng)中為了解決單點(diǎn)問(wèn)題,通常會(huì)把數(shù)據(jù)復(fù)制多個(gè)副本部署到其他機(jī)器(主從模式),滿(mǎn)足故障恢復(fù)和負(fù)載均衡的需求。
redis也是如此,它為我們提供了復(fù)制功能,實(shí)現(xiàn)了相同數(shù)據(jù)的多個(gè)redis副本(復(fù)制功能是高可用redis的基礎(chǔ),哨兵和集群都是在復(fù)制的基礎(chǔ)上實(shí)現(xiàn)高可用的)。
但是這樣會(huì)有如下問(wèn)題,多個(gè)副本之間的數(shù)據(jù)如何保持一致呢?數(shù)據(jù)讀寫(xiě)操作可以發(fā)送給所有實(shí)例呢?
實(shí)際上,Redis 提供了主從庫(kù)模式,以保證數(shù)據(jù)副本的一致,主從庫(kù)之間采用的是讀寫(xiě)分離的方式。

即:

說(shuō)明:?
在了解 Redis 的主從復(fù)制之前,讓我們先來(lái)理解一下現(xiàn)代分布式系統(tǒng)的理論基石——CAP 原理。
CAP 原理是分布式存儲(chǔ)的理論基石:
分布式系統(tǒng)的節(jié)點(diǎn)往往都是分布在不同的機(jī)器上進(jìn)行網(wǎng)絡(luò)隔離開(kāi)的,這意味著必然會(huì)有網(wǎng)絡(luò)斷開(kāi)的風(fēng)險(xiǎn),這個(gè)網(wǎng)絡(luò)斷開(kāi)的場(chǎng)景的專(zhuān)業(yè)詞匯叫做”網(wǎng)絡(luò)分區(qū)“。
在網(wǎng)絡(luò)分區(qū)發(fā)生時(shí),兩個(gè)分布式節(jié)點(diǎn)無(wú)法進(jìn)行通信,我們對(duì)一個(gè)節(jié)點(diǎn)進(jìn)行的修改操作將無(wú)法同步到另外一個(gè)節(jié)點(diǎn),所以數(shù)據(jù)的”一致性“將無(wú)法滿(mǎn)足,因?yàn)閮蓚€(gè)分布式節(jié)點(diǎn)的數(shù)據(jù)不再保持一致。除非我們犧牲”可用性“,也就是暫停分布式節(jié)點(diǎn)服務(wù),在網(wǎng)絡(luò)分區(qū)發(fā)生時(shí),不再提供修改數(shù)據(jù)的功能,直到網(wǎng)絡(luò)狀況完全恢復(fù)正常再繼續(xù)對(duì)外提供服務(wù)。
一句話(huà)概括 CAP 原理就是——網(wǎng)絡(luò)分區(qū)發(fā)生時(shí),一致性和可用性?xún)呻y全。
2、Redis主從同步最終一致性Redis 的主從數(shù)據(jù)是 異步 復(fù)制的,所以分布式的 Redis 系統(tǒng)并不滿(mǎn)足一致性要求。當(dāng)客戶(hù)端在 Redis 的主節(jié)點(diǎn)修改了數(shù)據(jù)后,立即返回,即使在主從網(wǎng)絡(luò)斷開(kāi)的情況下,主節(jié)點(diǎn)依舊可以正常對(duì)外提供服務(wù),所以 Redis 滿(mǎn)足可用性。
而 Redis 其實(shí)是保證 ”最終一致性“,從節(jié)點(diǎn)會(huì)努力追趕主節(jié)點(diǎn),最終從節(jié)點(diǎn)的狀態(tài)會(huì)和主節(jié)點(diǎn)的狀態(tài)保持一致。如果網(wǎng)絡(luò)斷開(kāi)了,主從節(jié)點(diǎn)的數(shù)據(jù)將會(huì)出現(xiàn)大量不一致,一旦網(wǎng)絡(luò)恢復(fù),從節(jié)點(diǎn)會(huì)采用多種策略努力追趕上落后的數(shù)據(jù),繼續(xù)盡力保持和主節(jié)點(diǎn)一致。
三、主從復(fù)制類(lèi)型 1、主備與主從1. 主備
請(qǐng)求都只能打到Master主節(jié)點(diǎn)上,備機(jī)只是等主機(jī)掛了后來(lái)自動(dòng)升級(jí)為客戶(hù)端繼續(xù)提供服務(wù)。也就是說(shuō)他不會(huì)為主節(jié)點(diǎn)分?jǐn)傉?qǐng)求壓力。
2. 主從
讀請(qǐng)求會(huì)均攤到主節(jié)點(diǎn)和從節(jié)點(diǎn)上,而不是等主機(jī)掛了才提供服務(wù)。寫(xiě)請(qǐng)求在master上進(jìn)行,然后同步到slaver。讀請(qǐng)求會(huì)分?jǐn)?,比?0w個(gè)請(qǐng)求,一主雙從的話(huà),可能M上3w個(gè),兩個(gè)S上處理6w個(gè),他會(huì)為主節(jié)點(diǎn)分?jǐn)倝毫?。所以可以解決單點(diǎn)故障問(wèn)題。
2、主從復(fù)制三種類(lèi)型1.?同步阻塞
這種方式講究強(qiáng)一致性,必須等所有Slave都寫(xiě)入成功后我才會(huì)給客戶(hù)端響應(yīng),否則一直阻塞。也是CAP中的C。
原理圖:

2. 異步非阻塞
Redis采取的這種方式。沒(méi)有采取下面同步阻塞mq的方式可能也是因?yàn)樾拾?,因?yàn)镽edis就是要高效??蛻?hù)端發(fā)完請(qǐng)求到Redis Master后,立馬給客戶(hù)端返回,我不管你Slaver是否同步完成。保留CAP的A,舍棄C。
原理圖:

3. 同步阻塞MQ
大數(shù)據(jù)hive采取的就是這種方式,他會(huì)保證最終一致性。相對(duì)于第二種方式好處在于能保證數(shù)據(jù)的最終一致性,壞處在于沒(méi)第二種方式高效,但第二種存在丟數(shù)據(jù)的風(fēng)險(xiǎn)。

主從復(fù)制其實(shí)就是實(shí)現(xiàn)高可用(雖然是人工操作),避免單點(diǎn)故障問(wèn)題。掛掉一個(gè)節(jié)點(diǎn),我其他節(jié)點(diǎn)可以接著提供服務(wù),但是明顯缺點(diǎn)發(fā)現(xiàn)是Slave掛掉還好,Master掛掉可就難受了,Slave太多的話(huà)那就夠運(yùn)維折騰的了,這時(shí)候就有了哨兵。 同時(shí),Redis雖然讀取寫(xiě)入的速度都特別快,但是也會(huì)產(chǎn)生讀壓力特別大的情況,主從復(fù)制也能夠分擔(dān)讀壓力。
主從復(fù)制原理圖:

其實(shí)就跟MySQL一個(gè)道理,mysql是靠binlog,而Redis靠的是rdb文件和aof文件。
2、主從復(fù)制實(shí)現(xiàn)原理總的來(lái)說(shuō)主從復(fù)制功能的詳細(xì)步驟可以分為7個(gè)步驟:
設(shè)置主節(jié)點(diǎn)的地址和端口-》建立套接字鏈接-》發(fā)送PING命令-》權(quán)限驗(yàn)證-》同步-》命令傳播
接下來(lái)分別敘述每個(gè)步驟,整個(gè)流程圖如下:

假設(shè)在本地機(jī)開(kāi)啟兩個(gè)Redis節(jié)點(diǎn),分別監(jiān)聽(tīng):
1. 設(shè)置主服務(wù)器的地址和端口
第一步首先是在從服務(wù)器設(shè)置需要同步的主服務(wù)器信息,包括機(jī)器IP,端口。
主從復(fù)制的開(kāi)啟,完全是從節(jié)點(diǎn)發(fā)起;不需要我們?cè)谥鞴?jié)點(diǎn)做任何事情。
從節(jié)點(diǎn)開(kāi)啟主從復(fù)制,有3種方式:
(1)配置文件
在從服務(wù)器的配置文件中加入:
slaveof masterip masterport(2)啟動(dòng)命令
redis-server啟動(dòng)命令后加入:
slaveof masterip masterport(3)客戶(hù)端命令
Redis服務(wù)器啟動(dòng)后,直接通過(guò)客戶(hù)端執(zhí)行命令:
slaveof masterip masterport則該Redis實(shí)例稱(chēng)為從節(jié)點(diǎn)。
上述3種方法是等效的,下面以客戶(hù)端命令的方式為例,看一下當(dāng)執(zhí)行了slaveof后,Redis主節(jié)點(diǎn)和從節(jié)點(diǎn)的變化。從服務(wù)器會(huì)將主服務(wù)器的ip地址和端口號(hào)保存到服務(wù)器狀態(tài)的屬性里面,可以使用Redis命令 info replication 分別查看從服務(wù)器和主服務(wù)器的主從信息。
2. 建立套接字連接
在slaveof命令執(zhí)行之后,從服務(wù)器會(huì)根據(jù)設(shè)置的ip和端口,向主服務(wù)器建立socket連接。
在6380從服務(wù)器里面執(zhí)行完 slave of 127.0.0.1 6379 后意味著,從服務(wù)器向主服務(wù)器發(fā)起 socket 連接。
在執(zhí)行info Replication 命令分別查看從服務(wù)器的主從信息:

而6379服務(wù)器已經(jīng)成為主服務(wù)器角色:?

3. 發(fā)送PING命令
從節(jié)點(diǎn)成為了主節(jié)點(diǎn)的客戶(hù)端之后,發(fā)送 ping 命令進(jìn)行首次請(qǐng)求,目的是:檢查socket連接是否可用,以及主節(jié)點(diǎn)當(dāng)前是否能夠處理請(qǐng)求。
從節(jié)點(diǎn)發(fā)送 ping 命令后,可能出現(xiàn)3種情況:
4. 身份驗(yàn)證
如果從節(jié)點(diǎn)中設(shè)置了masterauth選項(xiàng),則從節(jié)點(diǎn)需要向主節(jié)點(diǎn)進(jìn)行身份驗(yàn)證;沒(méi)有設(shè)置該選項(xiàng),則不需要驗(yàn)證。從節(jié)點(diǎn)進(jìn)行身份驗(yàn)證是通過(guò)向主節(jié)點(diǎn)發(fā)送auth命令進(jìn)行的,auth命令的參數(shù)即為配置文件中的masterauth的值。
如果主節(jié)點(diǎn)設(shè)置密碼的狀態(tài),與從節(jié)點(diǎn)masterauth的狀態(tài)一致(一致是指都存在,且密碼相同,或者都不存在),則身份驗(yàn)證通過(guò),復(fù)制過(guò)程繼續(xù);如果不一致,則從節(jié)點(diǎn)斷開(kāi)socket連接,并重連。
5. 同步
同步就是將從節(jié)點(diǎn)的數(shù)據(jù)庫(kù)狀態(tài)更新成主節(jié)點(diǎn)當(dāng)前的數(shù)據(jù)庫(kù)狀態(tài)。具體執(zhí)行的方式是:從節(jié)點(diǎn)向主節(jié)點(diǎn)發(fā)送psync命令(Redis2.8以前是sync命令),開(kāi)始同步。
數(shù)據(jù)同步階段是主從復(fù)制最核心的階段,根據(jù)主從節(jié)點(diǎn)當(dāng)前狀態(tài)的不同,可以分為 全量復(fù)制 和 部分復(fù)制。

6. 命令傳播
經(jīng)過(guò)上面同步操作,此時(shí)主從的數(shù)據(jù)庫(kù)狀態(tài)其實(shí)已經(jīng)一致了,但這種一致的狀態(tài)并不是一成不變的。
在完成同步之后,也許主服務(wù)器馬上就接受到了新的寫(xiě)命令,執(zhí)行完該命令后,主從的數(shù)據(jù)庫(kù)狀態(tài)又不一致。
數(shù)據(jù)同步階段完成后,主從節(jié)點(diǎn)進(jìn)入命令傳播階段;在這個(gè)階段主節(jié)點(diǎn)將自己執(zhí)行的寫(xiě)命令發(fā)送給從節(jié)點(diǎn),從節(jié)點(diǎn)接受命令并執(zhí)行,從而保證主從節(jié)點(diǎn)數(shù)據(jù)的一致性。
另外命令傳播我們需要關(guān)注兩個(gè)點(diǎn):延遲與不一致 和 心跳機(jī)制。
需要注意的是,命令傳播是異步的過(guò)程,即主節(jié)點(diǎn)發(fā)送寫(xiě)命令后并不會(huì)等待從節(jié)點(diǎn)的回復(fù);因此實(shí)際上主從節(jié)點(diǎn)之間很難保持實(shí)時(shí)的一致性,延遲在所難免。數(shù)據(jù)不一致的程度,與主從節(jié)點(diǎn)之間的網(wǎng)路狀況、主節(jié)點(diǎn)寫(xiě)命令執(zhí)行頻率、以及主節(jié)點(diǎn)中repl-disable-tcp-nodelay 配置等有關(guān)。
repl-disable-tcp-nodelay 配置如下:
概括來(lái)說(shuō)就是:前者關(guān)注性能,后者關(guān)注一致性。
一般來(lái)說(shuō),只有當(dāng)應(yīng)用對(duì)Redis數(shù)據(jù)不一致的容忍度較高,且主從節(jié)點(diǎn)之間網(wǎng)絡(luò)狀態(tài)不好時(shí),才會(huì)設(shè)置為yes;多數(shù)情況使用默認(rèn)值no
命令傳播階段,從服務(wù)器會(huì)利用心跳檢測(cè)機(jī)制定時(shí)的向主服務(wù)發(fā)送消息。
3、Redis主從復(fù)制結(jié)構(gòu)Redis的主從結(jié)構(gòu)可以采用一主一從、一主多從或者樹(shù)狀主從結(jié)構(gòu),Redis主從復(fù)制可以根據(jù)是否是全量分為全量同步和增量同步。
一主一從:

一主多從:

樹(shù)狀主從結(jié)構(gòu):

在Redis2.8以前,從接待你向主節(jié)點(diǎn)發(fā)送sync命令請(qǐng)求同步數(shù)據(jù),此時(shí)的同步方式是全量復(fù)制;在Redis2.8及以后,從節(jié)點(diǎn)可以發(fā)送psync命令請(qǐng)求同步數(shù)據(jù),此時(shí)根據(jù)主從節(jié)點(diǎn)當(dāng)前狀態(tài)的不同,同步方式可能是全量復(fù)制或部分復(fù)制。
全量復(fù)制:用于初次復(fù)制或其他無(wú)法進(jìn)行部分復(fù)制的情況,將主節(jié)點(diǎn)中的所有數(shù)據(jù)都發(fā)送給從節(jié)點(diǎn),是一個(gè)非常重型的操作。
部分復(fù)制:用于網(wǎng)絡(luò)中斷等情況后的復(fù)制,只將中斷期間主節(jié)點(diǎn)執(zhí)行的寫(xiě)命令發(fā)送給從節(jié)點(diǎn),與全量復(fù)制相比更加高效,需要注意的是,如果網(wǎng)絡(luò)中斷時(shí)間過(guò)長(zhǎng),導(dǎo)致主節(jié)點(diǎn)沒(méi)有能夠完整地保存中斷期間執(zhí)行地寫(xiě)命令,則無(wú)法進(jìn)行部分復(fù)制,仍使用全量復(fù)制。
1. 全量同步
Redis全量復(fù)制一般發(fā)生在Slave初始化階段,這時(shí)Slave需要將Master上的所有數(shù)據(jù)都復(fù)制一份。

具體步驟如下:?
完成上面幾個(gè)步驟后就完成了從服務(wù)器數(shù)據(jù)初始化的所有操作,從服務(wù)器此時(shí)可以接收來(lái)自用戶(hù)的讀請(qǐng)求。
2. 增量同步
由于全量復(fù)制在主節(jié)點(diǎn)數(shù)據(jù)量較大時(shí)效率太低,因此Redis2.8開(kāi)始提供部分復(fù)制,用于處理網(wǎng)絡(luò)中斷時(shí)的數(shù)據(jù)同步。
部分復(fù)制的實(shí)現(xiàn),依賴(lài)于三個(gè)重量的概念:復(fù)制偏移量、復(fù)制積壓緩沖區(qū)、服務(wù)器運(yùn)行id(runid)
1)復(fù)制偏移量
執(zhí)行復(fù)制的雙方,主從節(jié)點(diǎn),分別會(huì)維護(hù)一個(gè)復(fù)制偏移量offset:
offset用于判斷主從節(jié)點(diǎn)的數(shù)據(jù)庫(kù)狀態(tài)是否一致:如果二者offset相同,則一致;如果offset不同,則不一致,此時(shí)可以根據(jù)兩個(gè)offset找出從節(jié)點(diǎn)缺少的那部分?jǐn)?shù)據(jù)。例如,如果主節(jié)點(diǎn)offset是1000,而從節(jié)點(diǎn)的offset是500,那么部分復(fù)制舊需要將offset為501-1000的數(shù)據(jù)傳遞給從節(jié)點(diǎn)。而offset為501-1000的數(shù)據(jù)存儲(chǔ)的位置,就是下面要介紹的復(fù)制積壓緩沖區(qū)。
2)復(fù)制積壓緩沖區(qū)(replication-backlog-buffer)
主節(jié)點(diǎn)內(nèi)部維護(hù)了一個(gè)固定長(zhǎng)度的、先進(jìn)先出(FIFO)隊(duì)列作為復(fù)制積壓緩沖區(qū),默認(rèn)大小為1MB,在主節(jié)點(diǎn)進(jìn)行命令傳播時(shí),不僅會(huì)將寫(xiě)命令同步到從節(jié)點(diǎn),還會(huì)將寫(xiě)命令寫(xiě)入復(fù)制積壓緩沖區(qū)。
由于復(fù)制積壓緩沖區(qū)定長(zhǎng)且是先進(jìn)先出,所以他保存的是主節(jié)點(diǎn)最近執(zhí)行的寫(xiě)命令;時(shí)間較早的寫(xiě)命令會(huì)被擠出緩沖區(qū)。因此,當(dāng)主從節(jié)點(diǎn)offset的差距過(guò)大超過(guò)緩沖區(qū)長(zhǎng)度時(shí),將無(wú)法執(zhí)行部分復(fù)制,只能執(zhí)行全量復(fù)制。
為了提高網(wǎng)絡(luò)中斷時(shí)部分復(fù)制執(zhí)行的概率,可以根據(jù)需要增大復(fù)制積壓緩沖區(qū)的大?。ㄍㄟ^(guò)配置repl-backlog-size);例如如果網(wǎng)絡(luò)中斷的平均時(shí)間是60s,而主節(jié)點(diǎn)平均每秒產(chǎn)生的寫(xiě)命令(某些特定協(xié)議格式)所占據(jù)的字節(jié)數(shù)為100KB,則復(fù)制積壓緩沖區(qū)的平均需求為6MB,保險(xiǎn)起見(jiàn),可以設(shè)置為12MB,來(lái)保證絕大多數(shù)斷線(xiàn)情況都可以使用部分復(fù)制。
從節(jié)點(diǎn)將offset發(fā)送給主節(jié)點(diǎn)后,主節(jié)點(diǎn)根據(jù)offset和緩沖區(qū)大小決定能否執(zhí)行部分復(fù)制:
3)服務(wù)器運(yùn)行ID(runid)
每個(gè)Redis節(jié)點(diǎn),都有其運(yùn)行ID,運(yùn)行ID由節(jié)點(diǎn)在啟動(dòng)時(shí)自動(dòng)生成,主節(jié)點(diǎn)會(huì)將自己的運(yùn)行ID發(fā)送給從節(jié)點(diǎn),從節(jié)點(diǎn)會(huì)將主節(jié)點(diǎn)的運(yùn)行ID存起來(lái)。從節(jié)點(diǎn)Redis斷開(kāi)重連的時(shí)候,就是根據(jù)運(yùn)行ID來(lái)判斷同步的進(jìn)度:
如果從節(jié)點(diǎn)保存的runid與主節(jié)點(diǎn)現(xiàn)在的runid相同,說(shuō)明主從節(jié)點(diǎn)之前同步過(guò),主節(jié)點(diǎn)會(huì)繼續(xù)嘗試使用部分復(fù)制(到底能不能部分復(fù)制還要看offset和復(fù)制積壓緩沖區(qū)的情況);
如果從節(jié)點(diǎn)保存的runid與主節(jié)點(diǎn)現(xiàn)在的runid不同,說(shuō)明從節(jié)點(diǎn)在斷線(xiàn)前同步的Redis節(jié)點(diǎn)并不是當(dāng)前的主節(jié)點(diǎn),只能進(jìn)行全量復(fù)制。
4、psync命令的執(zhí)行在了解了復(fù)制偏移量、復(fù)制積壓緩沖區(qū)、節(jié)點(diǎn)運(yùn)行id之后,這里psync命令的參數(shù)和返回值,從而說(shuō)明psync命令執(zhí)行過(guò)程中,主從節(jié)點(diǎn)是如何確定使用全量復(fù)制還是部分復(fù)制的。
psync命令流程圖如下:

psync命令的大體流程如下:
如果從節(jié)點(diǎn)之前沒(méi)有復(fù)制過(guò)任何主節(jié)點(diǎn),或者之前執(zhí)行過(guò)slaveof no one 命令,從節(jié)點(diǎn)就會(huì)向主節(jié)點(diǎn)發(fā)送psync 命令,請(qǐng)求主節(jié)點(diǎn)進(jìn)行數(shù)據(jù)的全量同步。
如果前面從節(jié)點(diǎn)已經(jīng)同步過(guò)部分?jǐn)?shù)據(jù),此時(shí)從節(jié)點(diǎn)就會(huì)發(fā)送psync runid offset 命令給主節(jié)點(diǎn),其中runid是上一次主節(jié)點(diǎn)的運(yùn)行ID,offset是當(dāng)前從節(jié)點(diǎn)的復(fù)制偏移量
主節(jié)點(diǎn)收到psync命令后,會(huì)出現(xiàn)以下三種可能:
主節(jié)點(diǎn)返回 fullresync runid offset 回復(fù),表示主節(jié)點(diǎn)要求與從節(jié)點(diǎn)進(jìn)行數(shù)據(jù)的完整全量復(fù)制,其中runid表示主節(jié)點(diǎn)的運(yùn)行ID,offset表示當(dāng)前主節(jié)點(diǎn)的復(fù)制偏移量。
如果主服務(wù)器返回+continue,表示從節(jié)點(diǎn)與從節(jié)點(diǎn)會(huì)進(jìn)行部分?jǐn)?shù)據(jù)的同步操作,將從節(jié)點(diǎn)缺失的數(shù)據(jù)復(fù)制過(guò)來(lái)即可。
如果主服務(wù)器返回-err,表示主服務(wù)器的Redis版本低于2.8,無(wú)法是別psync命令,此時(shí)從服務(wù)器會(huì)向主服務(wù)器發(fā)送sync,進(jìn)行完整的數(shù)據(jù)全量復(fù)制。
Redis通過(guò)psnyc命令進(jìn)行全量復(fù)制的過(guò)程如下:
通過(guò)全量復(fù)制的過(guò)程可以看出,全量復(fù)制是非常重型的操作:
心跳檢測(cè)機(jī)制的作用有三個(gè):
檢查主從服務(wù)器的網(wǎng)絡(luò)連接狀態(tài),主節(jié)點(diǎn)信息中可以看到所屬的從節(jié)點(diǎn)的連接信息:

state 表示從節(jié)點(diǎn)狀態(tài)、offset表示復(fù)制偏移量、lag表示延遲值(幾秒之前有過(guò)心跳檢測(cè)機(jī)制)
輔助實(shí)現(xiàn)min-slaves選項(xiàng),Redis.conf 配置文件中有下方兩個(gè)參數(shù):
# 未達(dá)到下面兩個(gè)條件時(shí),寫(xiě)操作就不會(huì)被執(zhí)行
# 最少包含的從服務(wù)器
# min-slaves-to-write 3
# 延遲值
# min-slaves-max-lag 10如果將兩個(gè)參數(shù)注釋取消,那么如果從服務(wù)器的數(shù)量少于3個(gè),或者三個(gè)從服務(wù)器的延遲(lag)大于等于10秒時(shí),主服務(wù)器都會(huì)拒絕執(zhí)行寫(xiě)命令。
檢測(cè)命令丟失時(shí),在從服務(wù)器的連接信息中可以看到復(fù)制偏移量,如果此時(shí)主服務(wù)器的復(fù)制偏移量與從服務(wù)器的復(fù)制偏移量不一致時(shí),主服務(wù)器會(huì)補(bǔ)發(fā)缺失的數(shù)據(jù)。
5、無(wú)磁盤(pán)復(fù)制通常來(lái)講,一個(gè)完全重新同步需要在磁盤(pán)上創(chuàng)建一個(gè)RDB文件,然后加載這個(gè)文件以便為從服務(wù)器發(fā)送數(shù)據(jù)。如果使用比較低速的磁盤(pán),這種操作會(huì)給主服務(wù)器帶來(lái)較大的壓力。Redis從2.8.18版本開(kāi)始嘗試支持無(wú)磁盤(pán)的復(fù)制。使用這種設(shè)置時(shí),子進(jìn)程直接將RDB通過(guò)網(wǎng)絡(luò)發(fā)送給從服務(wù)器,不使用磁盤(pán)作為中間存儲(chǔ),避免了IO性能差問(wèn)題。
可以使用repl-diskless-sync 配置參數(shù)來(lái)啟動(dòng)無(wú)磁盤(pán)復(fù)制。使用repl-diskless-sync-delay參數(shù)來(lái)配置傳輸開(kāi)始的延遲時(shí)間,以便等待更多的從服務(wù)器連接上來(lái)。
開(kāi)啟無(wú)磁盤(pán)復(fù)制:
repl-diskless-sync yes6、主從復(fù)制架構(gòu)中出現(xiàn)宕機(jī)情況如果在主從復(fù)制架構(gòu)中出現(xiàn)宕機(jī)的情況,需要分情況看:
1. 從Redis宕機(jī)
這個(gè)相對(duì)而言比較簡(jiǎn)單,在Redis中從庫(kù)重新啟動(dòng)后會(huì)自動(dòng)加入到主從架構(gòu)中,自動(dòng)完成同步數(shù)據(jù),這是因?yàn)樵赗edis2.8版本后就新增了增量復(fù)制功能,主從斷線(xiàn)后恢復(fù)是通過(guò)增量復(fù)制實(shí)現(xiàn)的。所以這種情況無(wú)需擔(dān)心。
2. 主Redis宕機(jī)
這個(gè)情況相對(duì)而言就會(huì)復(fù)雜一些,需要以下2步才能完成:
第一步,在從數(shù)據(jù)庫(kù)中執(zhí)行SLAVEOF NO ONE命令,斷開(kāi)主從關(guān)系并且提升為主庫(kù)繼續(xù)服務(wù);
第二步,將主庫(kù)修復(fù)重新啟動(dòng)后,執(zhí)行SLAVEOF命令,將其設(shè)置為其他庫(kù)的從庫(kù),這時(shí)數(shù)據(jù)就能更新回來(lái);
這兩個(gè)步驟要通過(guò)手動(dòng)完成恢復(fù),過(guò)程其實(shí)是比較麻煩的并且容易出錯(cuò),有沒(méi)有好辦法解決呢?有的,Redis提供的哨兵(sentinel)功能就可以實(shí)現(xiàn)主Redis宕機(jī)的自動(dòng)切換。
7、Redis主從復(fù)制總結(jié)1. Redis主從復(fù)制策略
主從剛剛連接的時(shí)候,進(jìn)行全量同步;全同步結(jié)束后,進(jìn)行增量同步。當(dāng)然,如果有需要,slave 在任何時(shí)候都可以發(fā)起全量同步。redis的策略是,無(wú)論如何,首先會(huì)嘗試進(jìn)行增量同步,如不成功,要求從機(jī)進(jìn)行全量同步。
2. 主從復(fù)制的特點(diǎn)
主從復(fù)制的特點(diǎn):
主從模式并不完美,它也存在許多不足之處,下面做了簡(jiǎn)單地總結(jié):
雖然主從模式存在上述不足,但他仍然是實(shí)現(xiàn)分布式集群的基礎(chǔ)。Sentinel哨兵模式同樣是依賴(lài)于主從模式實(shí)現(xiàn)。
五、Redis主從復(fù)制實(shí)戰(zhàn) 1、主從復(fù)制配置文件redis.config配置文件相關(guān)配置:
配置主從:
# 相當(dāng)于我們上面客戶(hù)端執(zhí)行的REPLICAOF命令,配置到配置文件每次重啟就不用手動(dòng)再執(zhí)行命令了。
replicaof# master的密碼
masterauth 主從傳輸數(shù)據(jù)這期間,從節(jié)點(diǎn)是否允許對(duì)外提供服務(wù):
# 默認(rèn)是ye,允許
slave-serve-stale-data yes看下面的log(這是我們建立主從關(guān)系的時(shí)候產(chǎn)生的log)。

意思是說(shuō)在和Master建立連接,獲取完Master數(shù)據(jù)之間,也就是從庫(kù)進(jìn)行flush操作之前,是否允許對(duì)外繼續(xù)提供請(qǐng)求(就是Slave完成配置之前的那些flush之前的老數(shù)據(jù)是否還允許被訪(fǎng)問(wèn))。
是否開(kāi)啟Slave從節(jié)點(diǎn)也支持寫(xiě)命令:
# 默認(rèn)只讀,yes代表只讀
slave-read-only yes先落磁盤(pán)再傳輸還是直接網(wǎng)絡(luò)傳輸:
# 默認(rèn)是先落盤(pán),再進(jìn)行網(wǎng)絡(luò)傳輸
repl-diskless-sync no因?yàn)槟J(rèn)是Master先生成rdb文件到磁盤(pán),這時(shí)候產(chǎn)生一次磁盤(pán)IO,然后將磁盤(pán)上rdb文件以網(wǎng)絡(luò)的方式傳遞給Slave,這時(shí)候又產(chǎn)生一次IO,如果rdb幾個(gè)GB的話(huà)那還不如直接走網(wǎng)絡(luò)傳輸,就不走磁盤(pán)io了。 改為yes的話(huà)直接Master通過(guò)網(wǎng)絡(luò)的方式發(fā)送rdb給Slave。默認(rèn)是no,從日志也可以看出先落盤(pán)了

原理圖:

全量還是增量:
repl-backlog-size 1mb可以發(fā)現(xiàn)比主從復(fù)制原理圖中多了個(gè)隊(duì)列和偏移量。

這個(gè)隊(duì)列代表repl-backlog-size參數(shù)設(shè)置的值大小,是決定全量復(fù)制還是增量復(fù)制的關(guān)鍵參數(shù)。
RDB每次同步到slave的時(shí)候,slave都會(huì)記錄一個(gè)offset偏移量,然后每次同步數(shù)據(jù)的時(shí)候都會(huì)看隊(duì)列里的數(shù)據(jù)偏移量是否符合slave上次同步的數(shù)據(jù)大小,若符合則增量,否則全量。
舉例:
如果設(shè)置的1MB,你掛了3s鐘,假設(shè)1s鐘就寫(xiě)了1MB,那么3s鐘的隊(duì)列肯定放不下,這時(shí)候就觸發(fā)全量,所以這個(gè)需要看業(yè)務(wù)調(diào)整大小。
再比如master是100MB數(shù)據(jù),slave也是1MB數(shù)據(jù),然后slave掛了?;謴?fù)的時(shí)候發(fā)現(xiàn)master已經(jīng)有110MB了,但是隊(duì)列大小只有1MB,把隊(duì)列里的數(shù)據(jù)拿來(lái)顯然不行,所以會(huì)觸發(fā)全量,這只是舉例,其實(shí)不會(huì)那么傻的判斷總大小,而是通過(guò)偏移量來(lái)的。?
2、僅開(kāi)啟RDB僅僅開(kāi)啟RDB持久化,關(guān)閉AOF。
首先啟動(dòng)三個(gè)redis,端口分別是6379、6380、6381。我們這里設(shè)定6379為Master,其余兩個(gè)為Slaver。
1. 如何設(shè)置Slaver

可以看到Redis5.x后開(kāi)始用REPLICAOF命令代替5.x版本之前的SLAVEOF命令。
2. 設(shè)置Slaver
# 設(shè)置6380是6379的從節(jié)點(diǎn)
127.0.0.1:6380>REPLICAOF localhost 6379
OK設(shè)置完成后去看6379和6380的log
6379的log:

6380的log:

3. ????在Master執(zhí)行寫(xiě)命令
127.0.0.1:6379>set k1 123
OK
127.0.0.1:6379>get k1
"123"4. 在Slave(6380)上查看是否同步過(guò)來(lái)了
127.0.0.1:6380>keys *
1) "k1"
127.0.0.1:6380>get k1
"123"5.?Slave是禁止執(zhí)行寫(xiě)命令的
127.0.0.1:6380>set k2 123
(error) READONLY You can't write against a read only replica.6.?設(shè)置6382也作為6379的Slave
設(shè)置從節(jié)點(diǎn)之前先在6382內(nèi)set一個(gè)值,為了確定設(shè)置完后會(huì)進(jìn)行flush操作。
127.0.0.1:6381>set k2 222
OK
127.0.0.1:6381>get k2
"222"然后設(shè)置Slave:
127.0.0.1:6381>REPLICAOF 127.0.0.1 6379
OK
127.0.0.1:6381>keys *
1) "k1"將Master的數(shù)據(jù)同步過(guò)來(lái)了。
如果設(shè)置Slave后進(jìn)行了flush操作(上面的log也體現(xiàn)出來(lái)了),我們之前的k2沒(méi)了。
若6381宕機(jī)了,這時(shí)候他再啟動(dòng)的時(shí)候是會(huì)同步Master的數(shù)據(jù)的,增量同步的。不需要手動(dòng)進(jìn)行同步。
但前提是需要作為Master的Slave,有如下三種方式:
8.?Master掛了怎么辦
從節(jié)點(diǎn)會(huì)一直報(bào)錯(cuò):

導(dǎo)致的問(wèn)題:Slave無(wú)法提供寫(xiě)請(qǐng)求,只能讀了。影響了業(yè)務(wù)使用。
解決方案:讓其中一個(gè)Slave升級(jí)為Master,然后其他Slave作為這個(gè)新升級(jí)為Master的從。?
# 升級(jí)為Master的方法:在客戶(hù)端執(zhí)行,比如我們升級(jí)6380為Master
127.0.0.1:6380>REPLICAOF no one
OK
# 這時(shí)候再看6380就不會(huì)再刷錯(cuò)了,但是6381還在刷,
# 因?yàn)?381是已經(jīng)掛掉的6379的Slave,我們需要讓6381作為6380的Slave,
# 我們?cè)俨僮鬟@步驟之前,對(duì)6380set一個(gè)key,然后看6381的數(shù)據(jù)會(huì)重新復(fù)制6380的數(shù)據(jù)
# 顯示業(yè)務(wù)中幾乎不會(huì)存在此情況,因?yàn)閺墓?jié)點(diǎn)升級(jí)就是升級(jí),所有主從的數(shù)據(jù)都一致,不會(huì)隨意改
# 這里只是演示效果而已。
127.0.0.1:6380>set kkk 3333
OK
# 6381作為6380的Slave
127.0.0.1:6381>REPLICAOF 127.0.0.1 6380
OK
127.0.0.1:6381>keys *
1) "kkk"
2) "k1"
127.0.0.1:6381>get kkk
"3333"3、RDB+AOF混合模式1. 僅開(kāi)啟AOF
和上面一樣。只是會(huì)按照aof文件進(jìn)行主從復(fù)制數(shù)據(jù)。
2. 混合模式(RDB+AOF)
流程和僅開(kāi)啟RDB一樣,只是主從復(fù)制的時(shí)候會(huì)優(yōu)先按照aof來(lái)同步數(shù)據(jù),因?yàn)閍of文件丟失數(shù)據(jù)最少,更可靠。redis會(huì)判斷aof文件是否存在,若開(kāi)啟了aof且文件存在,則以aof復(fù)制,若沒(méi)開(kāi)啟aof則走rdb方式。
4、Redis主從復(fù)制實(shí)戰(zhàn)
1.?使用命令實(shí)現(xiàn)
1)方法一
使用命令在服務(wù)端搭建主從模式,其語(yǔ)法格式如下:
redis-server --port--slaveof 執(zhí)行以下命令:
#開(kāi)啟開(kāi)啟一個(gè)port為6300的從機(jī),它依賴(lài)的主機(jī)port=6379
>redis-server --port 6300 --slaveof 127.0.0.1 6379
接下來(lái)開(kāi)啟客戶(hù)端,并執(zhí)行查詢(xún)命令,如下所示:?
>redis-cli -p 6300
127.0.0.1:6300>get name
"jack"
127.0.0.1:6300>get website
"www.biancheng.net"
#不能執(zhí)行寫(xiě)命令
127.0.0.1:6300>set myname BangDe
(error) READONLY You can't write against a read only slave.
127.0.0.1:6300>keys *
1) "myset:__rand_int__"
2) "ID"
3) "title"
4) "course2"從上述命令可以看出,port =6300 的主機(jī),完全備份了主機(jī)的數(shù)據(jù),它可以執(zhí)行查詢(xún)命令,但不能執(zhí)行寫(xiě)入命令
從機(jī)服務(wù)端提示如下:
[18160] 20 Jan 17:40:34.101 # Server initialized #服務(wù)初始化
[18160] 20 Jan 17:40:34.108 * Ready to accept connections #準(zhǔn)備連接
[18160] 20 Jan 17:40:34.108 * Connecting to MASTER 127.0.0.1:6379 #連接到主服務(wù)器
[18160] 20 Jan 17:40:34.109 * MASTER<->REPLICA sync started #啟動(dòng)副本同步
[18160] 20 Jan 17:40:34.110 * Non blocking connect for SYNC fired the event.#自動(dòng)觸發(fā)SYNC命令,請(qǐng)求同步數(shù)據(jù)
[18160] 20 Jan 17:40:34.110 * Master replied to PING, replication can continue...
[18160] 20 Jan 17:40:34.112 * Partial resynchronization not possible (no cached master)
[18160] 20 Jan 17:40:34.431 * Full resync from master: 6eb220706f73107990c2b886dbc2c12a8d0d9d05:0
[18160] 20 Jan 17:40:34.857 * MASTER<->REPLICA sync: receiving 6916 bytes from master #從主機(jī)接受了數(shù)據(jù),并將其存在于磁盤(pán)
[18160] 20 Jan 17:40:34.874 * MASTER<->REPLICA sync: Flushing old data #清空原有數(shù)據(jù)
[18160] 20 Jan 17:40:34.874 * MASTER<->REPLICA sync: Loading DB in memory #將磁盤(pán)中數(shù)據(jù)載入內(nèi)存
[18160] 20 Jan 17:40:34.879 * MASTER<->REPLICA sync: Finished with success #同步數(shù)據(jù)完成可以看出主從模式下,數(shù)據(jù)的同步是自動(dòng)完成的,這個(gè)數(shù)據(jù)同步的過(guò)程,又稱(chēng)為全量復(fù)制。
2)方法二
啟動(dòng)一個(gè)服務(wù)端,并指定端口號(hào)。
#指定端口號(hào)為63001,不要關(guān)閉
redis-server --port 63001打開(kāi)一個(gè)客戶(hù)端,連接服務(wù)器,如下所示:
# 連接port=63001的服務(wù)器
>redis-cli -p 63001
// 現(xiàn)在處于主機(jī)模式下,所以運(yùn)行讀寫(xiě)數(shù)據(jù)
127.0.0.1:63001>keys *
1) "name"
127.0.0.1:63001>get name
"aaaa"
127.0.0.1:63001>set name "bbbb"
OK
127.0.0.1:63001>get name
"bbbb"
127.0.0.1:63001># 將當(dāng)前服務(wù)器設(shè)置為從服務(wù)器,從屬于6379
127.0.0.1:63001>SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:63001>keys *
1) "master_6379" # 現(xiàn)在它的數(shù)據(jù)和主服務(wù)器的數(shù)據(jù)一樣了
#寫(xiě)入命令執(zhí)行失敗
127.0.0.1:63001>SET mywebsite www.biancheng.net
(error) READONLY You can't write against a read only replica.
#再次切換為主機(jī)模式,執(zhí)行下面命令
127.0.0.1:63001>SLAVEOF no one
OK
127.0.0.1:63001>SLAVEOF no one
OK
127.0.0.1:63001>keys *
1) "master_6379" # 數(shù)據(jù)還是和之前主服務(wù)器的一樣
127.0.0.1:63001>SET mywebsite www.biancheng.net # 但是現(xiàn)在可以寫(xiě)入命令了
OK
127.0.0.1:63001>keys *
1) "mywebsite"
2) "master_6379"
2. 修改配置文件實(shí)現(xiàn)
每個(gè) Redis 服務(wù)器都有一個(gè)與其對(duì)應(yīng)的配置文件,通過(guò)修改該配置文件也可以實(shí)現(xiàn)主從模式。
新建 redis_6302.conf 文件,并添加以下配置信息:
slaveof 127.0.0.1 6379 #指定主機(jī)的ip與port
port 6302 #指定從機(jī)的端口啟動(dòng) Redis 服務(wù)器,執(zhí)行以下命令:
$ redis-server redis_6302.conf客戶(hù)端連接服務(wù)器,并進(jìn)行簡(jiǎn)單測(cè)試。
執(zhí)行以下命令:
$ redis-cli -p 6302
127.0.0.1:6300>HSET user:username biangcheng
#寫(xiě)入失敗
(error) READONLY You can't write against a read only slave.通過(guò)命令搭建主從模式,簡(jiǎn)單又快捷,所以不建議使用修改配置文件的方法。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧