Redis【二】Redis哨兵模式原理

Redis【一】Redis主從復(fù)制原理
Redis【二】Redis哨兵模式原理

Redis的高可用實(shí)現(xiàn)方案現(xiàn)在官方的有redis-sentinel redis-cluster都是直連(非代理模式)

  • redis-sentinel 是主從模式晃琳,同一時(shí)間只有一個(gè)master實(shí)例可以寫醒第,其他從節(jié)點(diǎn)是只讀的羽嫡,如果master節(jié)點(diǎn)宕機(jī),redis-sentinel之間會(huì)通過(guò)raft協(xié)議選舉出一個(gè)負(fù)責(zé)故障遷移的主redis-sentinel妻枕,這個(gè)主redis-sentinel負(fù)責(zé)選擇一個(gè)slave redis節(jié)點(diǎn)作為master,設(shè)置其他slave的master為這個(gè)新的master
  • redis-cluster 是集群粘驰、分片加主從模式

1. redis-sentinel拓?fù)浣Y(jié)構(gòu)圖

redis-sentinel拓?fù)浣Y(jié)構(gòu)圖

如上圖所示屡谐,sentinel是在正常的redis主從配置的基礎(chǔ)上,通過(guò)監(jiān)控redis節(jié)點(diǎn)的健康狀況蝌数,實(shí)現(xiàn)自動(dòng)化的主從切換愕掏。如果master節(jié)點(diǎn)掛掉了,sentinel會(huì)及時(shí)的發(fā)現(xiàn)顶伞,自動(dòng)化的設(shè)置新的master饵撑,并把其他的slave指向新的master剑梳。
Sentinel本質(zhì)上也是一個(gè)Redis節(jié)點(diǎn),但是僅支持部分命令

redis-sentinel基本配置
port 26379
daemonize yes
logfile "26379.log"
dir /opt/soft/redis/data
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000

其中最主要的配置是sentinel monitor mymaster 127.0.0.1 6379 2滑潘,格式為sentinel monitor {masterMame} {masterIP} {masterPort} {quorum}

  • masterName 是當(dāng)sentinel同時(shí)監(jiān)控多套redis主從的時(shí)候區(qū)分不同的主從的垢乙。
  • masterIP masterPort 是監(jiān)控的Redis實(shí)例中master的IP和port,sentinel通過(guò)該master可以獲取其他所有的slave實(shí)例和sentinel節(jié)點(diǎn)
  • quorum 用于故障發(fā)現(xiàn)和判定语卤,如果quorum=2追逮,則代表至少2個(gè)Sentinel節(jié)點(diǎn)認(rèn)為主節(jié)點(diǎn)不可達(dá),這個(gè)不可達(dá)的判定才是客觀的粱侣。一般設(shè)置為 {sentinel實(shí)例個(gè)數(shù)}/2 + 1

redis-sentinel的3個(gè)定時(shí)任務(wù)

  1. 每隔10秒羊壹,向Redis master和slave節(jié)點(diǎn)發(fā)送info命令獲取最新的拓?fù)浣Y(jié)構(gòu)
    通過(guò)解析info命令中的Replication信息,sentinel就可以獲取到所有的最新的master和slave節(jié)點(diǎn)齐婴,這也是為什么sentinel配而不需要顯示的配置slave節(jié)點(diǎn)油猫。
    定期向Redis master和slave節(jié)點(diǎn)發(fā)送info命令
  1. 每隔2秒,向master節(jié)點(diǎn)的sentinel:hello 頻道上publish該sentinel節(jié)點(diǎn)對(duì)于主節(jié)點(diǎn)的判斷以及當(dāng)前sentinel節(jié)點(diǎn)的信息柠偶,同時(shí)每個(gè)sentinel節(jié)點(diǎn)也會(huì)訂閱該頻道情妖,來(lái)了解其他sentinel節(jié)點(diǎn)以及它們對(duì)主節(jié)點(diǎn)的判斷。 所以這個(gè)定時(shí)任務(wù)可以完成以下兩個(gè)工作:
    1. sentinel節(jié)點(diǎn)之間互相發(fā)現(xiàn)诱担,每個(gè)sentinel節(jié)點(diǎn)上只配置了redis master節(jié)點(diǎn)毡证, 通過(guò)這種方式,sentinel節(jié)點(diǎn)之間就可以實(shí)現(xiàn)互相發(fā)現(xiàn)蔫仙。來(lái)實(shí)現(xiàn)后續(xù)的sentinel節(jié)點(diǎn)之間的互相通信料睛、選舉操作
    2. sentinel節(jié)點(diǎn)之間交換主節(jié)點(diǎn)狀態(tài),作為后面客觀下線以及領(lǐng)導(dǎo)者選舉的依據(jù)摇邦。
      sentinel節(jié)點(diǎn)publish的消息格式如下:
      {sentinel節(jié)點(diǎn)IP} {sentinel節(jié)點(diǎn)端口} {sentinel節(jié)點(diǎn)runId} {sentinel節(jié)點(diǎn)配置版本} {主節(jié)點(diǎn)名字} {主節(jié)點(diǎn)IP} {主節(jié)點(diǎn)Port} {主節(jié)點(diǎn)配置版本}恤煞,示例:

      10.xx.xx.xx,26379,811ee2bc21cfc21e6aea0da3ed90f80deeod91kc,1530,mymaster,10.xx.xx.xx,6379,1530
      每隔2秒向master publish當(dāng)前sentinel的狀態(tài)
  1. 每隔1秒,會(huì)向master施籍、slave節(jié)點(diǎn)居扒、其余sentinel節(jié)點(diǎn)發(fā)送ping命令做一次心跳檢測(cè),來(lái)確認(rèn)這些節(jié)點(diǎn)當(dāng)前是否可達(dá)丑慎。sentinel就是基于這個(gè)ping命令來(lái)決定redis節(jié)點(diǎn)和sentinel節(jié)點(diǎn)是否活著喜喂。


    每隔1秒向master、slave節(jié)點(diǎn)以及其他sentinel節(jié)點(diǎn)發(fā)送ping

2. redis-sentinel故障遷移流程

主觀下線和客觀下線

  1. 主觀下線
    上面介紹的sentinel的第三個(gè)定時(shí)任務(wù)每秒對(duì)其他的節(jié)點(diǎn)ping一次竿裂,如果這個(gè)節(jié)點(diǎn)超過(guò)down-after-milliseconds沒(méi)有有效的回復(fù)玉吁,該sentinel節(jié)點(diǎn)就會(huì)對(duì)這個(gè)節(jié)點(diǎn)做失敗判定,這個(gè)行為是主觀下線腻异。由此可見主觀下線只是單個(gè)sentinel的判定行為诈茧,在分布式環(huán)境中,肯定不能只靠一個(gè)節(jié)點(diǎn)的判斷捂掰。
  2. 客觀下線
    當(dāng)sentinel主觀下線的節(jié)點(diǎn)是master時(shí)敢会,該sentinel就會(huì)向其他sentinel節(jié)點(diǎn)發(fā)送sentinel is-master-down-by-addr命令詢問(wèn)對(duì)主節(jié)點(diǎn)的判斷曾沈,當(dāng)超過(guò){quorum}個(gè)數(shù)sentinel節(jié)點(diǎn)認(rèn)為主節(jié)點(diǎn)確實(shí)有問(wèn)題,這時(shí)該sentinel會(huì)做出客觀下線的決定鸥昏。

leader選舉

sentinel做出客觀下線的決定之后并不會(huì)立即進(jìn)行故障轉(zhuǎn)移塞俱,而是要在sentinel之間選舉出一個(gè)leader,由leader來(lái)執(zhí)行具體的故障轉(zhuǎn)移工作吏垮。
其實(shí)在上面的客觀下線中障涯,sentinel發(fā)送sentinel is-master-down-by-addr命令的時(shí)候就已經(jīng)包含了leader選舉的一些信息。
sentinel is-master-down-by-addr {故障masterIP} {故障masterPort} {downState} {leader_runid}

  • downState:1是下線膳汪、0是在線
  • leader_runid:如果為*唯蝶,表示返回結(jié)果只是用來(lái)表示主節(jié)點(diǎn)是否可達(dá),當(dāng)leader_runid等于具體的runid時(shí)遗嗽,就代表目標(biāo)節(jié)點(diǎn)同意runid稱為leader

故障轉(zhuǎn)移

上面選擇出一個(gè)sentinel作為leader之后粘我,該leader就會(huì)開始操作故障轉(zhuǎn)移,具體步驟如下:

  1. 從所有slave中選出一個(gè)slave作為新的master痹换,選擇方法如下圖所示:


    選取從節(jié)點(diǎn)過(guò)程
  2. sentinel leader對(duì)選擇出來(lái)的master執(zhí)行slaveof no one命令讓其成為真正的master
  3. sentinel leader對(duì)其他slave發(fā)送命令征字,讓它們成為新master的slave,新的slave的復(fù)制規(guī)則與parallel-syncs(同時(shí)允許多少個(gè)slave執(zhí)行sync操作)的配置有關(guān)系
  4. sentinel leader將原來(lái)的master更新為slave娇豫,并保持對(duì)其監(jiān)控匙姜,當(dāng)它恢復(fù)后命令它去復(fù)制新的master

3. redis-sentinel客戶端邏輯

實(shí)現(xiàn)一個(gè)Redis Sentinel客戶端的基本步驟如下:

  1. 遍歷sentinel節(jié)點(diǎn)集合獲取一個(gè)可用的sentinel節(jié)點(diǎn), 對(duì)sentinel節(jié)點(diǎn)調(diào)用sentinel get-master-addr-by-name master這個(gè)API來(lái)獲取對(duì)應(yīng)主節(jié)點(diǎn)的相關(guān)信息
  2. sentinel客戶端訂閱sentinel的swtich-master事件冯痢,如果master有變更氮昧,需要更新redis連接。
  3. sentinel客戶端如果是維護(hù)的連接池浦楣,在獲取連接的時(shí)候要檢查該連接是否與最新的master是一致的郭计,如果不一致就要銷毀該連接,重新獲取椒振。
redis.clients.jedis.JedisSentinelPool

private HostAndPort initSentinels(Set<String> sentinels, final String masterName) {

    HostAndPort master = null;
    boolean sentinelAvailable = false;

    log.info("Trying to find master from available Sentinels...");
    // 遍歷sentinel節(jié)點(diǎn),嘗試獲取master節(jié)點(diǎn)
    for (String sentinel : sentinels) {
      final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));

      log.fine("Connecting to Sentinel " + hap);

      Jedis jedis = null;
      try {
        jedis = new Jedis(hap.getHost(), hap.getPort());
        // 從sentinel獲取master節(jié)點(diǎn)
        List<String> masterAddr = jedis.sentinelGetMasterAddrByName(masterName);

        // connected to sentinel...
        sentinelAvailable = true;

        if (masterAddr == null || masterAddr.size() != 2) {
          log.warning("Can not get master addr, master name: " + masterName + ". Sentinel: " + hap
              + ".");
          continue;
        }

        master = toHostAndPort(masterAddr);
        log.fine("Found Redis master at " + master);
        break;
      } catch (JedisException e) {
        ...
      } finally {
        if (jedis != null) {
          jedis.close();
        }
      }
    }

    ...

    for (String sentinel : sentinels) {
      final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));

      // MasterListener會(huì)訂閱sentinel節(jié)點(diǎn)的swatich-master渠道梧乘,如果master有變更澎迎,就會(huì)執(zhí)行initPool操作
      MasterListener masterListener = new MasterListener(masterName, hap.getHost(), hap.getPort());
      // whether MasterListener threads are alive or not, process can be stopped
      masterListener.setDaemon(true);
      masterListeners.add(masterListener);
      masterListener.start();
    }

    return master;
  }
// 根據(jù)最新的master更新線程池中的jedis連接
private void initPool(HostAndPort master) {
    if (!master.equals(currentHostMaster)) {
      currentHostMaster = master;
      if (factory == null) {
        factory = new JedisFactory(master.getHost(), master.getPort(), connectionTimeout,
            soTimeout, password, database, clientName);
        initPool(poolConfig, factory);
      } else {
        factory.setHostAndPort(currentHostMaster);

        // clear操作只會(huì)destroy idle狀態(tài)的jedis連接,不會(huì)釋放正在使用的jedis連接选调。所以需要在getResource的時(shí)候再次做檢查
        internalPool.clear();
      }

      log.info("Created JedisPool to master at " + master);
    }
  }
// 從連接池中獲取一個(gè)連接
public Jedis getResource() {
    while (true) {
      Jedis jedis = super.getResource();
      jedis.setDataSource(this);

      // get a reference because it can change concurrently
      final HostAndPort master = currentHostMaster;
      final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient()
          .getPort());
       // 檢查當(dāng)前連接的master與最新的master是否相同夹供,如果相同就可以直接返回
      if (master.equals(connection)) {
        return jedis;
      } else {
        // 如果master不正確,就把該jedis連接返回給連接池仁堪,重新嘗試從連接池獲取
        returnBrokenResource(jedis);
      }
    }
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哮洽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弦聂,更是在濱河造成了極大的恐慌鸟辅,老刑警劉巖氛什,帶你破解...
    沈念sama閱讀 212,185評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異匪凉,居然都是意外死亡枪眉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門再层,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贸铜,“玉大人,你說(shuō)我怎么就攤上這事聂受≥锴兀” “怎么了?”我有些...
    開封第一講書人閱讀 157,684評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蛋济,是天一觀的道長(zhǎng)棍鳖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)瘫俊,這世上最難降的妖魔是什么鹊杖? 我笑而不...
    開封第一講書人閱讀 56,564評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮扛芽,結(jié)果婚禮上骂蓖,老公的妹妹穿的比我還像新娘。我一直安慰自己川尖,他們只是感情好登下,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叮喳,像睡著了一般被芳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馍悟,一...
    開封第一講書人閱讀 49,874評(píng)論 1 290
  • 那天畔濒,我揣著相機(jī)與錄音,去河邊找鬼锣咒。 笑死侵状,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毅整。 我是一名探鬼主播趣兄,決...
    沈念sama閱讀 39,025評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悼嫉!你這毒婦竟也來(lái)了艇潭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,761評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹋凝,沒(méi)想到半個(gè)月后鲁纠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,217評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仙粱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評(píng)論 2 327
  • 正文 我和宋清朗相戀三年房交,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伐割。...
    茶點(diǎn)故事閱讀 38,694評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡候味,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隔心,到底是詐尸還是另有隱情白群,我是刑警寧澤,帶...
    沈念sama閱讀 34,351評(píng)論 4 332
  • 正文 年R本政府宣布硬霍,位于F島的核電站帜慢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏唯卖。R本人自食惡果不足惜粱玲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拜轨。 院中可真熱鬧抽减,春花似錦、人聲如沸橄碾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,778評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)法牲。三九已至史汗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拒垃,已是汗流浹背停撞。 一陣腳步聲響...
    開封第一講書人閱讀 32,007評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悼瓮,地道東北人戈毒。 一個(gè)月前我還...
    沈念sama閱讀 46,427評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谤牡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子姥宝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 1. Redis Sentinel 簡(jiǎn)介 redis 的主從復(fù)制模式下翅萤,一旦主節(jié)點(diǎn)由于故障不能提供服務(wù),需要人工將...
    CoderJed閱讀 2,771評(píng)論 0 11
  • Redis Sentinel 介紹與部署 1. Sentinel介紹 1.1 主從復(fù)制的問(wèn)題 Redis主從復(fù)制可...
    56c60a7e3495閱讀 1,008評(píng)論 0 1
  • 1.概述 Sentinel(哨崗、哨兵)是Redis高可用性的解決方案:由一個(gè)或多個(gè)Sentinel實(shí)例組成的Se...
    孤塵F閱讀 815評(píng)論 0 0
  • 故障轉(zhuǎn)移 接著上章構(gòu)建的sentinel網(wǎng)絡(luò)構(gòu)建后分析sentinel的故障轉(zhuǎn)移套么。sentinel本身做為redi...
    ben1988閱讀 3,357評(píng)論 1 0
  • “花有重開日培己,人物再少年",總是在反反復(fù)復(fù)的中提醒自己胚泌。即使不是每一朵花開省咨,都會(huì)有結(jié)果,我也相信只要付出努力了玷室,...
    小雅竹閱讀 257評(píng)論 0 0