附:
Redis Cluster集羣主從方案:http://wosyingjun.iteye.com/blog/2289220
Redis Sentinel主從高可用方案:http://wosyingjun.iteye.com/blog/2289593
redis中文網對於redis哨兵的詳細介紹 http://redis.majunwei.com/topics/sentinel.html
一、Sentinel介紹
Sentinel是Redis的高可用性(HA)解決方案,由一個或多個Sentinel實例組成的Sentinel系統可以監視任意多個主服務器,以及這些主服務器屬下的所有從服務器,並在被監視的主服務器進行下線狀態時,自動將下線主服務器屬下的某個從服務器升級爲新的主服務器,然後由新的主服務器代替已下線的主服務器繼續處理命令請求。Redis提供的sentinel(哨兵)機制,通過sentinel模式啓動redis後,自動監控master/slave的運行狀態,基本原理是:心跳機制+投票裁決
- 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。
- 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。
- 自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其他從服務器改爲複製新的主服務器; 當客戶端試圖連接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可以使用新主服務器代替失效服務器。
二、Sentinel的主從原理
之前介紹過爲什麼Jedis要用2.2.2及以上版本,因爲主從實例地址(IP PORT)是不同的,當故障發生進行主從切換後,應用程序無法知道新地址,故在Jedis2.2.2中新增了對Sentinel的支持,應用通過redis.clients.jedis.JedisSentinelPool.getResource()取得的Jedis實例會及時更新到新的主實例地址。
三、Redis Sentinel配置
這裏我採用2個哨兵,1個主redis,2個從redis的方式,配置文件如下:
sentinel_63791.conf 配置:
port 63791
daemonize yes
logfile "/var/log/sentinel_63791.log"
#master-1
sentinel monitor master-1 192.168.78.99 6379 2
sentinel down-after-milliseconds master-1 5000
sentinel failover-timeout master-1 18000
sentinel auth-pass master-1 yingjun
sentinel parallel-syncs master-1 1
sentinel_63792.conf 配置:
port 63792
daemonize yes
logfile "/var/log/sentinel_63792.log"
#master-1
sentinel monitor master-1 192.168.78.99 6379 2
sentinel down-after-milliseconds master-1 5000
sentinel failover-timeout master-1 18000
sentinel auth-pass master-1 yingjun
sentinel parallel-syncs master-1 1
redis_master_6379.conf 配置:
在原配置文件中作如下修改:
port 6379
daemonize yes
requirepass yingjun
masterauth yingjun
redis_slave_6380.conf 配置:
在原配置文件中作如下修改:
port 6380
daemonize yes
requirepass yingjun
slaveof 192.168.78.99 6379
masterauth yingjun
redis_slave_6381.conf 配置:
在原配置文件中作如下修改:
port 6381
daemonize yes
requirepass yingjun
slaveof 192.168.78.99 6379
masterauth yingjun
按如下順序依次啓動服務:
./redis-server ../conf/redis_master_6379.conf
./redis-server ../conf/redis_slave_6381.conf
./redis-server ../conf/redis_slave_6382.conf
./redis-sentinel ../conf/sentinel_63791.conf
./redis-sentinel ../conf/sentinel_63792.conf
查看進程是否都已經啓動:
查看master的狀態:
查看slave的狀態:
查看sentinel的狀態:
接下來驗證redis sentinel的主從切換:
- 首先關閉主redis(6379)服務(shutdown)。
-
查看哨兵,發現端口號爲6380的從服務變成了主服務,sentinel自動完成了故障切換。
- 啓動剛纔被shutdown的6379服務並查看,發現它變成了從服務。
三、Jedis Sentinel教程
Maven依賴:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
<!-- spring-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.4.RELEASE</version>
</dependency>
redis的配置文件:
#redis config
redis.pass=yingjun
redis.pool.maxTotal=105
redis.pool.maxIdle=10
redis.pool.maxWaitMillis=60000
redis.pool.testOnBorrow=true
sentinel1.ip=192.168.78.99
sentinel1.port=63791
sentinel2.ip=192.168.78.99
sentinel2.port=63792
Spring的配置文件:
<!-- Redis 配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}" />
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>
<bean id="sentinelConfiguration"
class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<property name="master">
<bean class="org.springframework.data.redis.connection.RedisNode">
<property name="name" value="master-1"></property>
</bean>
</property>
<property name="sentinels">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${sentinel1.ip}"></constructor-arg>
<constructor-arg name="port" value="${sentinel1.port}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${sentinel2.ip}"></constructor-arg>
<constructor-arg name="port" value="${sentinel2.port}"></constructor-arg>
</bean>
</set>
</property>
</bean>
<!-- Jedis ConnectionFactory連接配置 -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="password" value="${redis.pass}"></property>
<property name="poolConfig" >
<ref bean="jedisPoolConfig"/>
</property>
<constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
</bean>
<!-- redisTemplate配置,redisTemplate是對Jedis的對redis操作的擴展,有更多的操作,封裝使操作更便捷 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>
代碼中直接用redisTemplate調用:
@Override
public boolean add(final KeyToken tkey) {
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = getRedisSerializer();
byte[] key = serializer.serialize(tkey.getIndex());
byte[] name = serializer.serialize(tkey.getExpire_time());
return connection.setNX(key, name);
}
});
return result;
}