真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何分析redis中的高可用方案

小編今天帶大家了解如何分析redis中的高可用方案,文中知識(shí)點(diǎn)介紹的非常詳細(xì)。覺(jué)得有幫助的朋友可以跟著小編一起瀏覽文章的內(nèi)容,希望能夠幫助更多想解決這個(gè)問(wèn)題的朋友找到問(wèn)題的答案,下面跟著小編一起深入學(xué)習(xí)“如何分析redis中的高可用方案”的知識(shí)吧。

建網(wǎng)站原本是網(wǎng)站策劃師、網(wǎng)絡(luò)程序員、網(wǎng)頁(yè)設(shè)計(jì)師等,應(yīng)用各種網(wǎng)絡(luò)程序開(kāi)發(fā)技術(shù)和網(wǎng)頁(yè)設(shè)計(jì)技術(shù)配合操作的協(xié)同工作。成都創(chuàng)新互聯(lián)專業(yè)提供做網(wǎng)站、網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站制作(企業(yè)站、響應(yīng)式網(wǎng)站設(shè)計(jì)、電商門戶網(wǎng)站)等服務(wù),從網(wǎng)站深度策劃、搜索引擎友好度優(yōu)化到用戶體驗(yàn)的提升,我們力求做到極致!

主從復(fù)制

用戶可以通過(guò)SLAVEOF命令或者配置,讓一個(gè)服務(wù)器去復(fù)制另一個(gè)服務(wù)器。被復(fù)制的服務(wù)器稱為主服務(wù)器,進(jìn)行復(fù)制的服務(wù)器稱為從服務(wù)器。這樣你在主服務(wù)器上增加鍵值,同時(shí)可以在從服務(wù)器上讀取?!鞠嚓P(guān)推薦:Redis視頻教程】

復(fù)制的過(guò)程又分為同步和命令傳播兩個(gè)步驟。

同步

同步將從服務(wù)器的數(shù)據(jù)庫(kù)狀態(tài)更新到主服務(wù)器當(dāng)前的數(shù)據(jù)庫(kù)狀態(tài)。

客戶端向從服務(wù)器發(fā)送SLAVEOF命令時(shí),從服務(wù)器會(huì)向主服務(wù)器發(fā)生SYNC命令進(jìn)行同步,步驟如下:

  • 從服務(wù)器向主服務(wù)器發(fā)生SYNC命令。

  • 收到SYNC命令的主服務(wù)器執(zhí)行BGSAVE命令,在后臺(tái)生成一個(gè)RDB文件,并用一個(gè)緩沖區(qū)記錄從現(xiàn)在開(kāi)始執(zhí)行的所有寫命令。

  • 主服務(wù)器的BGSAVE命令執(zhí)行完畢后,主服務(wù)器將BGSAVE生成的RDB文件發(fā)送給從服務(wù)器,從服務(wù)器接收并載入這個(gè)RDB文件,將從服務(wù)器的數(shù)據(jù)庫(kù)狀態(tài)更新到主服務(wù)器執(zhí)行BGSAVE命令時(shí)的數(shù)據(jù)庫(kù)狀態(tài)

  • 主服務(wù)器將緩沖區(qū)的所有寫命令發(fā)送給從服務(wù)器,從服務(wù)器執(zhí)行這些寫命令,將數(shù)據(jù)庫(kù)狀態(tài)更新至主服務(wù)器當(dāng)前數(shù)據(jù)庫(kù)狀態(tài)。

如何分析redis中的高可用方案

命令傳播

同步操作完成之后,主服務(wù)器和從服務(wù)器的數(shù)據(jù)庫(kù)狀態(tài)是一致的,但主服務(wù)器又接收到客戶端寫命令后,主從數(shù)據(jù)庫(kù)之間又產(chǎn)生了數(shù)據(jù)不一致,這時(shí)通過(guò)命令傳播達(dá)到數(shù)據(jù)庫(kù)一致。

PSYNC同步的優(yōu)化

2.8之前的同步每次都是全量同步,而如果是從服務(wù)器只是斷開(kāi)連接了一會(huì),事實(shí)上是不用從頭開(kāi)始同步的,只需要將斷開(kāi)連接這會(huì)的數(shù)據(jù)同步即可。所以2.8版本開(kāi)始使用PSYNC來(lái)代替SYNC命令。

PSYNC分成全量同步和部分同步兩種情況,全量同步就是處理初次同步的狀態(tài),而部分同步就是處理斷線重連這種情況。

部分同步的實(shí)現(xiàn)

部分同步主要使用了以下三部分:

  • 主服務(wù)器的復(fù)制偏移量和從服務(wù)器的復(fù)制偏移量

  • 主服務(wù)器的復(fù)制積壓緩沖區(qū)

  • 服務(wù)器的運(yùn)行ID

復(fù)制偏移量

主服務(wù)器的復(fù)制偏移量:主服務(wù)器每次向從服務(wù)器傳播N個(gè)字節(jié)的數(shù)據(jù)時(shí),就將自己的復(fù)制偏移量+N從服務(wù)器的復(fù)制偏移量:從服務(wù)器每次收到主服務(wù)器傳播的N個(gè)字節(jié)數(shù)據(jù),就將自己的復(fù)制偏移量+N 如果主從服務(wù)器處于一致?tīng)顟B(tài),那么它們的偏移量總是相同的,如果偏移量不相等,那么說(shuō)明它們處于不一致?tīng)顟B(tài)。

復(fù)制積壓緩沖區(qū)

復(fù)制積壓緩沖區(qū)由主服務(wù)器維護(hù)的一個(gè)固定長(zhǎng)度的FIFO隊(duì)列,默認(rèn)大小1MB,達(dá)到最大長(zhǎng)度后,最先入隊(duì)的會(huì)被彈出,給新入隊(duì)的元素讓位置。
redis命令傳播的時(shí)候不但會(huì)發(fā)送給從服務(wù)器,還會(huì)發(fā)送給復(fù)制積壓緩沖區(qū)。

如何分析redis中的高可用方案

當(dāng)從服務(wù)器重連上主服務(wù)器時(shí),從服務(wù)器會(huì)通過(guò)PSYNC命令將自己的復(fù)制偏移量offset發(fā)送給主服務(wù)器,主服務(wù)器根據(jù)復(fù)制偏移量來(lái)決定使用部分同步還是全量同步。 如果offset偏移量之后的數(shù)據(jù)還在復(fù)制積壓緩沖區(qū),那么使用部分同步,反之使用全量同步。
(書(shū)上沒(méi)說(shuō)是怎么判斷的,我猜測(cè)應(yīng)該是拿主復(fù)制偏移量減去從復(fù)制偏移量,如果大于1MB就說(shuō)明有數(shù)據(jù)不在緩沖積壓區(qū)?)

服務(wù)器的運(yùn)行ID

服務(wù)器啟動(dòng)時(shí)會(huì)生成一個(gè)40位隨機(jī)的字符作為服務(wù)器運(yùn)行ID。

從服務(wù)器對(duì)主服務(wù)器初次復(fù)制時(shí),主服務(wù)器會(huì)將自己的運(yùn)行ID傳送給從服務(wù)器,而從服務(wù)器會(huì)將這個(gè)運(yùn)行ID保存下來(lái)。從服務(wù)器斷線重連的時(shí)候,會(huì)將保存的運(yùn)行ID發(fā)送過(guò)去,如果從服務(wù)器保存的運(yùn)行ID和當(dāng)前主服務(wù)器的運(yùn)行ID相同,那么會(huì)嘗試部分同步,如果不同會(huì)執(zhí)行全量同步。

PSYNC的整體流程

如何分析redis中的高可用方案

心跳檢測(cè)

在命令傳播階段,從服務(wù)器會(huì)默認(rèn)以每秒一次的頻率,向主服務(wù)器發(fā)送命令:
REPLICONF ACK
其中replication_offset就是從服務(wù)器當(dāng)前的復(fù)制偏移量。 發(fā)送REPLICONF ACK命令對(duì)于主從服務(wù)器有三個(gè)作用:

  • 檢測(cè)主從服務(wù)器的網(wǎng)絡(luò)連接狀態(tài)。

  • 輔助實(shí)現(xiàn)min-slaves選項(xiàng)。

  • 檢測(cè)命令丟失。

檢測(cè)主從服務(wù)器的網(wǎng)絡(luò)連接狀態(tài)

主從服務(wù)器可以通過(guò)發(fā)送和接收REPLICONF ACK命令來(lái)檢查兩者之間的網(wǎng)絡(luò)連接是否正常:如果主服務(wù)器超過(guò)一秒鐘沒(méi)有收到從服務(wù)器發(fā)來(lái)的REPLICONF ACK命令,那么主服務(wù)器就知道主從之間出現(xiàn)問(wèn)題了。

輔助實(shí)現(xiàn)min-slaves選項(xiàng)

redis的min-slaves-to-writemin-slaves-max-lag兩個(gè)選項(xiàng)可以防止主從服務(wù)器在不安全的情況下執(zhí)行寫命令。

min-slaves-to-write 3
min-slaves-max-lag 10

如果配置如上,就表示如果從服務(wù)器的數(shù)量少于3個(gè),或者3個(gè)從服務(wù)器的延遲都大于或等于10秒時(shí),那么主服務(wù)器就將拒絕執(zhí)行寫命令。

檢測(cè)命令丟失

如果因?yàn)榫W(wǎng)絡(luò)故障,主服務(wù)器傳播給從服務(wù)器的寫命令在半路丟失,那么從服務(wù)器向主服務(wù)器發(fā)送REPLICONF ACK命令時(shí),主服務(wù)器將發(fā)覺(jué)從服務(wù)器當(dāng)前的復(fù)制偏移量少于自己的偏移量,那么主服務(wù)器可以根據(jù)從服務(wù)器的復(fù)制偏移量,在復(fù)制緩沖區(qū)當(dāng)中找到從服務(wù)器缺少的數(shù)據(jù),將這些數(shù)據(jù)重寫發(fā)送給從服務(wù)器。

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

其實(shí)主從復(fù)制就是多備份了一份數(shù)據(jù),因?yàn)榧词褂蠷DB和AOF進(jìn)行持久化,但是可能主服務(wù)器上整個(gè)機(jī)器掛掉了,而主從復(fù)制可以將主從服務(wù)器部署在兩臺(tái)不同的機(jī)器上,這樣即使主服務(wù)器的機(jī)器掛掉了,也可以手動(dòng)切換到從服務(wù)器繼續(xù)服務(wù)。

sentinel

主從雖然實(shí)現(xiàn)了數(shù)據(jù)的備份,但當(dāng)主服務(wù)器掛掉時(shí),需要手動(dòng)的將從服務(wù)器切換成主服務(wù)器。而sentinel就可以實(shí)現(xiàn)當(dāng)主服務(wù)器掛掉時(shí),自動(dòng)將從服務(wù)器切換成主服務(wù)器。

如何分析redis中的高可用方案

sentinel系統(tǒng)可以監(jiān)視所有的主從服務(wù)器,假設(shè)server1現(xiàn)在下線。當(dāng)server1的下線時(shí)長(zhǎng)超過(guò)用戶設(shè)定的下線時(shí)長(zhǎng)上限時(shí),sentinel系統(tǒng)就會(huì)對(duì)server1執(zhí)行故障轉(zhuǎn)移:

  • 首先sentinel系統(tǒng)會(huì)挑選server1下的其中一個(gè)從服務(wù)器,并將這個(gè)選中的從服務(wù)器升級(jí)成新的主服務(wù)器。

  • 之后,sentinel系統(tǒng)會(huì)向server1屬下的所有從服務(wù)器發(fā)送新的復(fù)制命令,讓他們成為新主服務(wù)器的從服務(wù)器。當(dāng)所有從服務(wù)器復(fù)制新的主服務(wù)器時(shí),故障轉(zhuǎn)移操作執(zhí)行完畢。

  • 另外,sentinel還會(huì)監(jiān)視已下線的server1,在它重新上線時(shí),將它設(shè)置為新的主服務(wù)器的從服務(wù)器。

初始化sentinel狀態(tài)

struct sentinelState {
    char myid[CONFIG_RUN_ID_SIZE+1]; 
    // 當(dāng)前紀(jì)元,用于實(shí)現(xiàn)故障轉(zhuǎn)移
    uint64_t current_epoch;
    // 保存了所有被這個(gè)sentinel監(jiān)視的主服務(wù)器
    // 字典的鍵是主服務(wù)器的名字
    // 字典的值是指向sentinelRedisInstance結(jié)構(gòu)的指針
    dict *masters;
    // 是否進(jìn)入了TILT模式
    int tilt;         
    // 目前正在執(zhí)行的腳本數(shù)量
    int running_scripts;   
    // 進(jìn)入TILT模式的時(shí)間
    mstime_t tilt_start_time;   
    // 最后一次執(zhí)行時(shí)間處理器的時(shí)間
    mstime_t previous_time;     
    // 一個(gè)fifo隊(duì)列,包含了所有需要執(zhí)行的用戶腳本
    list *scripts_queue;            
    char *announce_ip;  
    int announce_port; 
    unsigned long simfailure_flags; 
    int deny_scripts_reconfig;
    char *sentinel_auth_pass;   
    char *sentinel_auth_user;    
    int resolve_hostnames;      
    int announce_hostnames;     
} sentinel;

初始化sentinel狀態(tài)的masters屬性

masters記錄了所有被sentinel監(jiān)視的主服務(wù)器的相關(guān)信息,其中字典的鍵是被監(jiān)視服務(wù)器的名字,而值是被監(jiān)視服務(wù)器對(duì)應(yīng)著sentinelRedisInstance結(jié)構(gòu)。sentinelRedisInstance被sentinel服務(wù)器監(jiān)視的實(shí)例,可以是主服務(wù)器、從服務(wù)器或其他sentinel實(shí)例。

typedef struct sentinelRedisInstance {
    // 標(biāo)識(shí)值,記錄實(shí)例的類型,以及該實(shí)例的當(dāng)前狀態(tài)
    int flags;  
    // 實(shí)例的名字
    // 主服務(wù)器名字在配置文件中設(shè)置
    // 從服務(wù)器和sentinel名字由sentinel自動(dòng)設(shè)置,格式是ip:port
    char *name; 
    // 運(yùn)行id
    char *runid;   
    // 配置紀(jì)元,用于實(shí)現(xiàn)故障轉(zhuǎn)移
    uint64_t config_epoch;  
    // 實(shí)例的地址
    sentinelAddr *addr; /* Master host. */
    // 實(shí)例無(wú)響應(yīng)多少毫秒之后,判斷為主觀下線
    mstime_t down_after_period; 
    // 判斷這個(gè)實(shí)例為客觀下線所需的支持投票數(shù)量
    unsigned int quorum;
    // 執(zhí)行故障轉(zhuǎn)移,可以同時(shí)對(duì)新的主服務(wù)器進(jìn)行同步的從服務(wù)器數(shù)量
    int parallel_syncs; 
    // 刷新故障遷移狀態(tài)的最大時(shí)限
    mstime_t failover_timeout;  
    // 除了自己外,其他監(jiān)視主服務(wù)器的sentinel
    // 鍵是sentinel的名字,格式是ip:port
    // 值是鍵對(duì)應(yīng)的sentinel的實(shí)例結(jié)構(gòu)
    dict *sentinels;  
    // ...
} sentinelRedisInstance;

創(chuàng)建連向主服務(wù)器的網(wǎng)絡(luò)連接

初始化sentinel的最后一步是創(chuàng)建連向被監(jiān)視主服務(wù)器的網(wǎng)絡(luò)連接,會(huì)創(chuàng)建兩個(gè)連向主服務(wù)器的連接。

如何分析redis中的高可用方案

命令連接:專門向主服務(wù)器發(fā)送命令,并接收命令回復(fù)。
訂閱連接:專門用于訂閱主服務(wù)器的_sentinel_:hello頻道。

獲取主服務(wù)器信息

sentinel默認(rèn)會(huì)每10秒,通過(guò)命令連接向被監(jiān)視的主服務(wù)器發(fā)送INFO命令,并通過(guò)回復(fù)獲取主服務(wù)器當(dāng)前的信息?;貜?fù)可以獲得以下信息。

  • 主服務(wù)器的run_id

  • 主服務(wù)器下所有從服務(wù)器的信息。

根據(jù)這些信息可以更新sentinelRedisInstance下的name字典和runid字段。

獲取從服務(wù)器信息

sentinel也會(huì)創(chuàng)建連接到從服務(wù)器的命令連接和訂閱連接。

如何分析redis中的高可用方案

sentinel默認(rèn)會(huì)每10秒,通過(guò)命令連接向從服務(wù)器發(fā)送INFO命令,并通過(guò)回復(fù)獲取從服務(wù)器當(dāng)前的信息?;貜?fù)如下:

如何分析redis中的高可用方案

  • 從服務(wù)器的運(yùn)行ID

  • 從服務(wù)器的角色role

  • 主服務(wù)器的ip和端口

  • 主服務(wù)器的連接狀態(tài)master_link_status

  • 從服務(wù)器的優(yōu)先級(jí)slave_priority

  • 從服務(wù)器的復(fù)制偏移變量

根據(jù)info的回復(fù)信息,sentinel可以更新從服務(wù)器的實(shí)例結(jié)構(gòu)。

向主服務(wù)器和從服務(wù)器的訂閱連接發(fā)送信息

默認(rèn)情況下,sentinel會(huì)每2秒一次,向被監(jiān)視的主服務(wù)器和從服務(wù)器發(fā)送命令。

如何分析redis中的高可用方案

s_ip:sentinel的ip地址
s_port:sentinel的端口號(hào)
s_runid:sentinel的運(yùn)行id
s_epoch:sentinel當(dāng)前的配置紀(jì)元
m_name:主服務(wù)器的名字
m_ip:主服務(wù)器的ip地址
m_port:主服務(wù)器的端口號(hào)
m_epoch:主服務(wù)器當(dāng)前的配置紀(jì)元
向sentinel_:hello頻道發(fā)送信息,也會(huì)被監(jiān)視同一個(gè)服務(wù)器的其他sentinel監(jiān)聽(tīng)到(包括自己)。

創(chuàng)建連向其他sentinel的命令連接

sentinel之間會(huì)互相創(chuàng)建命令連接。監(jiān)視同一個(gè)囑咐其的多個(gè)sentinel將形成相互連接的網(wǎng)絡(luò)。

如何分析redis中的高可用方案

sentinel之間不會(huì)創(chuàng)建訂閱連接。

檢測(cè)主觀下線狀態(tài)

sentinel會(huì)每秒一次向所有與它創(chuàng)建了命令連接的實(shí)例(主服務(wù)器、從服務(wù)器、其他sentinel)發(fā)送ping命令,通過(guò)實(shí)例的回復(fù)來(lái)判斷實(shí)例是否在線。
有效回復(fù):實(shí)例返回+PONG、-LOADING、-MASTERDOWN其中一種。
無(wú)效回復(fù):以上三種回復(fù)之外的其他回復(fù),或者指定時(shí)長(zhǎng)內(nèi)沒(méi)回復(fù)。
某個(gè)實(shí)例在down-after-milliseconds毫秒內(nèi),連續(xù)向sentinel返回?zé)o效回復(fù)。那么sentinel就會(huì)修改這個(gè)實(shí)例對(duì)應(yīng)的實(shí)例結(jié)構(gòu),在結(jié)構(gòu)的flags屬性中打開(kāi)SRI_S_DOWN標(biāo)識(shí),標(biāo)識(shí)該實(shí)例進(jìn)入主觀下線狀態(tài)。(down-after-milliseconds可以在sentinel的配置文件中配置)

檢測(cè)客觀下線狀態(tài)

當(dāng)sentinel將一個(gè)主服務(wù)器判斷為主觀下線后,為了確認(rèn)這個(gè)主服務(wù)器是否真的下線,還會(huì)想其他同樣監(jiān)視這個(gè)主服務(wù)器的其他sentinel詢問(wèn),看其他sentinel是否也認(rèn)為該主服務(wù)器下線了。超過(guò)一定數(shù)量就將主服務(wù)器判斷為客觀下線。

詢問(wèn)其他sentinel是否同意該服務(wù)器下線

SENTINEL is-master-down-by-addr

通過(guò)SENTINEL is-master-down-by-addr命令詢問(wèn),參數(shù)意義如下圖:

如何分析redis中的高可用方案

接收SENTINEL is-master-down-by-addr命令

其他sentinel接收到SENTINEL is-master-down-by-addr命令后,會(huì)根據(jù)其中主服務(wù)器的ip和端口,檢查主服務(wù)器是否下線,然后返回包含三個(gè)參數(shù)的Multi Bulk的回復(fù)。

如何分析redis中的高可用方案

sentinel統(tǒng)計(jì)其他sentinel同意主服務(wù)器已下線的數(shù)量,達(dá)到配置的數(shù)量后,則將主服務(wù)器的flags屬性的SRI_O_DOWN標(biāo)識(shí)打開(kāi),表示主服務(wù)器已經(jīng)進(jìn)入客觀下線狀態(tài)。

選舉領(lǐng)頭sentinel

當(dāng)一個(gè)主服務(wù)器被判斷成客觀下線時(shí),監(jiān)視這個(gè)下線主服務(wù)器的各個(gè)sentinel就會(huì)協(xié)商選舉一個(gè)新的領(lǐng)頭sentinel,由這個(gè)sentinel進(jìn)行故障轉(zhuǎn)移操作。

如何分析redis中的高可用方案

確認(rèn)主服務(wù)器進(jìn)入客觀下線狀態(tài)后,會(huì)再次發(fā)送SENTINEL is-master-down-by-addr命令來(lái)選舉出領(lǐng)頭sentinel。

選舉規(guī)則

  • 監(jiān)視同一個(gè)主服務(wù)器的多個(gè)在線sentinel中每一個(gè)都可能成為領(lǐng)頭sentinel。

  • 每次進(jìn)行領(lǐng)頭sentinel選舉之后,無(wú)論選舉是否成功,所有sentinel的配置紀(jì)元(configuration epoch)的值都會(huì)自增一次。(配置紀(jì)元,其實(shí)就是一個(gè)計(jì)數(shù)器)

  • 在一個(gè)配置紀(jì)元里,所有sentinel都有將某個(gè)sentinel設(shè)置成局部sentinel的機(jī)會(huì),一旦設(shè)置在這個(gè)配置紀(jì)元里就不能再更改。

  • 所有發(fā)現(xiàn)主服務(wù)器客觀下線的sentinel都會(huì)要求其他sentinel將自己設(shè)置為局部領(lǐng)頭sentinel,也就是都會(huì)發(fā)送SENTINEL is-master-down-by-addr命令,嘗試讓其他sentinel將自己設(shè)置成局部領(lǐng)頭sentinel。

  • 當(dāng)一個(gè)sentinel向另一個(gè)sentinel發(fā)送SENTINEL is-master-down-by-addr命令時(shí),如果runid參數(shù)的值不是*,而是源sentinel的runid,就表示要目標(biāo)sentinel將自己設(shè)置成領(lǐng)頭sentinel。

  • sentinel設(shè)置局部領(lǐng)頭的規(guī)則是先到先得,第一個(gè)設(shè)置為局部領(lǐng)頭sentinel后,其他的請(qǐng)求都被拒絕。

  • 目標(biāo)sentinel在接收到一條SENTINEL is-master-down-by-addr命令后,將向源sentinel返回一個(gè)命令回復(fù)?;貜?fù)中l(wèi)eader_runid參數(shù)和leader_epoch參數(shù)分別記錄了目標(biāo)sentinel的局部領(lǐng)頭sentinel的runid和配置紀(jì)元。

  • 源sentinel接收到回復(fù)之后,會(huì)比較返回的配置紀(jì)元是否和自己的配置紀(jì)元相同,如果一樣再繼續(xù)比較返回的局部領(lǐng)頭sentinel的runid是否和自己的runid相同,如果一致就表示目標(biāo)sentinel將自己設(shè)置成了局部領(lǐng)頭sentinel。

  • 如果某個(gè)sentinel被半數(shù)以上的sentinel設(shè)置成了局部領(lǐng)頭sentinel,那么它就成為領(lǐng)頭sentinel。

  • 領(lǐng)頭sentinel需要半數(shù)以上支持,并且每個(gè)配置紀(jì)元內(nèi)只能設(shè)置一次,那么一個(gè)配置紀(jì)元里,只會(huì)出現(xiàn)一個(gè)領(lǐng)頭sentinel

  • 如果在一定時(shí)限內(nèi),每一個(gè)sentinel被選舉成領(lǐng)頭sentinel(沒(méi)人沒(méi)獲取半數(shù)以上選票),那么各個(gè)sentinel在一段時(shí)間之后再次選舉,直到選出領(lǐng)頭sentinel

故障轉(zhuǎn)移

故障轉(zhuǎn)移包含以下三個(gè)步驟:

  • 在已下線的主服務(wù)器下所有從服務(wù)器里,挑選出一個(gè)從服務(wù)器轉(zhuǎn)換成主服務(wù)器。

  • 讓已下線的主服務(wù)器屬下的所有從服務(wù)器改為復(fù)制新的主服務(wù)器。

  • 將已經(jīng)下線的主服務(wù)器設(shè)置為新服務(wù)器的從服務(wù)器,舊的主服務(wù)器重新上線后,它就成為新的主服務(wù)器的從服務(wù)器。

選出新的主服務(wù)器

已下線的主服務(wù)器下所有從服務(wù)器里,挑選出一個(gè)從服務(wù)器,向這個(gè)從服務(wù)器發(fā)送SLAVEOF no one命令,將這個(gè)從服務(wù)器轉(zhuǎn)換成主服務(wù)器。

挑選新主服務(wù)器的規(guī)則

領(lǐng)頭的sentinel會(huì)將已下線主服務(wù)器的所有從服務(wù)器保存到一個(gè)列表里面,然后對(duì)這個(gè)列表進(jìn)行過(guò)濾,挑選出新的主服務(wù)器。

  • 刪除列表中所有處于下線或者斷線狀態(tài)的從服務(wù)器。

  • 刪除列表中所有最近五秒內(nèi)沒(méi)有回復(fù)過(guò)領(lǐng)頭sentinel的INFO命令的從服務(wù)器

  • 刪除所有與已下線服務(wù)器連接斷開(kāi)超過(guò) dwon-after-milliseconds * 10毫秒的服務(wù)器

  • 然后根據(jù)從服務(wù)器的優(yōu)先級(jí),對(duì)列表中剩余的從服務(wù)器進(jìn)行排序,并選出其中優(yōu)先級(jí)最高的服務(wù)器。

  • 如果有多個(gè)相同最高優(yōu)先級(jí)的從服務(wù)器,那么就根據(jù)復(fù)制偏移量進(jìn)行排序,選出最大偏移量的從服務(wù)器(復(fù)制偏移量最大也代表它保存的數(shù)據(jù)最新)

  • 如果復(fù)制偏移量也相同,那么就根據(jù)runid進(jìn)行排序,選其中runid最小的從服務(wù)器

發(fā)送slaveof no one 命令之后,領(lǐng)頭sentinel會(huì)每秒一次向被升級(jí)的從服務(wù)器發(fā)送info命令(平常是每10秒一次),如果返回的回復(fù)role從原來(lái)的slave變成了master,那么領(lǐng)頭sentinel就知道從服務(wù)器已經(jīng)升級(jí)成主服務(wù)器了。

修改從服務(wù)器的復(fù)制目標(biāo)

通過(guò)SLAVEOF命令來(lái)使從服務(wù)器復(fù)制新的主服務(wù)器。當(dāng)sentinel監(jiān)測(cè)到舊的主服務(wù)器重新上線后,也會(huì)發(fā)送SLAVEOF命令使它成為新的主服務(wù)器的從服務(wù)器。

sentinel總結(jié)

sentinel其實(shí)就是一個(gè)監(jiān)控系統(tǒng),,而sentinel監(jiān)測(cè)到主服務(wù)器下線后,可以通過(guò)選舉機(jī)制選出一個(gè)領(lǐng)頭的sentinel,然后由這個(gè)領(lǐng)頭的sentinel將下線主服務(wù)器下的從服務(wù)器挑選一個(gè)切換成主服務(wù)器,而不用人工手動(dòng)切換。

集群

哨兵模式雖然做到了主從自動(dòng)切換,但是還是只有一臺(tái)主服務(wù)器進(jìn)行寫操作(當(dāng)然哨兵模式也可以監(jiān)視多個(gè)主服務(wù)器,但需要客戶端自己實(shí)現(xiàn)負(fù)載均衡)。官方也提供了自己的方式實(shí)現(xiàn)集群。

節(jié)點(diǎn)

每個(gè)redis服務(wù)實(shí)例就是一個(gè)節(jié)點(diǎn),多個(gè)連接的節(jié)點(diǎn)組成一個(gè)集群。

CLUSTER MEET

向另一個(gè)節(jié)點(diǎn)發(fā)送CLUSTER MEET命令,可以讓節(jié)點(diǎn)與目標(biāo)節(jié)點(diǎn)進(jìn)行握手,握手成功就能將該節(jié)點(diǎn)加入到當(dāng)前集群。

啟動(dòng)節(jié)點(diǎn)

redis服務(wù)器啟動(dòng)時(shí)會(huì)根據(jù)cluster-enabled配置選項(xiàng)是否為yes來(lái)決定是否開(kāi)啟服務(wù)器集群模式。

如何分析redis中的高可用方案

集群數(shù)據(jù)結(jié)構(gòu)

每個(gè)節(jié)點(diǎn)都會(huì)使用一個(gè)clusterNode結(jié)構(gòu)記錄自己的狀態(tài),并為集群中其他節(jié)點(diǎn)都創(chuàng)建一個(gè)相應(yīng)的clusterNode結(jié)構(gòu),記錄其他節(jié)點(diǎn)狀態(tài)。

typedef struct clusterNode {
    // 創(chuàng)建節(jié)點(diǎn)的時(shí)間
    mstime_t ctime; 
    // 節(jié)點(diǎn)的名稱
    char name[CLUSTER_NAMELEN];
    // 節(jié)點(diǎn)標(biāo)識(shí)
    // 各種不同的標(biāo)識(shí)值記錄節(jié)點(diǎn)的角色(比如主節(jié)點(diǎn)或從節(jié)點(diǎn))
    // 以及節(jié)點(diǎn)目前所處的狀態(tài)(在線或者下線)
    int flags;     
    // 節(jié)點(diǎn)當(dāng)前的配置紀(jì)元,用于實(shí)現(xiàn)故障轉(zhuǎn)移
    uint64_t configEpoch;
    // 節(jié)點(diǎn)的ip地址
    char ip[NET_IP_STR_LEN];  
    // 保存建立連接節(jié)點(diǎn)的有關(guān)信息
    clusterLink *link;          
    
    list *fail_reports;  
    // ...
} clusterNode;

clusterLink保存著連接節(jié)點(diǎn)所需的相關(guān)信息

typedef struct clusterLink {
    // ...
    // 連接的創(chuàng)建時(shí)間
    mstime_t ctime;           
    // 與這個(gè)連接相關(guān)聯(lián)的節(jié)點(diǎn),沒(méi)有就為null
    struct clusterNode *node;   
    // ...
} clusterLink;

每個(gè)節(jié)點(diǎn)還保存著一個(gè)clusterState結(jié)構(gòu),它記錄了在當(dāng)前節(jié)點(diǎn)視角下,集群目前所處的狀態(tài),例如集群在線還是下線,集群包含多少個(gè)節(jié)點(diǎn)等等。

typedef struct clusterState {
    // 指向當(dāng)前節(jié)點(diǎn)clusterNode的指針
    clusterNode *myself;  
    // 集群當(dāng)前的配置紀(jì)元,用于實(shí)現(xiàn)故障轉(zhuǎn)移
    uint64_t currentEpoch;
    // 集群當(dāng)前的狀態(tài),上線或者下線
    int state;           
    // 集群中至少處理一個(gè)槽的節(jié)點(diǎn)數(shù)量
    int size;      
    // 集群節(jié)點(diǎn)的名單(包括myself節(jié)點(diǎn))
    // 字典的鍵是節(jié)點(diǎn)的名字,字典的值為節(jié)點(diǎn)對(duì)應(yīng)的clusterNode結(jié)構(gòu)
    dict *nodes; 
} clusterState;

CLUSTER MEET 命令的實(shí)現(xiàn)

CLUSTER MEET

  • 節(jié)點(diǎn) A 會(huì)為節(jié)點(diǎn) B 創(chuàng)建一個(gè)clusterNode結(jié)構(gòu),并將該結(jié)構(gòu)添加到自己的clusterState.nodes 字典里面。

  • 之后,節(jié)點(diǎn) A 將根據(jù) CLUSTER MEET 命令給定的 IP 地址和端口號(hào),向節(jié)點(diǎn) B 發(fā)送一條 MEET 消息。

  • 如果一切順利,節(jié)點(diǎn) B 將接收到節(jié)點(diǎn) A 發(fā)送的 MEET 消息,節(jié)點(diǎn) B 會(huì)為節(jié)點(diǎn) A 創(chuàng)建一個(gè)clusterNode結(jié)構(gòu),并將該結(jié)構(gòu)添加到自己的clusterState.nodes字典里面。

  • 之后,節(jié)點(diǎn) B 將向節(jié)點(diǎn) A 返回一條 PONG 消息。

  • 如果一切順利,節(jié)點(diǎn) A 將接收到節(jié)點(diǎn) B 返回的 PONG 消息,通過(guò)這條 PONG 消息節(jié)點(diǎn) A 可以知道節(jié)點(diǎn) B 已經(jīng)成功地接收到了自己發(fā)送的 MEET 消息。

  • 之后,節(jié)點(diǎn) A 將向節(jié)點(diǎn) B 返回一條 PING 消息。

  • 如果一切順利,節(jié)點(diǎn)B將接收到節(jié)點(diǎn)A返回的PING消息,通過(guò)這條PING消息節(jié)點(diǎn)B知道節(jié)點(diǎn)A已經(jīng)成功接收到自己返回的PONG消息,握手完成。

如何分析redis中的高可用方案

槽指派

集群的整個(gè)數(shù)據(jù)庫(kù)被分為16384個(gè)槽,每個(gè)鍵都屬于16384個(gè)槽的其中一個(gè),集群中每個(gè)節(jié)點(diǎn)處理0個(gè)或16384個(gè)槽。當(dāng)所有的槽都有節(jié)點(diǎn)在處理時(shí),集群處于上線狀態(tài),否則就是下線狀態(tài)。

CLUSTER ADDSLOTS

CLUSTER ADDSLOTS ...
通過(guò)CLUSTER ADDSLOTS命令可以將指定槽指派給當(dāng)前節(jié)點(diǎn)負(fù)責(zé),例如:CLUSTER ADDSLOTS 0 1 2 3 4 可以將0至4的槽指派給當(dāng)前節(jié)點(diǎn)

記錄節(jié)點(diǎn)的槽指派信息

clusterNode結(jié)構(gòu)的slots屬性和numslot屬性記錄了節(jié)點(diǎn)負(fù)責(zé)處理哪些槽:

typedef struct clusterNode {
         
    unsigned char slots[CLUSTER_SLOTS/8];
    
    int numslots;
    // ...
} clusterNode;

slots:是一個(gè)二進(jìn)制數(shù)組,一共包含16384個(gè)二進(jìn)制位。當(dāng)二進(jìn)制位的值是1,代表節(jié)點(diǎn)負(fù)責(zé)處理該槽,如果是0,代表節(jié)點(diǎn)不處理該槽numslots:numslots屬性則記錄節(jié)點(diǎn)負(fù)責(zé)處理槽的數(shù)量,也就是slots中值為1的二進(jìn)制位的數(shù)量。

傳播節(jié)點(diǎn)的槽指派信息

節(jié)點(diǎn)除了會(huì)將自己負(fù)責(zé)的槽記錄在clusterNode中,還會(huì)將slots數(shù)組發(fā)送給集群中的其他節(jié)點(diǎn),以此告知其他節(jié)點(diǎn)自己目前負(fù)責(zé)處理哪些槽。

typedef struct clusterState {
    clusterNode *slots[CLUSTER_SLOTS];
} clusterState;

slots包含16384個(gè)項(xiàng),每一個(gè)數(shù)組項(xiàng)都是指向clusterNode的指針,表示被指派給該節(jié)點(diǎn),如果未指派給任何節(jié)點(diǎn),那么指針指向NULL。

CLUSTER ADDSLOTS命令的實(shí)現(xiàn)

如何分析redis中的高可用方案

在集群中執(zhí)行命令

客戶端向節(jié)點(diǎn)發(fā)送與數(shù)據(jù)庫(kù)有關(guān)的命令時(shí),接收命令的節(jié)點(diǎn)會(huì)計(jì)算出命令要處理的數(shù)據(jù)庫(kù)鍵屬于哪個(gè)槽,并檢查該槽是否指派給了自己。
如果指派給了自己,那么該節(jié)點(diǎn)直接執(zhí)行該命令。如果沒(méi)有,那么該節(jié)點(diǎn)會(huì)向客戶端返回一個(gè)MOCED的錯(cuò)誤,指引客戶端轉(zhuǎn)向正確的節(jié)點(diǎn),并再次發(fā)送執(zhí)行的命令。

如何分析redis中的高可用方案

計(jì)算鍵屬于那個(gè)槽

如何分析redis中的高可用方案

CRC16(key)是計(jì)算出鍵key的CRC16的校驗(yàn)和,而 & 16383就是取余,算出0-16383之間的整數(shù)作為鍵的槽號(hào)。

判斷槽是否由當(dāng)前節(jié)點(diǎn)負(fù)責(zé)處理

計(jì)算出鍵所屬的槽號(hào)i后,節(jié)點(diǎn)就能判斷該槽號(hào)是否由自己處理。
如果clusterState.slots[i]等于如果clusterState.myself,那么由自己負(fù)責(zé)該節(jié)點(diǎn)可以直接執(zhí)行命令。
如果不相等,那么可以獲取clusterState.slots[i]指向如果clusterNode的ip和端口,向客戶端返回MOVED錯(cuò)誤,指引客戶端轉(zhuǎn)向負(fù)責(zé)該槽的節(jié)點(diǎn)。

集群模式下不會(huì)打印MOVED錯(cuò)誤,而是直接自動(dòng)轉(zhuǎn)向。

重新分片

redis集群重新分配可以將任意數(shù)量已經(jīng)指派給某個(gè)節(jié)點(diǎn)的槽改為指派給另一個(gè)節(jié)點(diǎn),相關(guān)槽所屬的鍵值對(duì)也會(huì)從源節(jié)點(diǎn)移動(dòng)到目標(biāo)節(jié)點(diǎn)。
重新分片操作是在線進(jìn)行的,在重新分片的過(guò)程中,集群不用下線,源節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn)都可以繼續(xù)處理命令請(qǐng)求。 redis集群的重新分片操作是由redis-trib負(fù)責(zé)執(zhí)行。重新分片執(zhí)行步驟如下:

  • redis-trib對(duì)目標(biāo)節(jié)點(diǎn)發(fā)送CLUSTER SETSLOT IMPORTING 命令,讓目標(biāo)節(jié)點(diǎn)準(zhǔn)備好從源節(jié)點(diǎn)導(dǎo)入槽slot的鍵值對(duì)。

  • redis-trib對(duì)源節(jié)點(diǎn)發(fā)送CLUSTER SETSLOT MIGRTING 命令,讓源節(jié)點(diǎn)準(zhǔn)備好將屬于槽slot的鍵值對(duì)遷移至目標(biāo)節(jié)點(diǎn)。

  • redis-trib向源節(jié)點(diǎn)發(fā)送CLUSTER GETKEYSINSLOT 命令,獲取最多count個(gè)屬于槽的鍵值對(duì)的鍵名稱。

  • 對(duì)于步驟3獲取的每個(gè)鍵名,redis-trib都向源節(jié)點(diǎn)發(fā)送一個(gè)MIGRTING 0 命令,將被選中的鍵值對(duì)從源節(jié)點(diǎn)遷移至目標(biāo)節(jié)點(diǎn)。

  • 重復(fù)執(zhí)行步驟3和步驟4,直到源節(jié)點(diǎn)保存的所以屬于槽slot的鍵值對(duì)都被遷移至目標(biāo)節(jié)點(diǎn)。

  • redis-trib向集群中任何一個(gè)節(jié)點(diǎn)發(fā)送CLUSTER SETSLOT NODE 命令,將槽指派給目標(biāo)節(jié)點(diǎn)。這一信息最終會(huì)通過(guò)消息發(fā)送至整個(gè)集群。

如何分析redis中的高可用方案

CLUSTER SETSLOT IMPORTING 命令實(shí)現(xiàn)

typedef struct clusterState {
    // ...
    clusterNode *importing_slots_from[CLUSTER_SLOTS];

} clusterState;

importing_slots_from記錄了當(dāng)前節(jié)點(diǎn)正在從其他節(jié)點(diǎn)導(dǎo)入的槽。importing_slots_from[i]不為null,則指向CLUSTER SETSLOT IMPORTING 命令,所代表的clusterNode結(jié)構(gòu)。

CLUSTER SETSLOT MIGRTING 命令實(shí)現(xiàn)

typedef struct clusterState {
    // ...
    clusterNode *migrating_slots_to[CLUSTER_SLOTS];

} clusterState;

migrating_slots_to記錄了當(dāng)前節(jié)點(diǎn)正在遷移至其他節(jié)點(diǎn)的槽。migrating_slots_to[i]不為null,則指向遷移至目標(biāo)節(jié)點(diǎn)所代表的clusterNode結(jié)構(gòu)。

ASK錯(cuò)誤

在重新分片期間,源節(jié)點(diǎn)向目標(biāo)節(jié)點(diǎn)遷移槽的過(guò)程中,可能屬于這個(gè)槽的一部分鍵值對(duì)一部分保存在源節(jié)點(diǎn)當(dāng)中,而另一部分保存在目標(biāo)節(jié)點(diǎn)當(dāng)中。
客戶端向源節(jié)點(diǎn)發(fā)送一個(gè)與數(shù)據(jù)庫(kù)鍵有關(guān)的命令,恰好這個(gè)槽正在被遷移。
源節(jié)點(diǎn)現(xiàn)在自己的數(shù)據(jù)庫(kù)中查找指定的鍵,如果找到,直接執(zhí)行。
如果沒(méi)有找到,節(jié)點(diǎn)會(huì)檢查migrating_slots_to[i]查看鍵是否正在遷移,如果在遷移就返回一個(gè)ask錯(cuò)誤,引導(dǎo)客戶端轉(zhuǎn)向目標(biāo)節(jié)點(diǎn)。

ASKING

客戶端收到ask錯(cuò)誤之后,會(huì)先執(zhí)行ASKING命令,再向目標(biāo)節(jié)點(diǎn)發(fā)送命令。ASKING命令就是打開(kāi)發(fā)送該命令的客戶端的REDIS_ASKING標(biāo)識(shí)。一般來(lái)說(shuō)客戶端發(fā)送的鍵如果不屬于自己負(fù)責(zé)會(huì)返回MOVED錯(cuò)誤(槽只遷移部分,這時(shí)槽還不屬于目標(biāo)節(jié)點(diǎn)負(fù)責(zé)),但還會(huì)檢查importing_slots_from[i],如果顯示節(jié)點(diǎn)正在導(dǎo)入槽i,并且發(fā)送命令的客戶端帶有REDIS_ASKING標(biāo)識(shí),那么它就會(huì)破例執(zhí)行一次該命令。

如何分析redis中的高可用方案

集群的故障轉(zhuǎn)移

集群的故障轉(zhuǎn)移效果和哨兵模式類似,也是將從節(jié)點(diǎn)升級(jí)成主節(jié)點(diǎn)。舊的主節(jié)點(diǎn)重新上線后將會(huì)成為新主節(jié)點(diǎn)的從節(jié)點(diǎn)。

故障檢測(cè)

集群中每個(gè)節(jié)點(diǎn)會(huì)定期的向集群中其他節(jié)點(diǎn)發(fā)送PING消息,檢測(cè)對(duì)方是否在線,如果指定時(shí)間內(nèi)沒(méi)有收到PONG消息,那么就將該節(jié)點(diǎn)標(biāo)記為疑似下線。clusterState.nodes字典中找到該節(jié)點(diǎn)的clusterNode結(jié)構(gòu),將flags屬性修改成REDIS_NODE_PFAIL標(biāo)識(shí)。
集群中各個(gè)節(jié)點(diǎn)會(huì)互相發(fā)送消息來(lái)交換集群中各個(gè)節(jié)點(diǎn)的狀態(tài),例如:主節(jié)點(diǎn)A得知主節(jié)點(diǎn)B認(rèn)為主節(jié)點(diǎn)C進(jìn)入了疑似下線狀態(tài),主節(jié)點(diǎn)A會(huì)在clusterState.nodes字典中找到節(jié)點(diǎn)C的clusterNode結(jié)構(gòu),并將主節(jié)點(diǎn)B的下線報(bào)告添加到clusterNode結(jié)構(gòu)的fail_reports鏈表當(dāng)中。
每一個(gè)下線報(bào)告由一個(gè)clusterNodeFailReport結(jié)構(gòu)表示

typedef struct clusterNodeFailReport {
    struct clusterNode *node; 
    // 最后一次收到下線報(bào)告的時(shí)間
    mstime_t time;            
} clusterNodeFailReport;

如果一個(gè)集群當(dāng)中,半數(shù)以上負(fù)責(zé)處理槽的主節(jié)點(diǎn)都將某個(gè)主節(jié)點(diǎn)X報(bào)告為疑似下線。那么這個(gè)主節(jié)點(diǎn)X將被標(biāo)記為已下線。將主節(jié)點(diǎn)X標(biāo)記成已下線的節(jié)點(diǎn)會(huì)向集群廣播一條關(guān)于主節(jié)點(diǎn)X的FAIL消息。所有收到這條FAIL消息的節(jié)點(diǎn)都會(huì)將主節(jié)點(diǎn)X標(biāo)記成已下線。

故障轉(zhuǎn)移

當(dāng)一個(gè)從節(jié)點(diǎn)發(fā)現(xiàn)自己正在復(fù)制的主節(jié)點(diǎn)進(jìn)入了已下線狀態(tài),從節(jié)點(diǎn)將開(kāi)始對(duì)下線主節(jié)點(diǎn)進(jìn)行故障轉(zhuǎn)移。

  • 復(fù)制下線主節(jié)點(diǎn)的所有從節(jié)點(diǎn),會(huì)有一個(gè)主節(jié)點(diǎn)被選中。

  • 被選中的從節(jié)點(diǎn)會(huì)執(zhí)行SLAVEOF no one 命令,成為新的主節(jié)點(diǎn)。

  • 新的主節(jié)點(diǎn)會(huì)撤銷所有對(duì)已下線主節(jié)點(diǎn)的槽指派,并將這些槽全部指派給自己。

  • 新的主節(jié)點(diǎn)向集群廣播一條PONG消息,這條PONG消息可以讓集群中的其他節(jié)點(diǎn)立即知道這個(gè)節(jié)點(diǎn)已經(jīng)由從節(jié)點(diǎn)變成主節(jié)點(diǎn)。這個(gè)主節(jié)點(diǎn)已經(jīng)接管了已下線節(jié)點(diǎn)負(fù)責(zé)處理的槽。

  • 新的主節(jié)點(diǎn)開(kāi)始接收和自己負(fù)責(zé)處理的槽有關(guān)的命令請(qǐng)求,故障轉(zhuǎn)移完成。

選舉新的主節(jié)點(diǎn)

新的主節(jié)點(diǎn)通過(guò)選舉產(chǎn)生

  • 集群的配置紀(jì)元是一個(gè)自增計(jì)數(shù)器,它的初始值為0。

  • 當(dāng)集群的某個(gè)節(jié)點(diǎn)開(kāi)始一次故障轉(zhuǎn)移操作,集群的配置紀(jì)元的值加1。

  • 對(duì)于每個(gè)配置紀(jì)元,集群里每個(gè)負(fù)責(zé)處理槽的主節(jié)點(diǎn)都有一次投票的機(jī)會(huì),第一個(gè)想主節(jié)點(diǎn)要求投票的從節(jié)點(diǎn)將獲得主節(jié)點(diǎn)的投票。

  • 當(dāng)從節(jié)點(diǎn)發(fā)現(xiàn)自己正在復(fù)制的主節(jié)點(diǎn)進(jìn)入已下線狀態(tài)時(shí),從節(jié)點(diǎn)會(huì)向集群廣播一條CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST消息,要求所有收到這條消息,并具有投票權(quán)的主節(jié)點(diǎn)向這個(gè)從節(jié)點(diǎn)投票。

  • 如果一個(gè)主節(jié)點(diǎn)具有投票權(quán)(它正在負(fù)責(zé)處理槽),并且這個(gè)主節(jié)點(diǎn)尚未投票給其他從節(jié)點(diǎn),那么主節(jié)點(diǎn)將向要求投票的從節(jié)點(diǎn)返回一條CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示這個(gè)主節(jié)點(diǎn)支持從節(jié)點(diǎn)成為新的主節(jié)點(diǎn)。

  • 每個(gè)參與選舉的從節(jié)點(diǎn)都會(huì)接收CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,并根據(jù)自己收到了多少條這種消息來(lái)統(tǒng)計(jì)自己獲得了多少主節(jié)點(diǎn)的支持。

  • 如果集群里有 N 個(gè)具有投票權(quán)的主節(jié)點(diǎn),那么當(dāng)一個(gè)從節(jié)點(diǎn)收集到大于等于 N / 2 + l 張支持票時(shí),這個(gè)從節(jié)點(diǎn)就會(huì)當(dāng)選為新的主節(jié)點(diǎn)。

  • 因?yàn)樵诿恳粋€(gè)配置紀(jì)元里面,每個(gè)具有投票權(quán)的主節(jié)點(diǎn)只能投一次票,所以如果有 N 個(gè)主節(jié)點(diǎn)進(jìn)行投票,那么具有大于等于 N / 2 + l 張支持票的從節(jié)點(diǎn)只會(huì)有一個(gè),這確保了新的主節(jié)點(diǎn)只會(huì)有一個(gè)。

  • 如果在一個(gè)配置紀(jì)元里面沒(méi)有從節(jié)點(diǎn)能收集到足夠多的支持票,那么集群進(jìn)人一個(gè)新的配置紀(jì)元,并再次進(jìn)行選舉,直到選出新的主節(jié)點(diǎn)為止。

主節(jié)點(diǎn)選舉的過(guò)程和選舉領(lǐng)頭sentinel的過(guò)程非常相似。

數(shù)據(jù)丟失

主從復(fù)制數(shù)據(jù)丟失

主從復(fù)制之間是異步執(zhí)行的,有可能master的部分?jǐn)?shù)據(jù)還沒(méi)來(lái)得及同步到從數(shù)據(jù)庫(kù),然后master就掛了,這時(shí)這部分未同步的數(shù)據(jù)就丟失了。

腦裂

腦裂就是說(shuō),某個(gè)master所在機(jī)器突然脫離了正常的網(wǎng)絡(luò),跟其他slave機(jī)器不能連接,但是實(shí)際上master還運(yùn)行著。此時(shí)哨兵可能就會(huì)認(rèn)為master 宕機(jī)了,然后開(kāi)啟選舉,將其他slave切換成了master,這個(gè)時(shí)候,集群里面就會(huì)有2個(gè)master,也就是所謂的腦裂。
此時(shí)雖然某個(gè)slave被切換成了master,但是可能client還沒(méi)來(lái)得及切換到新的master,還繼續(xù)向舊master的寫數(shù)據(jù)。
master再次恢復(fù)的時(shí)候,會(huì)被作為一個(gè)slave掛到新的master上去,自己的數(shù)據(jù)將會(huì)清空,重新從新的master復(fù)制數(shù)據(jù),導(dǎo)致數(shù)據(jù)丟失。

減少數(shù)據(jù)丟失的配置

min-slaves-to-writ 1
min-slaves-max-lag 10

上述配置表示,如果至少有1個(gè)從服務(wù)器超過(guò)10秒沒(méi)有給自己ack消息,那么master不再執(zhí)行寫請(qǐng)求。

主從數(shù)據(jù)不一致

當(dāng)從數(shù)據(jù)庫(kù)因?yàn)榫W(wǎng)絡(luò)原因或者執(zhí)行復(fù)雜度高命令阻塞導(dǎo)致滯后執(zhí)行同步命令,導(dǎo)致數(shù)據(jù)同步延遲,造成了主從數(shù)據(jù)庫(kù)不一致。

感謝大家的閱讀,以上就是“如何分析redis中的高可用方案”的全部?jī)?nèi)容了,學(xué)會(huì)的朋友趕緊操作起來(lái)吧。相信創(chuàng)新互聯(lián)小編一定會(huì)給大家?guī)?lái)更優(yōu)質(zhì)的文章。謝謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!


網(wǎng)站題目:如何分析redis中的高可用方案
文章出自:http://weahome.cn/article/jiodih.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部