主從切換技術(shù)的方法是:當(dāng)主服務(wù)器宕機(jī)后锋玲,需要手動(dòng)把一臺(tái)從服務(wù)器切換為主服務(wù)器灭返,這就需要人工干預(yù)盗迟,費(fèi)事費(fèi)力,還會(huì)造成一段時(shí)間內(nèi)服務(wù)不可用熙含。這不是一種推薦的方式罚缕,更多時(shí)候,我們優(yōu)先考慮哨兵模式怎静。
一邮弹、哨兵模式概述
哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令蚓聘,哨兵是一個(gè)獨(dú)立的進(jìn)程腌乡,作為進(jìn)程,它會(huì)獨(dú)立運(yùn)行夜牡。其原理是哨兵通過(guò)發(fā)送命令导饲,等待Redis服務(wù)器響應(yīng),從而監(jiān)控運(yùn)行的多個(gè)Redis實(shí)例氯材。
這里的哨兵有兩個(gè)作用
通過(guò)發(fā)送命令,讓Redis服務(wù)器返回監(jiān)控其運(yùn)行狀態(tài)硝岗,包括主服務(wù)器和從服務(wù)器氢哮。
當(dāng)哨兵監(jiān)測(cè)到master宕機(jī),會(huì)自動(dòng)將slave切換成master型檀,然后通過(guò)發(fā)布訂閱模式通知其他的從服務(wù)器冗尤,修改配置文件,讓它們切換主機(jī)胀溺。
然而一個(gè)哨兵進(jìn)程對(duì)Redis服務(wù)器進(jìn)行監(jiān)控裂七,可能會(huì)出現(xiàn)問(wèn)題,為此仓坞,我們可以使用多個(gè)哨兵進(jìn)行監(jiān)控背零。各個(gè)哨兵之間還會(huì)進(jìn)行監(jiān)控,這樣就形成了多哨兵模式无埃。
用文字描述一下故障切換(failover)的過(guò)程徙瓶。假設(shè)主服務(wù)器宕機(jī)毛雇,哨兵1先檢測(cè)到這個(gè)結(jié)果,系統(tǒng)并不會(huì)馬上進(jìn)行failover過(guò)程侦镇,僅僅是哨兵1主觀的認(rèn)為主服務(wù)器不可用灵疮,這個(gè)現(xiàn)象成為主觀下線。當(dāng)后面的哨兵也檢測(cè)到主服務(wù)器不可用壳繁,并且數(shù)量達(dá)到一定值時(shí)震捣,那么哨兵之間就會(huì)進(jìn)行一次投票,投票的結(jié)果由一個(gè)哨兵發(fā)起闹炉,進(jìn)行failover操作蒿赢。切換成功后,就會(huì)通過(guò)發(fā)布訂閱模式剩胁,讓各個(gè)哨兵把自己監(jiān)控的從服務(wù)器實(shí)現(xiàn)切換主機(jī)诉植,這個(gè)過(guò)程稱為客觀下線。這樣對(duì)于客戶端而言昵观,一切都是透明的晾腔。
二、Redis配置哨兵模式
配置3個(gè)哨兵和1主2從的Redis服務(wù)器來(lái)演示這個(gè)過(guò)程啊犬。
服務(wù)類型 | 是否是主服務(wù)器 | 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的主從服務(wù)器灼擂,修改redis.conf文件如下
# 使得Redis服務(wù)器可以跨網(wǎng)絡(luò)訪問(wèn)
bind 0.0.0.0
# 設(shè)置密碼
requirepass "123456"
# 指定主服務(wù)器,注意:有關(guān)slaveof的配置只是配置從服務(wù)器觉至,主服務(wù)器不需要配置
slaveof 192.168.11.128 6379
# 主服務(wù)器密碼剔应,注意:有關(guān)slaveof的配置只是配置從服務(wù)器,主服務(wù)器不需要配置
masterauth 123456
上述內(nèi)容主要是配置Redis服務(wù)器语御,從服務(wù)器比主服務(wù)器多一個(gè)slaveof的配置和密碼峻贮。
配置3個(gè)哨兵,每個(gè)哨兵的配置都是一樣的应闯。在Redis安裝目錄下有一個(gè)sentinel.conf文件纤控,copy一份進(jìn)行修改
# 禁止保護(hù)模式
protected-mode no
# 配置監(jiān)聽(tīng)的主服務(wù)器,這里sentinel monitor代表監(jiān)控碉纺,mymaster代表服務(wù)器的名稱船万,可以自定義,192.168.11.128代表監(jiān)控的主服務(wù)器骨田,6379代表端口耿导,2代表只有兩個(gè)或兩個(gè)以上的哨兵認(rèn)為主服務(wù)器不可用的時(shí)候,才會(huì)進(jìn)行failover操作态贤。
sentinel monitor mymaster 192.168.11.128 6379 2
# sentinel author-pass定義服務(wù)的密碼舱呻,mymaster是服務(wù)名稱,123456是Redis服務(wù)器密碼
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster 123456
上述關(guān)閉了保護(hù)模式悠汽,便于測(cè)試狮荔。
有了上述的修改胎撇,我們可以進(jìn)入Redis的安裝目錄的src目錄,通過(guò)下面的命令啟動(dòng)服務(wù)器和哨兵
# 啟動(dòng)Redis服務(wù)器進(jìn)程
./redis-server ../redis.conf
# 啟動(dòng)哨兵進(jìn)程
./redis-sentinel ../sentinel.conf
注意啟動(dòng)的順序殖氏。首先是主機(jī)(192.168.11.128)的Redis服務(wù)進(jìn)程晚树,然后啟動(dòng)從機(jī)的服務(wù)進(jìn)程,最后啟動(dòng)3個(gè)哨兵的服務(wù)進(jìn)程雅采。
三爵憎、Java中使用哨兵模式
/**
* 測(cè)試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"));
// 創(chuàng)建連接池
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels,jedisPoolConfig,"123456");
// 獲取客戶端
Jedis jedis = pool.getResource();
// 執(zhí)行兩個(gè)命令
jedis.set("mykey", "myvalue");
String value = jedis.get("mykey");
System.out.println(value);
}
}
上面是通過(guò)Jedis進(jìn)行使用的,同樣也可以使用Spring進(jìn)行配置RedisTemplate使用婚瓜。
<bean id = "poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大空閑數(shù) -->
<property name="maxIdle" value="50"></property>
<!-- 最大連接數(shù) -->
<property name="maxTotal" value="100"></property>
<!-- 最大等待時(shí)間 -->
<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">
<!-- 服務(wù)名稱 -->
<property name="master">
<bean class="org.springframework.data.redis.connection.RedisNode">
<property name="name" value="mymaster"></property>
</bean>
</property>
<!-- 哨兵服務(wù)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>
四宝鼓、哨兵模式的其他配置項(xiàng)
配置項(xiàng) | 參數(shù)類型 | 作用 |
---|---|---|
port | 整數(shù) | 啟動(dòng)哨兵進(jìn)程端口 |
dir | 文件夾目錄 | 哨兵進(jìn)程服務(wù)臨時(shí)文件夾,默認(rèn)為/tmp巴刻,要保證有可寫入的權(quán)限 |
sentinel down-after-milliseconds | <服務(wù)名稱><毫秒數(shù)(整數(shù))> | 指定哨兵在監(jiān)控Redis服務(wù)時(shí)愚铡,當(dāng)Redis服務(wù)在一個(gè)默認(rèn)毫秒數(shù)內(nèi)都無(wú)法回答時(shí),單個(gè)哨兵認(rèn)為的主觀下線時(shí)間胡陪,默認(rèn)為30000(30秒) |
sentinel parallel-syncs | <服務(wù)名稱><服務(wù)器數(shù)(整數(shù))> | 指定可以有多少個(gè)Redis服務(wù)同步新的主機(jī)沥寥,一般而言,這個(gè)數(shù)字越小同步時(shí)間越長(zhǎng)柠座,而越大邑雅,則對(duì)網(wǎng)絡(luò)資源要求越高 |
sentinel failover-timeout | <服務(wù)名稱><毫秒數(shù)(整數(shù))> | 指定故障切換允許的毫秒數(shù),超過(guò)這個(gè)時(shí)間妈经,就認(rèn)為故障切換失敗淮野,默認(rèn)為3分鐘 |
sentinel notification-script | <服務(wù)名稱><腳本路徑> | 指定sentinel檢測(cè)到該監(jiān)控的redis實(shí)例指向的實(shí)例異常時(shí),調(diào)用的報(bào)警腳本吹泡。該配置項(xiàng)可選骤星,比較常用 |
sentinel down-after-milliseconds配置項(xiàng)只是一個(gè)哨兵在超過(guò)規(guī)定時(shí)間依舊沒(méi)有得到響應(yīng)后,會(huì)自己認(rèn)為主機(jī)不可用爆哑。對(duì)于其他哨兵而言妈踊,并不是這樣認(rèn)為。哨兵會(huì)記錄這個(gè)消息泪漂,當(dāng)擁有認(rèn)為主觀下線的哨兵達(dá)到sentinel monitor所配置的數(shù)量時(shí),就會(huì)發(fā)起一次投票歪泳,進(jìn)行failover萝勤,此時(shí)哨兵會(huì)重寫Redis的哨兵配置文件,以適應(yīng)新場(chǎng)景的需要呐伞。