
一、主從復(fù)制說(shuō)明
1.1、面臨問(wèn)題
在實(shí)際的場(chǎng)景當(dāng)中單一節(jié)點(diǎn)的redis容易面臨風(fēng)險(xiǎn)。
比如:
- 機(jī)器故障:我們部署一臺(tái)Redis服務(wù)器,當(dāng)發(fā)生機(jī)器故障時(shí),需要遷移到另外一臺(tái)服務(wù)器并且要保證數(shù)據(jù)是同步的。而數(shù)據(jù)是最重要的,如果你不在乎,基本就不會(huì)使用Redis了。
要實(shí)現(xiàn)分布式數(shù)據(jù)庫(kù)的更大的存儲(chǔ)容量和承受高并發(fā)訪問(wèn)量,我們會(huì)將原來(lái)集中式數(shù)據(jù)庫(kù)的數(shù)據(jù)分別存儲(chǔ)到其他多個(gè)網(wǎng)絡(luò)節(jié)點(diǎn)上。
Redis為了解決這個(gè)單一節(jié)點(diǎn)的問(wèn)題,也會(huì)把數(shù)據(jù)復(fù)制多個(gè)副本部署到其他節(jié)點(diǎn)上進(jìn)行復(fù)制,實(shí)現(xiàn)Redis的高可用,實(shí)現(xiàn)對(duì)數(shù)據(jù)的冗余備份,從而保證數(shù)據(jù)和服務(wù)的高可用。
1.2、什么是主從復(fù)制
主從復(fù)制, 是指將一臺(tái)Redis服務(wù)器的數(shù)據(jù),復(fù)制到其他的Redis服務(wù)器,前者稱(chēng)為主節(jié)點(diǎn)(master),后者稱(chēng)為從節(jié)點(diǎn)(slave),數(shù)據(jù)的復(fù)制是單向的,只能由主節(jié)點(diǎn)到從節(jié)點(diǎn)。
默認(rèn)情況下,每臺(tái)Redis服務(wù)器都是主節(jié)點(diǎn),且一個(gè)主節(jié)點(diǎn)可以有多個(gè)從節(jié)點(diǎn)(或沒(méi)有從節(jié)點(diǎn)),但一個(gè)從節(jié)點(diǎn)只能有一個(gè)主節(jié)點(diǎn)。

二、主從復(fù)制的作用
主從復(fù)制的作用主要包括:
1. 數(shù)據(jù)冗余:
主從復(fù)制實(shí)現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式。
2. 故障恢復(fù):
當(dāng)主節(jié)點(diǎn)出現(xiàn)問(wèn)題時(shí),可以由從節(jié)點(diǎn)提供服務(wù),實(shí)現(xiàn)快速的故障恢復(fù);實(shí)際上是一種服務(wù)的冗余。
3. 負(fù)載均衡:
在主從復(fù)制的基礎(chǔ)上,配合讀寫(xiě)分離,可以由主節(jié)點(diǎn)提供寫(xiě)服務(wù),由從節(jié)點(diǎn)提供讀服務(wù)(即寫(xiě)Redis數(shù)據(jù)時(shí)應(yīng)用連接主節(jié)點(diǎn),讀Redis數(shù)據(jù)分擔(dān)服務(wù)器負(fù)載;尤其是在寫(xiě)少讀多的場(chǎng)景下,通過(guò)多個(gè)從節(jié)點(diǎn)分擔(dān)讀負(fù)載,可以大大提高Redis服務(wù)器的并發(fā)量)。
4. 讀寫(xiě)分離:
可以用于實(shí)現(xiàn)讀寫(xiě)分離,主庫(kù)寫(xiě),從庫(kù)讀,讀寫(xiě)分離不僅可以提高服務(wù)器的負(fù)載能力,同時(shí)可根據(jù)需求的變化,改變從庫(kù)的數(shù)量;
5. 高可用基石:
除了上述作用外,主從復(fù)制還是哨兵和集群能夠?qū)嵤┑幕A(chǔ),因此說(shuō)主從復(fù)制時(shí)Redis高可用的基礎(chǔ)。
三、主從復(fù)制啟用
從節(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í)例成為從節(jié)點(diǎn)。
- redis保護(hù)模式:
protected-mode no,如果master實(shí)例啟用了密碼保護(hù),則需要再使用masterauth <master-password>命令 - 通過(guò) info replication命令可以看到復(fù)制的一些參數(shù)信息。
3.1 、主從復(fù)制原理
主從復(fù)制的原理以及過(guò)程必須要掌握,這樣我們才知道為什么會(huì)出現(xiàn)這些問(wèn)題
主從復(fù)制過(guò)程大體可以分為3個(gè)階段:連接建立階段(即準(zhǔn)備階段)、數(shù)據(jù)同步階段、命令傳播階段。
在從節(jié)點(diǎn)執(zhí)行 slaveof 命令后,復(fù)制過(guò)程便開(kāi)始運(yùn)作,下面圖示大概可以看到, 從圖中可以看出復(fù)制過(guò)程大致分為6個(gè)過(guò)程:

主從配置之后的日志記錄也可以看出這個(gè)流程
1、保存主節(jié)點(diǎn)(master)信息。執(zhí)行slaveof后Redis會(huì)打印如下日志:

2、從節(jié)點(diǎn)(slave)內(nèi)部通過(guò)每秒運(yùn)行的定時(shí)任務(wù)維護(hù)相關(guān)邏輯,當(dāng)定時(shí)任務(wù)發(fā)現(xiàn)存在新的主節(jié)點(diǎn)后,會(huì)嘗試與該節(jié)點(diǎn)建立網(wǎng)絡(luò)連接

從節(jié)點(diǎn)與主節(jié)點(diǎn)建立網(wǎng)絡(luò)連接
從節(jié)點(diǎn)會(huì)建立一個(gè)socket套接字,從節(jié)點(diǎn)建立了一個(gè)端口為51234的套接字(臨時(shí)端口,不固定,Redis),專(zhuān)門(mén)用于接受主節(jié)點(diǎn)發(fā)送的復(fù)制命令。從節(jié)點(diǎn)連接成功后打印如下日志:

如果從節(jié)點(diǎn)無(wú)法建立連接,定時(shí)任務(wù)會(huì)無(wú)限重試直到連接成功或者執(zhí)行slaveof no one取消復(fù)制
關(guān)于連接失敗,可以在從節(jié)點(diǎn)執(zhí)行
info replication 查看 master_link_down_since_seconds指標(biāo),它會(huì)記錄與主節(jié)點(diǎn)連接失敗的系統(tǒng)時(shí)間.從節(jié)點(diǎn)連接主節(jié)點(diǎn)失敗時(shí)也會(huì)每秒打印如下日志,方便發(fā)現(xiàn)問(wèn)題:Error condition on socket for SYNC:{socket_error_reason}
- 發(fā)送ping命令
連接建立成功后從節(jié)點(diǎn)發(fā)送ping請(qǐng)求進(jìn)行首次通信,ping請(qǐng)求主要目的如下:
- 檢測(cè)主從之間網(wǎng)絡(luò)套接字是否可用.
- 檢測(cè)主節(jié)點(diǎn)當(dāng)前是否可接受處理命令.
-
如果發(fā)送ping命令后,從節(jié)點(diǎn)沒(méi)有收到主節(jié)點(diǎn)的pong恢復(fù)或者超時(shí),比如網(wǎng)絡(luò)超時(shí)或者主節(jié)點(diǎn)正在阻塞無(wú)法響應(yīng)命令,從節(jié)點(diǎn)會(huì)斷開(kāi)復(fù)制連接,下次定時(shí)任務(wù)會(huì)發(fā)起重連.
輪訓(xùn)重試.png
發(fā)起重連.png
從節(jié)點(diǎn)發(fā)送的ping命令成功返回,Redis打印如下日志,并繼續(xù)后續(xù)復(fù)制流程:
ping成功日志.png
- 權(quán)限驗(yàn)證
如果主節(jié)點(diǎn)設(shè)置了requirepass參數(shù),則需要密碼驗(yàn)證,從節(jié)點(diǎn)必須配置masterauth參數(shù)保證與主節(jié)點(diǎn)相同的密碼才能通過(guò)驗(yàn)證;如果驗(yàn)證失敗復(fù)制將終 止,從節(jié)點(diǎn)重新發(fā)起復(fù)制流程。 - 同步數(shù)據(jù)集
主從復(fù)制連接正常通信后,對(duì)于首次建立復(fù)制的場(chǎng)景,主節(jié)點(diǎn)會(huì)把持有的數(shù)據(jù)全部發(fā)送給從節(jié)點(diǎn),這部分操作是耗時(shí)最長(zhǎng)的步驟。 - 命令持續(xù)復(fù)制
當(dāng)主節(jié)點(diǎn)把當(dāng)前的數(shù)據(jù)同步給從節(jié)點(diǎn)后,便完成了復(fù)制的建立流程。接下來(lái)主節(jié)點(diǎn)會(huì)持續(xù)地把寫(xiě)命令發(fā)送給從節(jié)點(diǎn),保證主從數(shù)據(jù)一致性。
四、全量復(fù)制和部分復(fù)制
4.1 相關(guān)概念
用于初次復(fù)制或其它無(wú)法進(jìn)行部分復(fù)制的情況,將主節(jié)點(diǎn)中的所有數(shù)據(jù)都發(fā)送給從節(jié)點(diǎn),是一個(gè)非常重型的操作,當(dāng)數(shù)據(jù)量較大時(shí),會(huì)對(duì)主從節(jié)點(diǎn)和網(wǎng)絡(luò)造成很大的開(kāi)銷(xiāo)。
4.2 部分復(fù)制
用于處理在主從復(fù)制中因網(wǎng)絡(luò)閃斷等原因造成的數(shù)據(jù)丟失場(chǎng)景,當(dāng)從節(jié)點(diǎn)再次連上主節(jié)點(diǎn)后,如果(條件允許),主節(jié)點(diǎn)會(huì)補(bǔ)發(fā)丟失數(shù)據(jù)給從節(jié)點(diǎn)。 因?yàn)檠a(bǔ)發(fā)的數(shù)據(jù)遠(yuǎn)遠(yuǎn)小于全量數(shù)據(jù),可以有效避免全量復(fù)制的過(guò)高開(kāi)銷(xiāo),需要注意的是,如果網(wǎng)絡(luò)中斷時(shí)間過(guò)長(zhǎng),造成主節(jié)點(diǎn)沒(méi)有能夠完整地保存中斷期間執(zhí)行 的寫(xiě)命令,則無(wú)法進(jìn)行部分復(fù)制,仍使用全量復(fù)制
4.3 復(fù)制偏移量
參與復(fù)制的主從節(jié)點(diǎn)都會(huì)維護(hù)自身復(fù)制偏移量。主節(jié)點(diǎn)(master)在處理完寫(xiě)入命令后,會(huì)把命令的字節(jié)長(zhǎng)度做累加記錄,統(tǒng)計(jì)信息在 info relication 中的master_repl_offset 指標(biāo)中:
127.0.0.1:6379> info replication

從節(jié)點(diǎn)(slave)每秒鐘 上報(bào)自身的復(fù)制偏移量給主節(jié)點(diǎn),因此主節(jié)點(diǎn)也會(huì)保存從節(jié)點(diǎn)的復(fù)制偏移量,統(tǒng)計(jì)指標(biāo)如下:

從節(jié)點(diǎn)在接收到主節(jié)點(diǎn)發(fā)送的命令后,也會(huì)累加記錄自身的偏移量。統(tǒng)計(jì)信息在
info replication 中的 slave_repl_offset 中
復(fù)制積壓緩沖區(qū)
復(fù)制積壓緩沖區(qū)是保存在主節(jié)點(diǎn)上的一個(gè)固定長(zhǎng)度的隊(duì)列,默認(rèn)大小為1MB,當(dāng)主節(jié)點(diǎn)有連接的從節(jié)點(diǎn)(slave)時(shí)被創(chuàng)建,這時(shí)主節(jié)點(diǎn)(master)響應(yīng)寫(xiě)命令時(shí),不但會(huì)把命令發(fā)送給從節(jié)點(diǎn),還會(huì)寫(xiě)入復(fù)制積壓緩沖區(qū)。

在命令傳播階段,主節(jié)點(diǎn)除了將寫(xiě)命令發(fā)送給從節(jié)點(diǎn),還會(huì)發(fā)送一份給復(fù)制積壓緩沖區(qū),作為寫(xiě)命令的備份;除了存儲(chǔ)寫(xiě)命令,復(fù)制積壓緩沖區(qū)中還存儲(chǔ)了其中 的每個(gè)字節(jié)對(duì)應(yīng)的復(fù)制偏移量(offset) 。由于復(fù)制積壓緩沖區(qū)定長(zhǎng)且先進(jìn)先出,所以它保存的是主節(jié)點(diǎn)最近執(zhí)行的寫(xiě)命令;時(shí)間較早的寫(xiě)命令會(huì)被擠出緩沖區(qū)。
Redis全量復(fù)制過(guò)程如下:

如圖所示:
1.Redis內(nèi)部會(huì)發(fā)出一個(gè)同步命令,剛開(kāi)始是Psync命令,Psync ? -1表示要求master主機(jī)同步數(shù)據(jù)
- 主機(jī)會(huì)向從機(jī)發(fā)送runid和offset,因?yàn)閟lave并沒(méi)有對(duì)應(yīng)的offset,所以是全量復(fù)制。
3.從機(jī) slave 會(huì)保存 主機(jī)master 的基本信息 save masterInfo - 主節(jié)點(diǎn)收到全量復(fù)制的命令后,執(zhí)行bgsave(異步執(zhí)行),在后臺(tái)生成RDB文件(快照),并使用一個(gè)緩沖區(qū)(稱(chēng)為復(fù)制緩沖區(qū))記錄從現(xiàn)在開(kāi)始執(zhí)行 的所有寫(xiě)命令,(新版可以設(shè)置不用生成RDB)
- 主機(jī)send RDB 發(fā)送 RDB 文件給從機(jī)
- 發(fā)送緩沖區(qū)數(shù)據(jù)
- 刷新舊的數(shù)據(jù),從節(jié)點(diǎn)在載入主節(jié)點(diǎn)的數(shù)據(jù)之前要先將老數(shù)據(jù)清除
- 加載 RDB 文件將數(shù)據(jù)庫(kù)狀態(tài)更新至主節(jié)點(diǎn)執(zhí)行bgsave時(shí)的數(shù)據(jù)庫(kù)狀態(tài)和緩沖區(qū)數(shù)據(jù)的加載。(從節(jié)點(diǎn)在載入主節(jié)點(diǎn)的數(shù)據(jù)之前會(huì)把從節(jié)點(diǎn)的舊數(shù)據(jù)清除)
全量復(fù)制開(kāi)銷(xiāo),主要有以下幾項(xiàng)
- bgsave時(shí)間
- RDB文件網(wǎng)絡(luò)傳輸時(shí)間
- 從節(jié)點(diǎn)清空數(shù)據(jù)的時(shí)間
- 從節(jié)點(diǎn)加載RDB的時(shí)間
部分復(fù)制
部分復(fù)制是 Redis 2.8 以后出現(xiàn)的,之所以要加入部分復(fù)制,是因?yàn)槿繌?fù)制會(huì)產(chǎn)生很多問(wèn)題,比如像上面的時(shí)間開(kāi)銷(xiāo)大、無(wú)法隔離等問(wèn)題, Redis 希望能夠在 master 出現(xiàn)抖動(dòng)(相當(dāng)于斷開(kāi)連接)的時(shí)候,可以有一些機(jī)制將復(fù)制的損失降低到最低。

- 如果網(wǎng)絡(luò)抖動(dòng)(連接斷開(kāi)connection lost)。
- 主機(jī)master 還是會(huì)寫(xiě) repl_back_buffer(復(fù)制緩沖區(qū))。
- 從機(jī)slave 會(huì)繼續(xù)嘗試連接主機(jī)。
- 從機(jī)slave 會(huì)把自己當(dāng)前 runid 和偏移量傳輸給主機(jī) master,并且執(zhí)行 pysnc 命令同步。
- 如果 master 發(fā)現(xiàn)你的偏移量是在緩沖區(qū)的范圍內(nèi),就會(huì)返回 continue 命令。
- 同步了 offset 的部分?jǐn)?shù)據(jù),所以部分復(fù)制的基礎(chǔ)就是偏移量 offset。
注意:
正常情況下redis是如何決定是全量復(fù)制還是部分復(fù)制
從節(jié)點(diǎn)將offset發(fā)送給主節(jié)點(diǎn)后,主節(jié)點(diǎn)根據(jù)offset和緩沖區(qū)大小決定能否執(zhí)行部分復(fù)制:
- 如果offset偏移量之后的數(shù)據(jù),仍然都在復(fù)制積壓緩沖區(qū)里,則執(zhí)行部分復(fù)制。
- 如果offset偏移量之后的數(shù)據(jù)已不在復(fù)制積壓緩沖區(qū)中(數(shù)據(jù)已被擠出),則執(zhí)行全量復(fù)制。
緩沖區(qū)大小調(diào)節(jié):
由于緩沖區(qū)長(zhǎng)度固定且有限,因此可以備份的寫(xiě)命令也有限,當(dāng)主從節(jié)點(diǎn)offset的差距過(guò)大超過(guò)緩沖區(qū)長(zhǎng)度時(shí),將無(wú)法執(zhí)行部分復(fù)制,只能執(zhí)行全量復(fù)制。反過(guò) 來(lái)說(shuō),為了提高網(wǎng)絡(luò)中斷時(shí)部分復(fù)制執(zhí)行的概率,可以根據(jù)需要增大復(fù)制積壓緩沖區(qū)的大小(通過(guò)配置repl-backlog-size)來(lái)設(shè)置; 例如 如果網(wǎng)絡(luò)中斷的平均時(shí)間是60s,而主節(jié)點(diǎn)平均每秒產(chǎn)生的寫(xiě)命令(特定協(xié)議格式)所占的字節(jié)數(shù)為100KB,則復(fù)制積壓緩沖區(qū)的平均需求為6MB,保險(xiǎn)起見(jiàn), 可以設(shè)置為12MB,來(lái)保證絕大多數(shù)斷線情況都可以使用部分復(fù)制
服務(wù)器運(yùn)行ID(runid)
每個(gè)Redis節(jié)點(diǎn)(無(wú)論主從),在啟動(dòng)時(shí)都會(huì)自動(dòng)生成一個(gè)隨機(jī)ID(每次啟動(dòng)都不一樣),由40個(gè)隨機(jī)的十六進(jìn)制字符組成;runid用來(lái)唯一識(shí)別一個(gè)Redis節(jié)點(diǎn)。 通過(guò) info server命令,可以查看節(jié)點(diǎn)的runid:

主從節(jié)點(diǎn)初次復(fù)制時(shí),主節(jié)點(diǎn)將自己的runid發(fā)送給從節(jié)點(diǎn),從節(jié)點(diǎn)將這個(gè)runid保存起來(lái),當(dāng)斷線重連時(shí),從節(jié)點(diǎn)會(huì)將這個(gè)runid發(fā)送給主節(jié)點(diǎn);主節(jié)點(diǎn)根據(jù)runid 判斷能否進(jìn)行部分復(fù)制:
- 如果從節(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)在斷線前同步的Redis節(jié)點(diǎn)并不是當(dāng)前的主節(jié)點(diǎn),只能進(jìn)行全量復(fù)制。
五、主從復(fù)制的常用相關(guān)配置
從數(shù)據(jù)庫(kù)配置
-
slaveof <masterip> <masterport>
slave實(shí)例需要配置該項(xiàng),指向master的(ip, port)。 -
masterauth <master-password>
如果master實(shí)例啟用了密碼保護(hù),則該配置項(xiàng)需填master的啟動(dòng)密碼;若master未啟用密碼,該配置項(xiàng)需要注釋掉 -
slave-serve-stale-data
指定 slave 與 master 連接中斷時(shí)的動(dòng)作。默認(rèn)為yes,表明slave會(huì)繼續(xù)應(yīng)答來(lái)自client的請(qǐng)求,但這些數(shù)據(jù)可能已經(jīng)過(guò)期(因?yàn)檫B接中斷導(dǎo)致無(wú)法從 master 同步)。 若配置為no,則slave除正常應(yīng)答"INFO"和"SLAVEOF"命令外,其余來(lái)自客戶(hù)端的請(qǐng)求命令均會(huì)得到" SYNC with master in progress "的應(yīng)答,直到該 slave 與 master 的連接重建成功或該 slave 被提升為 master 。 -
slave-read-only
指定slave是否只讀,默認(rèn)為yes。若配置為no,這表示slave是可寫(xiě)的,但寫(xiě)的內(nèi)容在主從同步完成后會(huì)被刪掉。 -
repl-disable-tcp-nodelay
指定向slave同步數(shù)據(jù)時(shí),是否禁用 socket 的 NO_DELAY 選項(xiàng)。若配置為yes,則禁用 NO_DELAY ,則TCP協(xié)議棧會(huì)合并小包統(tǒng)一發(fā)送,這樣可以減少主從節(jié)點(diǎn) 間的包數(shù)量并節(jié)省帶寬,但會(huì)增加數(shù)據(jù)同步到slave的時(shí)間。 若配置為no,表明啟用 NO_DELAY ,則TCP協(xié)議棧不會(huì)延遲小包的發(fā)送時(shí)機(jī),這樣數(shù)據(jù)同步的延時(shí)會(huì)減少,但需要更大的帶寬。通常情況下,應(yīng)該配置為no以降 低同步延時(shí),但在主從節(jié)點(diǎn)間網(wǎng)絡(luò)負(fù)載已經(jīng)很高的情況下,可以配置為yes。 -
slave-priority
指定 slave 的優(yōu)先級(jí)。在不只1個(gè) slave 存在的部署環(huán)境下,當(dāng) master 宕機(jī)時(shí), Redis Sentinel 會(huì)將priority值最小的slave提升為master。需要注意的是,若 該配置項(xiàng)為0,則對(duì)應(yīng)的slave永遠(yuǎn)不會(huì)被 Redis Sentinel 自動(dòng)提升為 master 。
六、主從復(fù)制進(jìn)階常見(jiàn)問(wèn)題解決
- 讀寫(xiě)分離
- 數(shù)據(jù)延遲
- 主從配置不一致
- 規(guī)避全量復(fù)制
- 規(guī)避復(fù)制風(fēng)暴
讀寫(xiě)分離
讀流量分?jǐn)偟綇墓?jié)點(diǎn)。這是個(gè)非常好的特性,如果一個(gè)業(yè)務(wù)只需要讀數(shù)據(jù),那么我們只需要連一臺(tái) slave 從機(jī)讀數(shù)據(jù)。

雖然讀寫(xiě)有優(yōu)勢(shì),能夠讓讀這部分分配給各個(gè) slave 從機(jī),如果不夠,直接加 slave 機(jī)器就好了。但是也會(huì)出現(xiàn)以下問(wèn)題。
復(fù)制數(shù)據(jù)延遲
可能會(huì)出現(xiàn)slave延遲導(dǎo)致讀寫(xiě)不一致等問(wèn)題,當(dāng)然你也可以監(jiān)控偏移量offset,如果offset超出范圍就切換到master上,邏輯切換,而具體延遲多少,可以通過(guò)info replication 的 offset 指標(biāo)進(jìn)行排查。
對(duì)于無(wú)法容忍大量延遲場(chǎng)景,可以編寫(xiě)外部監(jiān)控程序監(jiān)聽(tīng)主從節(jié)點(diǎn)的復(fù)制偏移量,當(dāng)延遲較大時(shí)觸發(fā)報(bào)警或者通知客戶(hù)端避免讀取延遲過(guò)高的從節(jié)點(diǎn),同時(shí)從節(jié)點(diǎn)的 slave-serve-stale-data 參數(shù)也與此有關(guān),它控制這種情況下從節(jié)點(diǎn)的表現(xiàn) 當(dāng)從庫(kù)同主機(jī)失去連接或者復(fù)制正在進(jìn)行,從機(jī)庫(kù)有兩種運(yùn)行方式:
- 如果
slave-serve-stale-data設(shè)置為yes(默認(rèn)設(shè)置),從庫(kù)會(huì)繼續(xù)響應(yīng)客戶(hù)端的請(qǐng)求 - 如果
slave-serve-stale-data設(shè)置為no,除去INFO和SLAVOF命令之外的任何請(qǐng)求都會(huì)返回一個(gè)錯(cuò)誤”SYNC with master in progress”。
例子: 模擬網(wǎng)絡(luò)延遲
docker run --privileged -itd -v /usr/docker/test/slave02:/usrsrc/redis --name redis-slave2 --net redis-network -p 6381:6379 --ip 192.168.1.3 redis
--privileged Docker容器將擁有訪問(wèn)主機(jī)所有設(shè)備的權(quán)限
通過(guò)linux下的控流工具,模擬網(wǎng)絡(luò)延遲,用代碼模擬下,因?yàn)閷?duì)于網(wǎng)絡(luò)的操作屬于特殊權(quán)限所以需要添加 --privileged 參數(shù)
通過(guò)linux下的控流工具,模擬網(wǎng)絡(luò)延遲,用代碼模擬下,因?yàn)閷?duì)于網(wǎng)絡(luò)的操作屬于特殊權(quán)限所以需要添加 --privileged 參數(shù)
centos: yum install iproute
alpine: apk add install iproute2
進(jìn)入到容器之后配置延遲5s
tc qdisc add dev eth0 root netem delay 5000ms
tc qdisc del dev eth0 root netem delay 5000ms
異步復(fù)制導(dǎo)致數(shù)據(jù)丟失
因?yàn)閙aster->slave的復(fù)制是異步,所以可能有部分還沒(méi)來(lái)得及復(fù)制到slave就宕機(jī)了,此時(shí)這些部分?jǐn)?shù)據(jù)就丟失了。 怎么解決?(請(qǐng)記住只能降低到可控范圍,沒(méi)辦法做到100%不丟失)
- 最少有多少臺(tái)從機(jī)器才能寫(xiě)入
min-slaves-to-write 1 - 從節(jié)點(diǎn)最大延遲時(shí)間,延遲小于
min-slaves-max-lag秒的slave才認(rèn)為是健康的
slave min-slaves-max-lag 10
要求至少有1個(gè)slave,數(shù)據(jù)復(fù)制和同步的延遲不能超過(guò)10秒
如果說(shuō)一旦所有的slave,數(shù)據(jù)復(fù)制和同步的延遲都超過(guò)了10秒鐘,那么這個(gè)時(shí)候,master就不會(huì)再接收任何請(qǐng)求了 有了min-slaves-max-lag這個(gè)配置,就可以確保說(shuō),一旦slave復(fù)制數(shù)據(jù)和ack延時(shí)太長(zhǎng),就認(rèn)為可能master宕機(jī)后損失的數(shù)據(jù)太多了,那么就拒絕寫(xiě)請(qǐng)求,這樣可 以把master宕機(jī)時(shí)由于部分?jǐn)?shù)據(jù)未同步到slave導(dǎo)致的數(shù)據(jù)丟失降低到可控范圍內(nèi)。
如何選擇,要不要讀寫(xiě)分離?
沒(méi)有最合適的方案,只有最合適的場(chǎng)景,讀寫(xiě)分離需要業(yè)務(wù)可以容忍一定程度的數(shù)據(jù)不一致,適合讀多寫(xiě)少的業(yè)務(wù)場(chǎng)景,讀寫(xiě)分離,是為了什么,主要是因 為要建立一主多從的架構(gòu),才能橫向任意擴(kuò)展 slave node 去支撐更大的讀吞吐量。
從節(jié)點(diǎn)故障問(wèn)題
對(duì)于從節(jié)點(diǎn)的故障問(wèn)題,需要在客戶(hù)端維護(hù)一個(gè)可用從節(jié)點(diǎn)可用列表,當(dāng)從節(jié) 點(diǎn)故障時(shí),立刻切換到其他從節(jié)點(diǎn)或主節(jié)點(diǎn),之后講解redis Cluster 時(shí)候可以解 決這個(gè)問(wèn)題
配置不一致
主機(jī)和從機(jī)不同,經(jīng)常導(dǎo)致主機(jī)和從機(jī)的配置不同,并帶來(lái)問(wèn)題。
- 數(shù)據(jù)丟失: 主機(jī)和從機(jī)有時(shí)候會(huì)發(fā)生配置不一致的情況,例如 maxmemory 不一致,如果主機(jī)配置 maxmemory 為8G,從機(jī) slave 設(shè)置為4G,這個(gè)時(shí)候是可 以用的,而且還不會(huì)報(bào)錯(cuò)。 但是如果要做高可用,讓從節(jié)點(diǎn)變成主節(jié)點(diǎn)的時(shí)候,就會(huì)發(fā)現(xiàn)數(shù)據(jù)已經(jīng)丟失了,而且無(wú)法挽回
規(guī)避全量復(fù)制
全量復(fù)制指的是當(dāng) slave 從機(jī)斷掉并重啟后,runid 產(chǎn)生變化而導(dǎo)致需要在 master 主機(jī)里拷貝全部數(shù)據(jù)。這種拷貝全部數(shù)據(jù)的過(guò)程非常耗資源。 全量復(fù)制是不可避免的,例如第一次的全量復(fù)制是不可避免的,這時(shí)我們需要選擇小主節(jié)點(diǎn),且 maxmemory 值不要過(guò)大,這樣就會(huì)比較快。同時(shí)選擇在低峰值 的時(shí)候做全量復(fù)制。
造成全量復(fù)制的原因
- 是主從機(jī)的運(yùn)行 runid 不匹配。解釋一下,主節(jié)點(diǎn)如果重啟, runid 將會(huì)發(fā)生變化。如果從節(jié)點(diǎn)監(jiān)控到 runid 不是同一個(gè),它就會(huì)認(rèn)為你的節(jié)點(diǎn)不安全。 當(dāng)發(fā)生故障轉(zhuǎn)移的時(shí)候,如果主節(jié)點(diǎn)發(fā)生故障,那么從機(jī)就會(huì)變成主節(jié)點(diǎn)。我們會(huì)在后面講解哨兵和集群。
- 復(fù)制緩沖區(qū)空間不足,比如默認(rèn)值1M,可以部分復(fù)制。但如果緩存區(qū)不夠大的話(huà),首先需要網(wǎng)絡(luò)中斷,部分復(fù)制就無(wú)法滿(mǎn)足。其次需要增大復(fù)制緩沖區(qū)配 置(relbacklogsize),對(duì)網(wǎng)絡(luò)的緩沖增強(qiáng)。參考之前的說(shuō)明。
怎么解決
在一些場(chǎng)景下,可能希望對(duì)主節(jié)點(diǎn)進(jìn)行重啟,例如主節(jié)點(diǎn)內(nèi)存碎片率過(guò)高,或者希望調(diào)整一些只能在啟動(dòng)時(shí)調(diào)整的參數(shù)。如果使用普通的手段重啟主節(jié)點(diǎn),會(huì)使 得runid發(fā)生變化,可能導(dǎo)致不必要的全量復(fù)制。 為了解決這個(gè)問(wèn)題,Redis提供了debug reload的重啟方式:重啟后,主節(jié)點(diǎn)的runid和offset都不受影響,避免了全量復(fù)制。
單機(jī)的復(fù)制風(fēng)暴
- 當(dāng)一個(gè)主機(jī)下面掛了很多個(gè)
slave從機(jī)的時(shí)候,主機(jī)master掛了,這時(shí)master主機(jī)重啟后,因?yàn)?runid發(fā)生了變化,所有的 slave 從機(jī)都要做一次全 量復(fù)制。這將引起單節(jié)點(diǎn)和單機(jī)器的復(fù)制風(fēng)暴,開(kāi)銷(xiāo)會(huì)非常大。
單機(jī)復(fù)制風(fēng)暴.png
解決:
- 可以采用樹(shù)狀結(jié)構(gòu)降低多個(gè)從節(jié)點(diǎn)對(duì)主節(jié)點(diǎn)的消耗
- 從節(jié)點(diǎn)采用樹(shù)狀樹(shù)非常有用,網(wǎng)絡(luò)開(kāi)銷(xiāo)交給位于中間層的從節(jié)點(diǎn),而不必消耗頂層的主節(jié)點(diǎn)。但是這種樹(shù)狀結(jié)構(gòu)也帶來(lái)了運(yùn)維的復(fù)雜性,增加了手動(dòng)和自動(dòng) 處理故障轉(zhuǎn)移的難度
-
由于 Redis 的單線程架構(gòu),通常單臺(tái)機(jī)器會(huì)部署多個(gè) Redis 實(shí)例。當(dāng)一臺(tái)機(jī)器(machine)上同時(shí)部署多個(gè)主節(jié)點(diǎn) (master) 時(shí),如果每個(gè) master 主 機(jī)只有一臺(tái) slave 從機(jī),那么當(dāng)機(jī)器宕機(jī)以后,會(huì)產(chǎn)生大量全量復(fù)制。這種情況是非常危險(xiǎn)的情況,帶寬?cǎi)R上會(huì)被占用,會(huì)導(dǎo)致不可用。
1.png
解決:
- 應(yīng)該把主節(jié)點(diǎn)盡量分散在多臺(tái)機(jī)器上,避免在單臺(tái)機(jī)器上部署過(guò)多的主節(jié)點(diǎn)。
- 當(dāng)主節(jié)點(diǎn)所在機(jī)器故障后提供故障轉(zhuǎn)移機(jī)制,避免機(jī)器恢復(fù)后進(jìn)行密集的全量復(fù)制
主從配置參數(shù)參考
###########主庫(kù)##############
- 在slave和master同步后(發(fā)送psync/sync),后續(xù)的同步是否設(shè)置成TCP_NODELAY假如設(shè)置成yes,則redis會(huì)合并小的TCP包從而節(jié)省帶寬,但會(huì)增加 同步延遲(40ms),造成master與slave數(shù)據(jù)不一致假如設(shè)置成no,則redis master會(huì)立即發(fā)送同步數(shù)據(jù),沒(méi)有延遲,前者關(guān)注性能,后者關(guān)注一致性
repl-disable-tcp-nodelay no - 從庫(kù)會(huì)按照一個(gè)時(shí)間間隔向主庫(kù)發(fā)送PING命令來(lái)判斷主服務(wù)器是否在線,默認(rèn)是10秒
repl-ping-slave-period 10 - 復(fù)制積壓緩沖區(qū)大小設(shè)置
repl-backlog-size 1mb - master沒(méi)有slave一段時(shí)間會(huì)釋放復(fù)制緩沖區(qū)的內(nèi)存,repl-backlog-ttl用來(lái)設(shè)置該時(shí)間長(zhǎng)度。單位為秒
repl-backlog-ttl 3600 - redis提供了可以讓master停止寫(xiě)入的方式,如果配置了min-slaves-to-write,健康的slave的個(gè)數(shù)小于N,mater就禁止寫(xiě)入。master最少得有多少個(gè)健康的slave存活才能執(zhí)行寫(xiě)命令。這個(gè)配置雖然不能保證N個(gè)slave都一定能接收到master的寫(xiě)操作,但是能避免沒(méi)有足夠健康的slave的時(shí)候,master不 能寫(xiě)入來(lái)避免數(shù)據(jù)丟失。設(shè)置為0是關(guān)閉該功能
min-slaves-to-write 3
min-slaves-max-lag 10




