Redis主從/哨兵機(jī)制原理分析
一、主從復(fù)制
1.1 什么是主從復(fù)制
主從復(fù)制,是指將一臺Redis服務(wù)器的數(shù)據(jù),復(fù)制到其他的Redis服務(wù)器。
前者稱為主節(jié)點(diǎn)(master),后者稱為從節(jié)點(diǎn)(slave);數(shù)據(jù)的復(fù)制是單向的,只能由主節(jié)點(diǎn)到從節(jié)點(diǎn)
默認(rèn)情況下,每臺redis服務(wù)器都是主節(jié)點(diǎn);且一個(gè)主節(jié)點(diǎn)可以有多個(gè)從節(jié)點(diǎn)(或者沒有),但一個(gè)從節(jié)點(diǎn)只有一個(gè)主。
1.2 主從復(fù)制的作用
1)數(shù)據(jù)冗余:主從復(fù)制實(shí)現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式。
2)故障恢復(fù):當(dāng)主節(jié)點(diǎn)出現(xiàn)問題時(shí),可以由從節(jié)點(diǎn)提供服務(wù),實(shí)現(xiàn)快速的故障恢復(fù);實(shí)際上是一種服務(wù)的冗余。
3)負(fù)載均衡:在主從復(fù)制的基礎(chǔ)上,配合讀寫分離,可以由主節(jié)點(diǎn)提供寫服務(wù),由從節(jié)點(diǎn)提供讀服務(wù)(即寫Redis數(shù)據(jù)時(shí)應(yīng)用連接主節(jié)點(diǎn),讀Redis數(shù)據(jù)時(shí)應(yīng)用連接從節(jié)點(diǎn)),分擔(dān)服務(wù)器負(fù)載;尤其是在寫少讀多的場景下,通過多個(gè)從節(jié)點(diǎn)分擔(dān)讀負(fù)載,可以大大提高Redis服務(wù)器的并發(fā)量。
4)高可用基石:除了上述作用以外,主從復(fù)制還是哨兵和集群能夠?qū)嵤┑幕A(chǔ),因此說主從復(fù)制是Redis高可用的基礎(chǔ)。
主從庫采用的是讀寫分離的方式
1.3 主從復(fù)制原理
分為全量復(fù)制與增量復(fù)制
1.3.1 全量復(fù)制
發(fā)生在第一次復(fù)制時(shí)
- 第一階段是主從庫間建立連接、協(xié)商同步的過程。
- 第二階段,主庫將所有數(shù)據(jù)同步給從庫。
- 第三個(gè)階段,主庫會把第二階段執(zhí)行過程中新收到的寫命令,再發(fā)送給從庫。
1.3.2 增量復(fù)制
只會把主從庫網(wǎng)絡(luò)斷連期間主庫收到的命令,同步給從庫
1.3.3 同步流程
- 1)一個(gè)從數(shù)據(jù)庫啟動(dòng)后,會向主數(shù)據(jù)庫發(fā)送SYNC命令。
- 2)主數(shù)據(jù)庫在接收到SYNC命令后會開始在后臺保存快照(即RDB持久化的過程),并將保存快照期間接收到的命令緩存起來。在該持久化過程中會生成一個(gè).rdb的快照文件。
- 3)在主數(shù)據(jù)庫快照執(zhí)行完成后, Redis 會將快照文件和所有緩存的命令以 .rdb 快照文件的形式發(fā)送給從數(shù)據(jù)庫 。
- 4)從數(shù)據(jù)庫收到主數(shù)據(jù)庫的 .rdb 照文件后,載入該快照文件到本地。
- 5)從數(shù)據(jù)庫執(zhí)行載入后的 .rdb 照文件,將數(shù)據(jù)寫入內(nèi)存中。以上過程被稱為復(fù)制初始化
- 6)在 制初始化結(jié)束后, 主數(shù)據(jù)庫在每次收到寫命令時(shí)都會將命令同步給從數(shù)據(jù)庫,從而保證主從數(shù)據(jù)庫的數(shù)據(jù)一致性。
二、哨兵機(jī)制
2.1 哨兵機(jī)制介紹
2.1.1 集群邏輯圖
下圖是一個(gè)典型的哨兵集群監(jiān)控的邏輯圖
Redis Sentinel包含了若個(gè)Sentinel節(jié)點(diǎn),這樣做也帶來了兩個(gè)好處:
1)對于節(jié)點(diǎn)的故障判斷是由多個(gè)Sentinel節(jié)點(diǎn)共同完成,這樣可以有效地防止誤判
2)即使個(gè)別Sentinel節(jié)點(diǎn)不可用,整個(gè)Sentinel集群依然是可用的。
2.1.2 哨兵機(jī)制實(shí)現(xiàn)的功能
Redis-Sentinel是在master-slave機(jī)制上加入監(jiān)控機(jī)制哨兵Sentinel實(shí)現(xiàn)的。Sentinel主要功能就是為Redis Master-Slave集群提供:
1)監(jiān)控(Monitoring): Sentinel 會不斷地檢查你的主服務(wù)器和從服務(wù)器是否運(yùn)作正常。
2)提醒(Notification): 當(dāng)被監(jiān)控的某個(gè) Redis 服務(wù)器出現(xiàn)問題時(shí), Sentinel 可以通過 API 向管理員或者其他應(yīng)用程序發(fā)送通知。
3)自動(dòng)故障遷移(Automatic failover): 當(dāng)一個(gè)主服務(wù)器不能正常工作時(shí), Sentinel 會開始一次自動(dòng)故障遷移操作, 它會將失效主服務(wù)器的其中一個(gè)從服務(wù)器升級為新的主服務(wù)器, 并讓失效主服務(wù)器的其他從服務(wù)器改為復(fù)制新的主服務(wù)器; 當(dāng)客戶端試圖連接失效的主服務(wù)器時(shí), 集群也會向客戶端返回新主服務(wù)器的地址, 使得集群可以使用新主服務(wù)器代替失效服務(wù)器。
4)配置中心:在Redis Sentinel模式中,客戶端在初始化的時(shí)候連接的是Sentinel節(jié)點(diǎn)集合,從中獲取主節(jié)點(diǎn)信息。
其中,監(jiān)控和自動(dòng)故障轉(zhuǎn)移功能,使得哨兵可以及時(shí)發(fā)現(xiàn)主節(jié)點(diǎn)故障并完成轉(zhuǎn)移;而配置中心和通知功能,則需要在與客戶端的交互中才能體現(xiàn)。
在Sentinel集群中,一個(gè)最小的Master-Slave單元包含一個(gè)master和一個(gè)slave服務(wù)器。當(dāng)master失效后,sentinel自動(dòng)將slave提升為master,從而可以減少管理員的人工切換slave的操作過程。
2.2 哨兵機(jī)制原理
2.2.1 監(jiān)控
Sentinel節(jié)點(diǎn)需要監(jiān)控master、slave以及其它Sentinel節(jié)點(diǎn)的狀態(tài)。這一過程是通過Redis的pub/sub系統(tǒng)實(shí)現(xiàn)的。Redis Sentinel一共有三個(gè)定時(shí)監(jiān)控任務(wù),完成對各個(gè)節(jié)點(diǎn)發(fā)現(xiàn)和監(jiān)控:
1)監(jiān)控主從拓?fù)湫畔ⅲ?/strong>每隔10秒,每個(gè)Sentinel節(jié)點(diǎn),會向master和slave發(fā)送INFO命令獲取最新的拓?fù)浣Y(jié)構(gòu)
2)Sentinel節(jié)點(diǎn)信息交換:每隔2秒,每個(gè)Sentinel節(jié)點(diǎn),會向Redis數(shù)據(jù)節(jié)點(diǎn)的__sentinel__:hello頻道上,發(fā)送自身的信息,以及對主節(jié)點(diǎn)的判斷信息。這樣,Sentinel節(jié)點(diǎn)之間就可以交換信息
3)節(jié)點(diǎn)狀態(tài)監(jiān)控:每隔1秒,每個(gè)Sentinel節(jié)點(diǎn),會向master、slave、其余Sentinel節(jié)點(diǎn)發(fā)送PING命令做心跳檢測,來確認(rèn)這些節(jié)點(diǎn)當(dāng)前是否可達(dá)。
2.2.2 下線
2.2.2.1 下線流程
1)每個(gè)Sentinel以每秒一次的頻率向它所知的Master,Slave以及其他Sentinel實(shí)例發(fā)送一個(gè)PING命令。
2)如果一個(gè)實(shí)例(instance)距離最后一次有效恢復(fù)PING命令的時(shí)間超過own-after-milliseconds選項(xiàng)所指定的值,則這個(gè)實(shí)例會被Sentinel標(biāo)為主觀下線(Sentinel Leader PING命令確認(rèn))。
3)當(dāng)有足夠的Sentinel(大于等于文件配置的值)在指定的時(shí)間范圍內(nèi)確認(rèn)Master的確進(jìn)入了主觀下線狀態(tài),則Master會被標(biāo)記為客觀下線。
2.2.2.2 主觀下線
每個(gè)Sentinel節(jié)點(diǎn),每隔1秒會對數(shù)據(jù)節(jié)點(diǎn)發(fā)送ping命令做心跳檢測,當(dāng)這些節(jié)點(diǎn)超過down-after-milliseconds沒有進(jìn)行有效回復(fù)時(shí),Sentinel節(jié)點(diǎn)會對該節(jié)點(diǎn)做失敗判定,這個(gè)行為叫做主觀下線。
2.2.2.3 客觀下線
客觀下線,是指當(dāng)大多數(shù)Sentinel節(jié)點(diǎn),都認(rèn)為master節(jié)點(diǎn)宕機(jī)了,那么這個(gè)判定就是客觀的,叫做客觀下線。
那么這個(gè)大多數(shù)是指多少呢?這其實(shí)就是分布式協(xié)調(diào)中的quorum判定了,大多數(shù)就是過半數(shù),比如哨兵數(shù)量是5,那么大多數(shù)就是5/2+1=3個(gè),哨兵數(shù)量是10大多數(shù)就是10/2+1=6個(gè)。
注:Sentinel節(jié)點(diǎn)的數(shù)量至少為3個(gè),否則不滿足quorum判定條件。
2.2.3 哨兵選舉
如果發(fā)生了客觀下線,那么哨兵節(jié)點(diǎn)會選舉出一個(gè)Leader來進(jìn)行實(shí)際的故障轉(zhuǎn)移工作。Redis使用了Raft算法來實(shí)現(xiàn)哨兵領(lǐng)導(dǎo)者選舉,大致思路如下:
1)每個(gè)Sentinel節(jié)點(diǎn)都有資格成為領(lǐng)導(dǎo)者,當(dāng)它主觀認(rèn)為某個(gè)數(shù)據(jù)節(jié)點(diǎn)宕機(jī)后,會向其他Sentinel節(jié)點(diǎn)發(fā)送sentinel is-master-down-by-addr命令,要求自己成為領(lǐng)導(dǎo)者;
2)收到命令的Sentinel節(jié)點(diǎn),如果沒有同意過其他Sentinel節(jié)點(diǎn)的sentinelis-master-down-by-addr命令,將同意該請求,否則拒絕(每個(gè)Sentinel節(jié)點(diǎn)只有1票);
3)如果該Sentinel節(jié)點(diǎn)發(fā)現(xiàn)自己的票數(shù)已經(jīng)大于等于MAX(quorum, num(sentinels)/2+1),那么它將成為領(lǐng)導(dǎo)者;
4)如果此過程沒有選舉出領(lǐng)導(dǎo)者,將進(jìn)入下一次選舉。
2.2.4 故障轉(zhuǎn)移
1)向被選中的從服務(wù)器發(fā)送slave of no one命令,讓它轉(zhuǎn)變?yōu)橹鞣?wù)器
2)通過發(fā)布/訂閱功能,將更新后的配置傳播給所有其他Sentinel,其他Sentinel對他們自己的配置進(jìn)行更新。
3)向所有Slave下達(dá)slave of 命令,指向新的主
4)redis-slave 向master重新建立連接,master向所有slave節(jié)點(diǎn)發(fā)送rdb,保持?jǐn)?shù)據(jù)同步
5)在上述轉(zhuǎn)移過程中,伴隨著Redis本地配置文件的自動(dòng)重寫,這樣即便是實(shí)例重啟配置也不會丟失
6)原有的master在恢復(fù)后降級為slave與新的master全量同步
注:Leader Sentinel節(jié)點(diǎn),會從新的master節(jié)點(diǎn)那里得到一個(gè)configuration epoch,本質(zhì)是個(gè)version版本號,每次主從切換的version號都必須是唯一的。其他的哨兵都是根據(jù)version來更新自己的master配置。
1)Sentinel自動(dòng)故障遷移使用raft算法來選舉Sentinel-leader。
2)超過半數(shù)投票選出leader,Sentinel Leader用于下達(dá)故障轉(zhuǎn)移的指令。
3)如果某個(gè)Leader掛了,則使用raft從剩下的Sentinel中選出leader。
2.2.5 redis哨兵主備切換的數(shù)據(jù)丟失問題
2.2.5.1 主從異步復(fù)制導(dǎo)致的數(shù)據(jù)丟失
Redis master 和slave 數(shù)據(jù)復(fù)制是異步的,這樣就有可能會出現(xiàn)部分?jǐn)?shù)據(jù)還沒有復(fù)制到slave中,master就掛掉了,那么這部分的數(shù)據(jù)就會丟失了。
2.2.5.2 腦裂導(dǎo)致的數(shù)據(jù)丟失
腦裂其實(shí)就是網(wǎng)絡(luò)分區(qū)導(dǎo)致的現(xiàn)象,比如,我們的master機(jī)器網(wǎng)絡(luò)突然不正常了發(fā)生了網(wǎng)絡(luò)分區(qū),和其他的slave機(jī)器不能正常通信了,其實(shí)master并沒有掛還活著好好的呢,但是哨兵可不是吃閑飯的啊,它會認(rèn)為master掛掉了啊,那么問題來了,client可能還在繼續(xù)寫master的呀,還沒來得及更新到新的master呢,那這部分?jǐn)?shù)據(jù)就會丟失。
2.2.5.3 解決方案
上面的兩個(gè)數(shù)據(jù)丟失的問題,那我們該怎么去解決呢?其實(shí)也很簡單,只需要在配置中加兩個(gè)配置就行了,如下:
min-slaves-to-write 1 # 要求至少一個(gè)slave min-slaves-max-lag 10 # 數(shù)據(jù)復(fù)制和同步的延遲不能超過10s
我們不能只是去解決問題,我們要知道為什么這么做就可以解決問題,下面我們就來分析下,加上了這兩個(gè)配置是怎么解決我們數(shù)據(jù)丟失問題的。
核心思想就是,一旦所有的slave節(jié)點(diǎn),在數(shù)據(jù)復(fù)制和同步時(shí)延遲了超過10秒的話,那么master它就不會再接客戶端的請求了,這樣就會有效減少大量數(shù)據(jù)丟失的發(fā)生。
- 2.2.5.3.1 如何減少異步復(fù)制數(shù)據(jù)的丟失
現(xiàn)在當(dāng)我們的slave在數(shù)據(jù)復(fù)制的時(shí)候,發(fā)現(xiàn)返回的ACK時(shí)延太長達(dá)到了 min-slaves-max-lag 配置,這個(gè)時(shí)候就會認(rèn)為如果master宕機(jī)就會導(dǎo)致大量數(shù)據(jù)丟失,所以就提前進(jìn)行了預(yù)測,就不再去接收客戶端的任何請求了,來將丟失的數(shù)據(jù)降低在可控范圍內(nèi)。
- 2.2.5.3.2 如何減少腦裂數(shù)據(jù)的丟失
1)如果master出現(xiàn)了腦裂,和其他的slave失去了通信,不能繼續(xù)給指定數(shù)量的slave發(fā)送數(shù)據(jù)。
2)slave超過10秒沒有給自己返回ack消息。
3)master就會拒絕客戶端的寫請求
三、總結(jié)
今天我們學(xué)習(xí)了Redis 主從集群機(jī)制和Redis Sentinel 機(jī)制的基本使用和底層知識原理介紹,同時(shí)在使用哨兵機(jī)制過程中對于可能出現(xiàn)的數(shù)據(jù)丟失進(jìn)行相關(guān)避坑方案講解,希望幫助大家能更好的掌握Redis的主從機(jī)制和哨兵機(jī)制。
這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis實(shí)現(xiàn)每周熱評的項(xiàng)目實(shí)踐
實(shí)時(shí)統(tǒng)計(jì)和展示熱門內(nèi)容是一種常見的需求,本文主要介紹了Redis實(shí)現(xiàn)每周熱評的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03使用百度地圖api通過redis實(shí)現(xiàn)地標(biāo)存儲及范圍坐標(biāo)點(diǎn)查詢功能
這篇文章主要介紹了使用百度地圖api通過redis實(shí)現(xiàn)地標(biāo)存儲及范圍坐標(biāo)點(diǎn)查詢功能,本文通過圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-08-08Redis禁用命令、危險(xiǎn)命令及規(guī)避方法
這篇文章主要介紹了Redis禁用命令、危險(xiǎn)命令及規(guī)避方法,本文介紹了個(gè)非常致命的兩個(gè)命令以及用配置文件禁用這些命令的方法,需要的朋友可以參考下2015-06-06Redis實(shí)現(xiàn)Session共享與單點(diǎn)登錄
本文主要介紹了Redis實(shí)現(xiàn)Session共享與單點(diǎn)登錄,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07