Redis 高可用主要是使用 主從復(fù)制 和 哨兵來(lái)做,集群不能算是高可用,因?yàn)楫?dāng)節(jié)點(diǎn)B有大量的數(shù)據(jù)欣孤,如果節(jié)點(diǎn)B掛掉,就再無(wú)法訪問(wèn)到節(jié)點(diǎn)B的數(shù)據(jù)昔逗,因?yàn)槠渌?jié)點(diǎn)并不會(huì)有節(jié)點(diǎn)B的數(shù)據(jù)降传。其中的原因跟本身Redis的設(shè)計(jì)有關(guān)。
復(fù)制
使用和配置主從復(fù)制非常簡(jiǎn)單勾怒,從 Redis 服務(wù)器(下文稱 slave)能精確得復(fù)制主 Redis 服務(wù)器(下文稱 master)的內(nèi)容婆排。每次當(dāng) slave 和 master 之間的連接斷開(kāi)時(shí), slave 會(huì)自動(dòng)重連到 master 上笔链,并且無(wú)論這期間 master 發(fā)生了什么段只, slave 都將嘗試讓自身成為 master 的精確副本。
這個(gè)系統(tǒng)的運(yùn)行依靠三個(gè)主要的機(jī)制:
- 當(dāng)一個(gè) master 實(shí)例和一個(gè) slave 實(shí)例連接正常時(shí)鉴扫, master 會(huì)發(fā)送一連串的命令流來(lái)保持對(duì) slave 的更新赞枕,以便于將自身數(shù)據(jù)集的改變復(fù)制給 slave ,包括客戶端的寫(xiě)入、key 的過(guò)期或被逐出等等(增量)炕婶。
- 當(dāng) master 和 slave 之間的連接斷開(kāi)之后姐赡,因?yàn)榫W(wǎng)絡(luò)問(wèn)題、或者是主從意識(shí)到連接超時(shí)柠掂, slave 重新連接上 master 并會(huì)嘗試進(jìn)行部分重同步:這意味著它會(huì)嘗試只獲取在斷開(kāi)連接期間內(nèi)丟失的命令项滑。
- 當(dāng)無(wú)法進(jìn)行部分重同步時(shí), slave 會(huì)請(qǐng)求進(jìn)行全量重同步陪踩。這會(huì)涉及到一個(gè)更復(fù)雜的過(guò)程杖们,例如 master 需要?jiǎng)?chuàng)建所有數(shù)據(jù)的快照,將之發(fā)送給 slave 肩狂,之后在數(shù)據(jù)集更改時(shí)持續(xù)發(fā)送命令到 slave 摘完。
Redis 默認(rèn)使用異步復(fù)制,其特點(diǎn)是低延遲和高性能傻谁。slave 服務(wù)會(huì)異步地確認(rèn)其從 master 服務(wù)器周期接收到的數(shù)據(jù)量孝治。
Redis 復(fù)制的非常重要的事實(shí):
- Redis 使用異步復(fù)制,slave 和 master 之間異步確認(rèn)處理數(shù)據(jù)审磁。
- 一個(gè) master 可以擁有多個(gè) slave
- slave 可以接受其他 slave 的連接谈飒。除了多個(gè) slave 可以連接到同一個(gè) master 之外, slave 之間也可以像層疊狀的結(jié)構(gòu)連接到其他 slave 态蒂。自 Redis 4.0 起杭措,所有的 sub-slave 將會(huì)從 master 收到完全一樣的復(fù)制流。
- Redis 復(fù)制在 master 是非阻塞的钾恢。這意味著 master 在一個(gè)或多個(gè) slave 進(jìn)行初次同步或者是部分重同步時(shí)手素,可以繼續(xù)處理查詢請(qǐng)求。
- 主從復(fù)制對(duì)于 slave 服務(wù)器來(lái)說(shuō)也是非阻塞的瘩蚪,這意味著泉懦,即使從redis在進(jìn)行主從復(fù)制過(guò)程中也可以接受外界的查詢請(qǐng)求,只不過(guò)這時(shí)候 slave 返回的是以前老的數(shù)據(jù)疹瘦,如果你不想這樣崩哩,那么在啟動(dòng)redis時(shí),可以在配置文件中進(jìn)行設(shè)置言沐,那么 slave 在復(fù)制同步過(guò)程中來(lái)自外界的查詢請(qǐng)求都會(huì)返回錯(cuò)誤給客戶端邓嘹;(雖然說(shuō)主從復(fù)制過(guò)程中對(duì)于 slave 是非阻塞的,但是當(dāng) slave 從 master 同步過(guò)來(lái)最新的數(shù)據(jù)后還需要將新數(shù)據(jù)加載到內(nèi)存中险胰,在加載到內(nèi)存的過(guò)程中是阻塞的吴超,在這段時(shí)間內(nèi)的請(qǐng)求將會(huì)被阻,但是即使對(duì)于大數(shù)據(jù)集鸯乃,加載到內(nèi)存的時(shí)間也是比較多的)
- 主從復(fù)制提高了redis服務(wù)的擴(kuò)展性,避免單個(gè)redis服務(wù)器的讀寫(xiě)訪問(wèn)壓力過(guò)大的問(wèn)題,同時(shí)也可以給為數(shù)據(jù)備份及冗余提供一種解決方案缨睡;
- 為了避免 master 服務(wù)器寫(xiě)磁盤(pán)壓力帶來(lái)的開(kāi)銷(xiāo)鸟悴,可以配置讓 master 不在將數(shù)據(jù)持久化到磁盤(pán),而是通過(guò)連接讓一個(gè)配置的 slave 服務(wù)器及時(shí)的將相關(guān)數(shù)據(jù)持久化到磁盤(pán)奖年,不過(guò)這樣會(huì)存在一個(gè)問(wèn)題细诸,就是 master 服務(wù)器一旦重啟,因?yàn)?master 服務(wù)器數(shù)據(jù)為空陋守,這時(shí)候通過(guò)主從同步可能導(dǎo)致從 slave 服務(wù)器上的數(shù)據(jù)也被清空震贵;
強(qiáng)烈建議在 master 和在 slave 中啟用持久化。否則會(huì)有如下問(wèn)題:
我們?cè)O(shè)置節(jié)點(diǎn) A 為 master 并關(guān)閉它的持久化設(shè)置水评,slave B 和 C 從 節(jié)點(diǎn) A 復(fù)制數(shù)據(jù)猩系。節(jié)點(diǎn) A 崩潰,但是他有一些自動(dòng)重啟的系統(tǒng)可以重啟進(jìn)程中燥。但是由于持久化被關(guān)閉了寇甸,節(jié)點(diǎn)重啟后其數(shù)據(jù)集合為空。節(jié)點(diǎn) B 和 節(jié)點(diǎn) C 會(huì)從節(jié)點(diǎn) A 復(fù)制數(shù)據(jù)疗涉,但是節(jié)點(diǎn) A 的數(shù)據(jù)集是空的拿霉,因此復(fù)制的結(jié)果是它們會(huì)銷(xiāo)毀自身之前的數(shù)據(jù)副本。
當(dāng) Redis Sentinel 被用于高可用并且 master 關(guān)閉持久化咱扣,這時(shí)如果允許自動(dòng)重啟進(jìn)程也是很危險(xiǎn)的绽淘。例如, master 可以重啟的足夠快以致于 Sentinel 沒(méi)有探測(cè)到故障闹伪,因此上述的故障模式也會(huì)發(fā)生沪铭。
工作模式
Redis不管是舊版還是新版,復(fù)制的實(shí)現(xiàn)都可以分為七個(gè)步驟:
1. 設(shè)置主服務(wù)的地址與端口
127.0.0.1:12345> SLAVEOF 127.0.0.1 6379
當(dāng)客戶端向 slave 器發(fā)送以上命令時(shí)或者在配置文件中配置slaveof選項(xiàng)祭往。slave 將向發(fā)送 SLAVEOF 命令的 客戶端 返回OK伦意,表示復(fù)制指令已經(jīng)被接收,而實(shí)際上復(fù)制工作是在OK返回之后進(jìn)行硼补。
2. 建立套接字連接
slave 器根據(jù)設(shè)置的套接字創(chuàng)建連向 master 的套接字連接驮肉。 master 接收 slave 器的套接字連接之后,為該套接字創(chuàng)建響應(yīng)的客戶端狀態(tài)已骇,并將此時(shí)的 slave 器看做是 master 的客戶端离钝,也就是該 slave 器同時(shí)具備服務(wù)器與客戶端兩個(gè)身份。
3. 發(fā)送PING命令
slave 成為 master 的客戶端之后褪储,做的第一件事就是向 master 發(fā)送PING命令卵渴。PING命令主要有兩種作用:
- 雖然建立了套接字連接,但是還未使用過(guò)鲤竹,通過(guò)發(fā)送PING命令檢查套接字的讀寫(xiě)狀態(tài)是否正常
- 通過(guò)發(fā)送PING命令檢查 master 能否正常處理命令請(qǐng)求
slave 在發(fā)送PING命令之后將遇到以下三種情況的其中一種:
- master 向 slave 返回一個(gè)回復(fù)浪读,但是 slave 卻不能在規(guī)定的會(huì)時(shí)間(timeout)內(nèi)讀取命令回復(fù)的內(nèi)容,則表示當(dāng)前主 slave 之間的網(wǎng)絡(luò)狀態(tài)連接不佳,不能基礎(chǔ)執(zhí)行復(fù)制工作的后續(xù)步驟碘橘,這時(shí) slave 會(huì)斷開(kāi)套接字連接重新創(chuàng)建互订。
- master 向 slave 返回一個(gè)錯(cuò)誤,那么表示 master 暫時(shí)沒(méi)有辦法處理 slave 器的命令請(qǐng)求痘拆,不能繼續(xù)執(zhí)行復(fù)制工作的后續(xù)步驟仰禽,這時(shí) slave 會(huì)斷開(kāi)套接字連接重新創(chuàng)建。
- 如果 slave 讀取到“PONG”回復(fù)纺蛆,那么表示主從之間網(wǎng)絡(luò)連接正常吐葵,并且 master 可以處理 slave 發(fā)送的命令請(qǐng)求。
4. 身份驗(yàn)證
slave 接收到 master 返回的“PONG”回復(fù)桥氏,接下來(lái)就需要考慮身份驗(yàn)證的事温峭。
如果 slave 設(shè)置了 masterauth 選項(xiàng),那么進(jìn)行身份驗(yàn)證
如果 slave 沒(méi)有設(shè)置 masterauth 選項(xiàng)识颊,那么不進(jìn)行身份驗(yàn)證
slave 在身份驗(yàn)證的時(shí)候可能遇到三種情況
- 主服務(wù)沒(méi)有設(shè)置 requirepass 選項(xiàng)诚镰,并且 slave 也沒(méi)有設(shè)置 masterquth 選項(xiàng),那么 master 繼續(xù)執(zhí)行 slave 命令祥款,完成復(fù)制工作
- 如果 slave 通過(guò)AUTH命令發(fā)送的密碼與 master 中requirepass密碼相同清笨,那么 master 將繼續(xù)執(zhí)行 slave 發(fā)送的命令,復(fù)制工作繼續(xù)刃跛,與此相反抠艾,密碼不一致,則會(huì)返回 invalid password 錯(cuò)誤
- 如果 slave 沒(méi)有設(shè)置 masterauth 選項(xiàng)桨昙,而 master 設(shè)置了 requirepass 選項(xiàng)检号,那么 master 將返回一個(gè)NOAUTH錯(cuò)誤。反之沒(méi)有設(shè)設(shè)置 masterauth 選項(xiàng)蛙酪,而設(shè)置了 requirepass 選項(xiàng)齐苛,那么會(huì)返回 no password is set 錯(cuò)誤。
5. 發(fā)送端口信息
在身份驗(yàn)證步驟之后桂塞,slave 將執(zhí)行命令REPLCONF listening-port <port>凹蜂,向 master 發(fā)送 slave 的監(jiān)聽(tīng)端口號(hào)。
6. 同步 7. 命令傳播
slave 向 master 發(fā)送PSYNC命令阁危,執(zhí)行同步操作玛痊,值得注意的是只有 slave 是 master 的客戶端,但是執(zhí)行同步操作之后狂打,master 也會(huì)成為 slave 的客戶端擂煞。
master | slave | 備注 |
---|---|---|
主從完成同步 | 主從完成同步 | 主從都啟動(dòng),并完成同步 |
set k1,v1 | set k1,v1 | master 執(zhí)行set會(huì)傳播到slave 進(jìn)行set |
set k2,v2 | set k2,v2 | master 執(zhí)行set會(huì)傳播到slave 進(jìn)行set |
...... | ...... | 更多的操作 |
主從斷開(kāi)連接 | 主從斷開(kāi)連接 | slave故障停止了同步操作 |
set k5002,v5002 | slave 嘗試重新連接 | |
set k5003,v5003 | slave 嘗試重新連接 | |
主從重連接成功 | 主從重連接成功 | 主從重連接成功 |
PSYNC | 連接成功趴乡,slave 向 master 發(fā)送PSYNC命令对省,執(zhí)行同步蝗拿,以上第6步 | |
向slave返回+CONTINUE,并執(zhí)行同步 | ||
接收+CONTINUE | slave 接收+CONTINUE官辽,準(zhǔn)備執(zhí)行部分同步 | |
向 slave 發(fā)送 set k5002,v5002 和 set k5003,v5003 命令 | ||
set k5002,v5002 set k5003,v5003 | 從接收到命令并執(zhí)行 | |
主從完成同步 | 主從完成同步 | 同步完成 |
高版本的 Redis slave 默認(rèn)為只讀蛹磺。