主從切換技術的方法是:當主服務器宕機後,須要手動把一臺從服務器切換爲主服務器,這就須要人工干預,費事費力,還會形成一段時間內服務不可用。這不是一種推薦的方式,更多時候,咱們優先考慮哨兵模式。java
哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令,哨兵是一個獨立的進程,做爲進程,它會獨立運行。其原理是哨兵經過發送命令,等待Redis服務器響應,從而監控運行的多個Redis實例。
redis
這裏的哨兵有兩個做用spring
經過發送命令,讓Redis服務器返回監控其運行狀態,包括主服務器和從服務器。編程
當哨兵監測到master宕機,會自動將slave切換成master,而後經過發佈訂閱模式通知其餘的從服務器,修改配置文件,讓它們切換主機。bash
然而一個哨兵進程對Redis服務器進行監控,可能會出現問題,爲此,咱們可使用多個哨兵進行監控。各個哨兵之間還會進行監控,這樣就造成了多哨兵模式。服務器
用文字描述一下故障切換(failover)的過程。假設主服務器宕機,哨兵1先檢測到這個結果,系統並不會立刻進行failover過程,僅僅是哨兵1主觀的認爲主服務器不可用,這個現象成爲主觀下線。當後面的哨兵也檢測到主服務器不可用,而且數量達到必定值時,那麼哨兵之間就會進行一次投票,投票的結果由一個哨兵發起,進行failover操做。切換成功後,就會經過發佈訂閱模式,讓各個哨兵把本身監控的從服務器實現切換主機,這個過程稱爲客觀下線。這樣對於客戶端而言,一切都是透明的。網絡
配置3個哨兵和1主2從的Redis服務器來演示這個過程。測試
服務類型 | 是不是主服務器 | IP地址 | 端口 |
---|---|---|---|
Redis | 是 | 192.168.11.128 | 6379 |
Redis | 否 | 192.168.11.129 | 6379 |
Redis | 否 | 192.168.11.130 | 6379 |
Sentinel | - | 192.168.11.128 | 26379 |
Sentinel | - | 192.168.11.129 | 26379 |
Sentinel | - | 192.168.11.130 | 26379 |
首先配置Redis的主從服務器,修改redis.conf文件以下ui
# 使得Redis服務器能夠跨網絡訪問 bind 0.0.0.0 # 設置密碼 requirepass "123456" # 指定主服務器,注意:有關slaveof的配置只是配置從服務器,主服務器不須要配置 slaveof 192.168.11.128 6379 # 主服務器密碼,注意:有關slaveof的配置只是配置從服務器,主服務器不須要配置 masterauth 123456
上述內容主要是配置Redis服務器,從服務器比主服務器多一個slaveof的配置和密碼。spa
配置3個哨兵,每一個哨兵的配置都是同樣的。在Redis安裝目錄下有一個sentinel.conf文件,copy一份進行修改
# 禁止保護模式 protected-mode no # 配置監聽的主服務器,這裏sentinel monitor表明監控,mymaster表明服務器的名稱,能夠自定義,192.168.11.128表明監控的主服務器,6379表明端口,2表明只有兩個或兩個以上的哨兵認爲主服務器不可用的時候,纔會進行failover操做。 sentinel monitor mymaster 192.168.11.128 6379 2 # sentinel author-pass定義服務的密碼,mymaster是服務名稱,123456是Redis服務器密碼 # sentinel auth-pass <master-name> <password> sentinel auth-pass mymaster 123456
上述關閉了保護模式,便於測試。
有了上述的修改,咱們能夠進入Redis的安裝目錄的src目錄,經過下面的命令啓動服務器和哨兵
# 啓動Redis服務器進程 ./redis-server ../redis.conf # 啓動哨兵進程 ./redis-sentinel ../sentinel.conf
注意啓動的順序。首先是主機(192.168.11.128)的Redis服務進程,而後啓動從機的服務進程,最後啓動3個哨兵的服務進程。
/** * 測試Redis哨兵模式 * @author liu */ public class TestSentinels { @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); } }
上面是經過Jedis進行使用的,一樣也可使用Spring進行配置RedisTemplate使用。
<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>
配置項 | 參數類型 | 做用 |
---|---|---|
port | 整數 | 啓動哨兵進程端口 |
dir | 文件夾目錄 | 哨兵進程服務臨時文件夾,默認爲/tmp,要保證有可寫入的權限 |
sentinel down-after-milliseconds | <服務名稱><毫秒數(整數)> | 指定哨兵在監控Redis服務時,當Redis服務在一個默認毫秒數內都沒法回答時,單個哨兵認爲的主觀下線時間,默認爲30000(30秒) |
sentinel parallel-syncs | <服務名稱><服務器數(整數)> | 指定能夠有多少個Redis服務同步新的主機,通常而言,這個數字越小同步時間越長,而越大,則對網絡資源要求越高 |
sentinel failover-timeout | <服務名稱><毫秒數(整數)> | 指定故障切換容許的毫秒數,超過這個時間,就認爲故障切換失敗,默認爲3分鐘 |
sentinel notification-script | <服務名稱><腳本路徑> | 指定sentinel檢測到該監控的redis實例指向的實例異常時,調用的報警腳本。該配置項可選,比較經常使用 |
sentinel down-after-milliseconds配置項只是一個哨兵在超過規定時間依舊沒有獲得響應後,會本身認爲主機不可用。對於其餘哨兵而言,並非這樣認爲。哨兵會記錄這個消息,當擁有認爲主觀下線的哨兵達到sentinel monitor所配置的數量時,就會發起一次投票,進行failover,此時哨兵會重寫Redis的哨兵配置文件,以適應新場景的須要。