天天看點

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

主從技術的切換方法是:當主節點當機後,需要人工将從節點切換為主節點,這樣的方式費事費力還會造成一段時間内服務不可用,這樣的方式顯然不是我們需要的,是以我們必須要有一個高可用的方案來抵抗節點的故障,當節點發生故障時可以自動進行主從切換,程式可以不用重新開機,仿佛什麼事情都沒有發生一樣。Redis官方提供了這樣一種方案-——Redis Sentinel(Sentinel的含義是哨兵)。

一、Redis Sentinel 架構

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

如上圖所示,我們可以将Redis Sentinel 叢集看成是一個zookeeper叢集,它是叢集高可用的心髒,一般有3~5個節點組成,這樣即使個别節點挂了,叢集還可以正常運轉。

Sentinel 負責監控主從節點的健康,當主節點挂掉時自動選擇一個最優的從節點切換為主節點。當用戶端來連接配接叢集時會首先連接配接Sentinel,通過Sentinel來查詢主節點的位址,然後再連接配接主節點進行資料互動。當主節點發生故障時,用戶端會重新向Sentinel要位址,Sentinel會将最新的主節點位址告訴用戶端,如此應用将無須重新啟動就可以自動完成節點切換。

二、Redis Sentinel 故障轉移

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

如上圖所示,如果主節點挂掉了,原先的主從複制也斷開了,一個從節點被提升為新的主節點,其他的從節點開始和新的主節點建立複制關系。用戶端通過新的主節點繼續進行互動,Sentinel會持續監聽已經挂掉的主節點,待它恢變成從節點,從新的主節點哪裡建立 複制關系。

故障轉移可以概括為下面的幾個步驟:

  1.  當多個sentinel發現master有問題會選舉出一個sentinel為上司。
  2. 被選為上司的sentinel會選擇出一個slave為新的master。
  3. 通知其餘的slave成為新的master的slave。
  4. 通知用戶端新的master的位址
  5. 等待原來的master複活成為新master的slave。

三、Redis Sentinel 配置與安裝

1. redis 主節點

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

2. redis從節點

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

3. sentinel配置

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

配置說明:

  • port: 端口号
  • dir:工作目錄
  • logfile:日志
  • sentinel monitor mymaster 127.0.0.1 7000 2 :mymaster代表的是master的名字,127.0.0.1 7000代表的是master的ip和端口,2代表的是至少有多少個sentinel發現master是有問題的才會進行下一步的故障轉移
  • sentinel down-after-milliseconds mymaster 3000:sentinel對master的進行一個判斷,如果超過規定的時間master還沒有響應就代表master是有問題的,這裡是30000毫秒。
  • sentinel parallel-syncs mymaster 1:老的slave對新的master複制同時是串行的還是并發的,這裡的1 代表每次隻能複制一個。
  • sentinel failover-timeout mymastere 180000:故障轉移的時間

四、使用用戶端連接配接redis sentinel

1. 用戶端實作基本原理

a. 用戶端周遊sentinel節點集合擷取一個可用的sentinel節點

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

b. 對可用sentinel擷取master節點的名字、位址和端口

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

c. 擷取到master節點後使用role/role application驗證是否是真正的master

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

d. 當master發生變化時通知用戶端

Redis Sentinel一、Redis Sentinel 架構二、Redis Sentinel 故障轉移三、Redis Sentinel 配置與安裝四、使用用戶端連接配接redis sentinel 五、三個定時任務六、其他

2.jedis

public class TestSentinel {
    @SuppressWarnings("resource")
    @Test
    public void testSentinel() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(10);
        jedisPoolConfig.setMaxIdle(5);
        jedisPoolConfig.setMinIdle(5);
        // 哨兵資訊
        Set<String> sentinels = new HashSet<>(Arrays.asList("192.168.11.128:26379",
                "192.168.11.129:26379","192.168.11.130:26379"));
        // 建立連接配接池
        JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels,jedisPoolConfig,"123456");
        // 擷取用戶端
        Jedis jedis = pool.getResource();
        // 執行兩個指令
        jedis.set("mykey", "myvalue");
        String value = jedis.get("mykey");
        System.out.println(value);
    }
}
           

3. 通過spring進行配置

<bean id = "poolConfig" class="redis.clients.jedis.JedisPoolConfig">
            <!-- 最大空閑數 -->
            <property name="maxIdle" value="50"></property>
            <!-- 最大連接配接數 -->
            <property name="maxTotal" value="100"></property>
            <!-- 最大等待時間 -->
            <property name="maxWaitMillis" value="20000"></property>
        </bean>
        
        <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
            <constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
            <constructor-arg name="sentinelConfig" ref="sentinelConfig"></constructor-arg>
            <property name="password" value="123456"></property>
        </bean>
        
        <!-- JDK序列化器 -->
        <bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
        
        <!-- String序列化器 -->
        <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        
        <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
            <property name="connectionFactory" ref="connectionFactory"></property>
            <property name="keySerializer" ref="stringRedisSerializer"></property>
            <property name="defaultSerializer" ref="stringRedisSerializer"></property>
            <property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
        </bean>
        
        <!-- 哨兵配置 -->
        <bean id="sentinelConfig" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
            <!-- 服務名稱 -->
            <property name="master">
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <property name="name" value="mymaster"></property>
                </bean>
            </property>
            <!-- 哨兵服務IP和端口 -->
            <property name="sentinels">
                <set>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="192.168.11.128"></constructor-arg>
                        <constructor-arg name="port" value="26379"></constructor-arg>
                    </bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="192.168.11.129"></constructor-arg>
                        <constructor-arg name="port" value="26379"></constructor-arg>
                    </bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="192.168.11.130"></constructor-arg>
                        <constructor-arg name="port" value="26379"></constructor-arg>
                    </bean>
                </set>
            </property>
        </bean>
           

 五、三個定時任務

為了保證可以為redis進行故障轉移,redis sentinel内部有三個定時任務

1. 每10秒每個sentinel對master和slave執行info

這個定時任務的主要目的如下:

  • 發現slave節點:在配置中并沒有配置slave節點的資訊,實際上是不需要的配置的 ,sentinel會對master執行info操作,會在info replication 中發現slave資訊進而發現slave節點。
  • 确認主從關系:對每個執行info就可以确認他們之前的關系和關系的變化。

2.每2秒每個sentinel通過master節點的channel交換資訊(pub/sub)

mster節點上會有一個釋出訂閱的channel(頻道)用于讓sentinel節點進行資訊交換利用的原理就是每個sentinel釋出資訊,其他的sentinel可以收到資訊(資訊中會包含目前自身的資訊、master的資訊和對master和slave的判斷),最後sentinel之間會達成一個共識,他們之前的資訊交換是利用的master的 channel,利用的是釋出訂閱。

這個定時任務的主要目的如下:

  • 通過_sentinel_:hello頻道互動
  • 互動對節點的看法和自身的資訊

3.每1秒每個sentinel對其他的sentinel執行和redis執行ping

這個定時任務的主要目的如下:

  • 心跳檢測,失敗判斷的依據

六、其他

1. 主觀下線和可觀下線

  • 主觀下線:每個sentinel節點對節點失敗的偏見
  • 客觀下線:所有sentinel對節點的失敗達成共識

2.上司者選擇

  • 原因:隻有一個sentinel完成故障轉移
  • 選舉:通過sentinel is-master-down-by-addr 指令都希望成為上司者

選舉過程如下:

  1. 每個主觀下線的sentinel向其他sentinel發送指令,要求将他設定為上司者。
  2. 收到指令的sentinel節點如果沒有同意通過其他sentinel節點發送的指令,那麼将同意該請求否則拒絕。
  3. 如果該sentinel節點發現自己已經超過sentinel集合的半數并且超過 sentinel monitor這個配置中所設定的數量,那麼它将成為上司者。
  4. 如果此過程有多個sentinel成為上司者,那麼将等待一段時間再次選舉。

3.故障轉移

故障轉移有如下幾個步驟:

  1. 從slave節點選出一個“合适”的節點作為新的matser
  2. 對上面的slave節點執行 slaveof no one 指令讓其成為master節點。
  3. 向剩餘的slave節點發送指令,讓他們成為新master節點的slave節點,複制規則和parallel-sync參數有關
  4. 更新對原來master節點配置為slave,并保持着對其關注,當其恢複後指令它去複制新的master節點。

什麼是合适的slave節點?

  • 選擇 save-priority(slave節點優先級)最高的slave節點,如果存在則傳回,不存在則繼續。
  • 選擇複制偏移量最大的slave節點(複制的最完整),如果存在則傳回,不存在則繼續。
  • 選擇runId最小的slave節點

4.消息丢失

Redis主從采用異步複制,意味着主節點挂掉時,從節點可能沒有收到全部的同步消息,這部分未同步的消息就丢失了,如果主從延遲特别大,那麼丢失的資料就可能會特别多。Sentinel無法保證資料不丢失,但也能保證消息少丢失,它有兩個選項可以限制主從延遲過大。

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

第一個參數表示主節點必須至少有一個從節點在進行正常複制,否則就停止對外寫服務,喪失可用性。

第二個參數控制什麼是正常複制,什麼是異常複制,它的機關是秒(s),表示如果在10s沒有收到從節點回報,就意味着從節點同步不正常,要麼是網絡斷開了,要麼是一直沒有給回報。

繼續閱讀