高可用性的redis服務(wù) (sentinel)

1. 高可用性

redis sentinel 官方文檔
redis sentinel 中文文檔

前面說到使用主從備份的方式可以保證數(shù)據(jù)的安全性,當(dāng)主節(jié)點(diǎn)掛了的時候,從節(jié)點(diǎn)可以頂上作為主節(jié)點(diǎn)。但是需要手動去切換,這個過程需要認(rèn)為干預(yù)。那么有沒有一種由程序自己監(jiān)控主節(jié)點(diǎn)狀態(tài)并在主節(jié)點(diǎn)掛了的時候自己選擇一個從節(jié)點(diǎn)的方案呢?答案肯定是有的。redis sentinel(哨兵)。

從宏觀上講,redis sentinel 可以做到的如下幾點(diǎn):

  1. Monitoring 監(jiān)控,可以監(jiān)控master和slaves實(shí)例是不是按照預(yù)期的執(zhí)行
  2. Notification 通知,當(dāng)被監(jiān)控的redis的實(shí)例出現(xiàn)問題。能夠通知系統(tǒng)管理員或者其他應(yīng)用程序
  3. Automatic failover 自動災(zāi)難遷移,當(dāng)master出現(xiàn)故障的時候,sentinel會開啟一個選舉流程,選擇一個合適slave升級為master
  4. Configuration provider 幫客戶端發(fā)現(xiàn)redis服務(wù)??蛻舳诉B接sentinel,sentinel拿到當(dāng)前redis master address 給客戶端提供服務(wù)。當(dāng)redis master 掛了的時候,找到一個新的service address。

sentinel具有分布式的特性,他被設(shè)計成多個Sentinel 進(jìn)行一起協(xié)同工作。這樣左右兩個有點(diǎn):

  1. 故障檢測的時候,多個進(jìn)程認(rèn)為出現(xiàn)故障的時候才認(rèn)為出現(xiàn)故障。避免wupan
  2. 多個sentinel進(jìn)程一起工作,當(dāng)有部分sentinel死掉的時候,系統(tǒng)仍然能夠繼續(xù)工作。sentinel不一定要求所有的sentinel一起工作

2. 啟動和配置

在主從配置的時候把slave配置bind ,因為他有可能成為master。

sentinel服務(wù)是和redis服務(wù)一起發(fā)布。啟動腳本位置和redis的啟動位置一樣 redis-sentinel 腳本就是的。啟動方式如下:

## pwd=redis-3.2.8
## 方式一
src/redis-sentinel sentinel.conf

## 方式二
src/redis-server sentinel.conf --sentinel

兩種啟動方式是一摸一樣的。redis服務(wù)和sentinel一起使用的使用的時候,redis啟動和sentinel啟動都需要指明配置文件。因為在sentinel進(jìn)行故障遷移切換master的時候會修改原來的master和slave的redis和sentinel的配置

sentinel的配置,redis提供個默認(rèn)的配置sentinel.conf。 配置項如下:

protected-mode no # 設(shè)置成no,沒有訪問限制
port 5000
sentinel monitor mymaster 192.168.206.200 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

官方說法是,使用sentinel的時候,最好3個以上的sentinel實(shí)例(instance)較好,因為他的選舉策略要投票過半。

上面的配置,每個實(shí)例使用相同的配置即可,如果sentinel有在同一個機(jī)器上,需要修改下端口保持不同,避免端口占用的問題

現(xiàn)在來看這個配置各項說明

  1. sentinel monitor mymaster 192.168.206.200 6379 2 他的配置 規(guī)則是
sentinel monitor <master-group-name> <ip> <port> <quorum>

master-group-name: master的名稱,唯一標(biāo)志,ip, port redis服務(wù) master的ip和端口
quorum: 要確定master掛了,知道要多少個sentinel實(shí)例投票

  1. 選項配置
sentinel <option_name> <master_name> <option_value>

down-after-milliseconds:在master沒有回應(yīng)后多久(多少毫秒)認(rèn)為master掛掉
failover-timeout:故障遷移進(jìn)程多久超時,設(shè)置時間內(nèi)沒有完成認(rèn)為超時
parallel-syncs:故障遷移的時候,最多同時幾臺和master數(shù)據(jù)同步。數(shù)字越小,故障遷移越耗時,但是如果slave配置了master遷移繼續(xù)使用old data提供服務(wù)的話。建議配置此項為1。

3. 部署架構(gòu)

在redis得官方文檔中,建議不用使用只有兩個sentinel的實(shí)例的方式部署,可用不高,建議知道要3個實(shí)例。示例的部署方案如下:

示例中 M1..Mn代表master,R1...R2代表slave , S1....Sn代表sentinel實(shí)例,C1.....Cn clients

  1. redis實(shí)力和sentinel在同一臺機(jī)器,1master ,2slave模式
             +----+
             | M1 |
             | S1 |
             +----+
                 |
    +----+    |       +----+
    | R2 |----+----   | R3 |
    | S2 |            | S3 |
    +----+            +----+

Configuration: quorum = 2
  1. 1 master,1 slave, sentinel放在客戶端這邊
            +----+         +----+
            | M1 |----+----| R1 |
            |    |    |    |    |
            +----+    |    +----+
                      |
         +------------+------------+
         |            |            |
         |            |            |
      +----+        +----+      +----+
      | C1 |        | C2 |      | C3 |
      | S1 |        | S2 |      | S3 |
      +----+        +----+      +----+

      Configuration: quorum = 2
  1. 1 master ,1 slave
           +----+         +----+
            | M1 |----+----| R1 |
            | S1 |    |    | S2 |
            +----+    |    +----+
                      |
               +------+-----+
               |            |  
               |            |
            +----+        +----+
            | C1 |        | C2 |
            | S3 |        | S4 |
            +----+        +----+

      Configuration: quorum = 3

4. 高級概念

大部分概念在文章開頭提到的中英文文檔中都有介紹。這里簡單說下幾個最基本的

4.1. 主觀下線和客觀下線

  1. 主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個 Sentinel 實(shí)例對服務(wù)器做出的下線判斷。
  2. 客觀下線(Objectively Down, 簡稱 ODOWN)指的是多個 Sentinel 實(shí)例在對同一個服務(wù)器做出 SDOWN 判斷, 并且通過 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服務(wù)器下線判斷。 (一個 Sentinel 可以通過向另一個 Sentinel 發(fā)送 SENTINEL is-master-down-by-addr 命令來詢問對方是否認(rèn)為給定的服務(wù)器已下線。)
    如果一個服務(wù)器沒有在 master-down-after-milliseconds 選項所指定的時間內(nèi), 對向它發(fā)送 PING 命令的 Sentinel 返回一個有效回復(fù)(valid reply), 那么 Sentinel 就會將這個服務(wù)器標(biāo)記為主觀下線。

客觀下線條件只適用于主服務(wù)器

4.2. 每個 Sentinel 都需要定期執(zhí)行的任務(wù)

  1. 每個 Sentinel 以每秒鐘一次的頻率向它所知的主服務(wù)器、從服務(wù)器以及其他 Sentinel 實(shí)例發(fā)送一個 PING 命令。
  2. 如果一個實(shí)例(instance)距離最后一次有效回復(fù) PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 那么這個實(shí)例會被 Sentinel 標(biāo)記為主觀下線。 一個有效回復(fù)可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
  3. 如果一個主服務(wù)器被標(biāo)記為主觀下線, 那么正在監(jiān)視這個主服務(wù)器的所有 Sentinel 要以每秒一次的頻率確認(rèn)主服務(wù)器的確進(jìn)入了主觀下線狀態(tài)。
  4. 如果一個主服務(wù)器被標(biāo)記為主觀下線, 并且有足夠數(shù)量的 Sentinel (至少要達(dá)到配置文件指定的數(shù)量)在指定的時間范圍內(nèi)同意這一判斷, 那么這個主服務(wù)器被標(biāo)記為客觀下線。
  5. 在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有主服務(wù)器和從服務(wù)器發(fā)送 INFO 命令。 當(dāng)一個主服務(wù)器被 Sentinel 標(biāo)記為客觀下線時, Sentinel 向下線主服務(wù)器的所有從服務(wù)器發(fā)送 INFO 命令的頻率會從 10 秒一次改為每秒一次。
  6. 當(dāng)沒有足夠數(shù)量的 Sentinel 同意主服務(wù)器已經(jīng)下線, 主服務(wù)器的客觀下線狀態(tài)就會被移除。 當(dāng)主服務(wù)器重新向 Sentinel 的 PING 命令返回有效回復(fù)時, 主服務(wù)器的主管下線狀態(tài)就會被移除。

4.3 自動發(fā)現(xiàn)sentinel和slave

sentinel可以自動的發(fā)現(xiàn)其他的sentinel服務(wù)和slave節(jié)點(diǎn)。具體概念,官網(wǎng)有非常詳細(xì)的解釋

5. 代碼實(shí)現(xiàn) Jedis示例

部署架構(gòu)如上面提到的第一種方式,當(dāng)前環(huán)境:

192.168.206.200 redis slave1,sentinel1
192.168.206.201 redis master,sentinel2
192.168.206.202 redis slave2,sentinel3

redis.conf 大部分使用默認(rèn)配置,列出幾個重要的配置

bind 192.168.206.200 # 跟據(jù)master,slave對應(yīng)修改
protected-mode yes
slave-serve-stale-data yes
slave-read-only yes
slave-priority 100
min-slaves-to-write 1
min-slaves-max-lag 10

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec

#slaveof 192.168.206.201 6379 在slave節(jié)點(diǎn)中才配置。master中不配置這個

sentinel.conf 三個實(shí)例一樣的配置

protected-mode no 
port 26379
sentinel monitor mymaster 192.168.206.201 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

redis客戶端配置情況

package com.fun.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;

import java.util.HashSet;
import java.util.Set;

/**
 * Created by fun
 *
 * @date 2017/5/18.
 */
public class SentinelDemo {

    public static void main(String[] args) throws Exception {

        Set<String> sentinels = new HashSet<String>();
        sentinels.add("192.168.206.200:26379");
        sentinels.add("192.168.206.201:26379");
        sentinels.add("192.168.206.202:26379");
        JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);

        while(true) {
            System.out.println("press enter to continue");
            System.in.read();

            Jedis jedis = pool.getResource();
            System.out.println(pool.getCurrentHostMaster());
            String name = jedis.get("name");
            System.out.println("redis get key name="+name);
            jedis.close();
        }

    }
}

// output
/*
按下第一次enter的時候
press enter to continue
192.168.206.201:6379
redis get key name=fun

kill -9 殺掉master 后臺選舉,產(chǎn)生新的master 再次按下enter的時候
192.168.206.202:6379
redis get key name=fun
press enter to continue

*/

查看sentinel 的日志情況 ,可以看到切換master的過程。

4440:X 17 May 13:51:18.774 # +vote-for-leader 86a01849eb3e61289300a93a12855b6483088730 11
4440:X 17 May 13:51:19.793 # +odown master mymaster 192.168.206.201 6379 #quorum 3/2
4440:X 17 May 13:51:19.793 # Next failover delay: I will not start a failover before Wed May 17 13:57:19 2017
4440:X 17 May 13:51:19.859 # +config-update-from sentinel 86a01849eb3e61289300a93a12855b6483088730 192.168.206.200 26379 @ mymaster 192.168.206.201 6379
4440:X 17 May 13:51:19.859 # +switch-master mymaster 192.168.206.201 6379 192.168.206.202 6379
4440:X 17 May 13:51:19.859 * +slave slave 192.168.206.200:6379 192.168.206.200 6379 @ mymaster 192.168.206.202 6379
4440:X 17 May 13:51:19.860 * +slave slave 192.168.206.201:6379 192.168.206.201 6379 @ mymaster 192.168.206.202 6379

6. 問題延伸

在實(shí)際生產(chǎn)中,如果業(yè)務(wù)量比較大的情況,一臺redis實(shí)例作為緩存很有可能回出現(xiàn)不夠使用的情況,這個時候就需要做集群方式,但是redis的官方的說法是集群模式目前還處在驗證階段,沒有statble的版本出現(xiàn)。

大多時候我們都是使用sharding的方式的時候。Jedis中有ShardedJedisPool 來管理鏈接。但是如果我們對分片方式也做主從的話。加入sentinel之后。就要使用JedisSentinelPool方式管理。不難發(fā)現(xiàn),這兩種只能有一種存在。那Jedis如果做到分片情況下也能使用sentinel呢 ?

針對項目的問題,github上面有人開發(fā)了一個 ShardedJedisSentinelPool 可以用來處理這個問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Redis Sentinel 是一個分布式系統(tǒng), 你可以在一個架構(gòu)中運(yùn)行多個 Sentinel 進(jìn)程(progre...
    你是妖怪吧閱讀 905評論 0 0
  • 參考:redis官方文檔,Redis 復(fù)制、Sentinel的搭建和原理說明 Redis Sentinel(哨兵)...
    zzzTango閱讀 1,657評論 0 6
  • Redis 2.8版開始正式提供名為Sentinel的主從切換方案,Sentinel用于管理多個Redis服務(wù)器實(shí)...
    183207efd207閱讀 617評論 0 1
  • 文/鹿小喵 高考成績出來了,你考了一個不錯的成績,雖然與一本線有差距,但足以報一個好的二本學(xué)校。心滿意足。報志愿的...
    鹿小喵閱讀 318評論 0 3
  • 41周歲生日。 被前夫打擾,很不爽。歷來不懂如何拒絕他的說教,道理,所謂的正確。離了快一年,還在允許他這么做,我真...
    Judy970606閱讀 344評論 0 0