一、哨兵模式的蛋生

我们都知道单节点、单实例的东西一旦挂点就没救啦,所以凡事一定要多节点,一个节点挂掉,另一个节点还可以对外提供服务,这叫高可用。

一般来说,要保持高可用,启用多个实例,然后在客户端配置多个实例地址就可以了。

比如:

redis.host=127.0.0.1:6379;127.0.0.1:6380;127.0.0.1:6381

如果连接其中一个redis失败了,就尝试去连接另外一个redis。

然鹅,事实上这是不行的。

两个原因:

  1. redis不支持主从自动切换;
  2. redis仅支持 主-从,不支持 主-主,只能数据从master同步到slave;

既然Redis无法自动切换主从,所以只好让别人来做了,那就是sentinel。

所以,sentinel需要做什么事情呢?

  1. 监控各个redis实例是否存活;
  2. master断掉以后,自动选举出新的master;
  3. 通知其他redis:master变了;

服务器端采用多个sentinel节点来监控各个redis节点,并做主从自动切换。但是这和客户端没什么关系,所以如果客户端不对此做什么改变的话,那sentinel就形同虚设了。

现在,客户端肯定是不知道谁是master的,所以客户端肯定是不能直接连接到某个redis节点的。但是sentinel知道呀~ 所以,客户端应该连接到sentinel,由sentinel动态地告诉客户端应该连接到哪个Redis节点。

image.png

二、客户端接入Redis Sentinel

没错,客户端怎么接入sentinel呢?

我这里拿Jedis举例子。

通常,Jedis有两种接入sentinel的模式,按照业务层操作redis的直接对象,可以分为

  • Jedis
  • RedisTemplate

配置文件

redis.sentinel.master=mymaster
redis.sentinel.pwd=123456
redis.sentinel.nodes=10.10.101.123:26379;10.10.101.124:26380;10.10.101.125:26381

Jedis

即使用原生的Jedis来操作redis。

@Configuration
public class RedisTemplate {
    
     @Value("${redis.sentinel.master}")
    String masterName;
    @Value("${redis.sentinel.pwd}")
    String sentinelPwd;
    @Value("${redis.sentinel.nodes}")
    String sentinelNodes;
    @Value("${redis.pool.maxIdle}")
    int maxIdle;
    @Value("${redis.pool.maxTotal}")
    int maxTotal;
    @Value("${redis.pool.maxWaitMillis}")
    long maxWaitMillis;
    @Value("${redis.pool.testOnBorrow}")
    boolean testOnBorrow;
    @Value("${redis.pool.minEvictableIdleTimeMillis}")
    long minEvictableIdleTimeMillis;
    
       @Bean(name = "jedisConnectionFactory")
    public JedisConnectionFactory getFactory(){
        JedisConnectionFactory factory = new JedisConnectionFactory(getSentinelConfig(), getPool());
        factory.setPassword(sentinelPwd);
        return factory;
    }
    
        @Bean(name = "jedisPoolConfig")
    public JedisPoolConfig getPool(){
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxIdle(maxIdle);
        config.setMaxTotal(maxTotal);
        config.setMaxWaitMillis(maxWaitMillis);
        config.setTestOnBorrow(testOnBorrow);
        config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        return config;
    }
    
        @Bean(name = "jedisSentinelPool")
    public JedisSentinelPool getJedisSentinelPool(){
        Set<String> sets = Sets.newHashSet(getSentinelNodes());
        JedisSentinelPool sentinelPool = new JedisSentinelPool(masterName, sets, getPool(), sentinelPwd);
        return sentinelPool;
    }
    
    public List<String> getSentinelNodes(){
        List<RedisNode> nodesList = Lists.newArrayList();
        String[] nodes = sentinelNodes.split(";");
        return Arrays.asList(nodes);
    }
    
    
}    

使用的时候只需这样

@Autowired
JedisSentinelPool pool;
public void test(){
    String key = "key";
    String value = "value";
	Jedis jedis = pool.getgetResource();
    jedis.set(key, value);
}

RedisTemplate

@Configuration
public class RedisTemplate {
    
...(忽略一部分,和上面是一样的)
	
        @Bean(name = "stringRedisTemplate")
    public StringRedisTemplate getRedisTemplate(){
        StringRedisTemplate template = new StringRedisTemplate();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setDefaultSerializer(stringRedisSerializer);
        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(new JdkSerializationRedisSerializer());
        template.setConnectionFactory(getFactory());
        template.afterPropertiesSet();
        return template;
    }

}

使用的时候

@Autowired
StringRedisTemplate stringRedisTemplate;
public void test(){
    String key = "key";
    String value = "value";
    stringRedisTemplate.template.opsForValue().set(key, value);
}

Jedis和RedisTemplate有何区别

Jedis操作完成后,需要手动调用close()释放连接;RedisTemplate不需要用户手动释放连接;

我们到 RedisConnectionUtils 查看一下execute方法会发现,每次RedisTemplate执行一个操作以后都会releaseConnection

public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		...
		try {
			...
			// TODO: any other connection processing?
			return postProcessResult(result, connToUse, existingConnection);
		} finally {
			RedisConnectionUtils.releaseConnection(conn, factory);
		}
	}

继续查看一下releaseConnection()

public static void releaseConnection(RedisConnection conn, RedisConnectionFactory factory) {

		...
 
		if (connHolder != null && connHolder.isTransactionSyncronisationActive()) {
			if (log.isDebugEnabled()) {
				log.debug("Redis Connection will be closed when transaction finished.");
			}
			return;
		}

		// release transactional/read-only and non-transactional/non-bound connections.
		// transactional connections for read-only transactions get no synchronizer registered
		if (isConnectionTransactional(conn, factory)
				&& TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
			unbindConnection(factory);
		} else if (!isConnectionTransactional(conn, factory)) {
			if (log.isDebugEnabled()) {
				log.debug("Closing Redis Connection");
			}
			conn.close();
		}
	}

可以看到,如果不是处于一个transactional事务,操作完成后,connection直接就close()了。

Jedis采用原生Jedis接口操作数据,redisTemplate则为不同客户端提供了统一的操作模板;

使用redisTemplate以后,如果切换为别的redis客户端,修改的成本比较低。

有人经过测试反映说redis是原生接口,效率比redisTemplate高一些。

三、How Redis Sentinel Work?

我们需要通过一些简单的场景来观察这个过程。在接下来的时间里,我们尝试去模拟可能发生的5种场景。

0. 环境

先来看下试验的环境:

145、146、147 三台服务器,都安装和运行了Redis和Sentinel。其中,146的redis为master,145/147的redis为slave。

如下图所示:

image.png

1. sentinel正常,关闭master

停止master服务

redis-cli -h 127.0.0.1 -p 6379 shutdown

先看一下最终的结果,最终的状态是这样子的

500,500

我们发现:

  • 原146的redis(master)变成slave;
  • 145变成了master;
  • 147 slaveof 145;

然后我们观察根据三台Sentinel的日志,看一下sentinel是如何进行failover的(为了方便,我们把sentinel简写为S,Redis简写为R):

(ps:三台Sentinel的日志放在 附录1 噢)

  1. 146的S 首先发现发现146的R下线了(+sdown :subject down,主观下线)

    +sdown master mymaster 10.10.101.146 6379
    
  2. 达到指定人数(quorum),认同故障已发生,146的S将146的R标记为已下线(+odown:object down,客观下线)

+odown master mymaster 10.10.101.146 6379 #quorum 2/2
  1. 146的S尝试进行故障转移

    +try-failover master mymaster 10.10.101.146 6379
    
  2. 146的S发起投票,选举新的S Leader

    +vote-for-leader 22c7af0b9b4bdfbb79337ec9d46a90f925a2f308 2
    
  3. 145/147回应选举。

    +vote-for-leader 22c7af0b9b4bdfbb79337ec9d46a90f925a2f308 2
    
  4. 146统计选举结果:146赢得选举,成为Leader

    +elected-leader master mymaster 10.10.101.146 6379
    
  5. 146的S将145R选为新Master,并发送相关指令

    7349:X 10 Dec 17:23:47.431 # +failover-state-select-slave master mymaster 10.10.101.146 6379  (尝试寻找一个slave来提升为master)
    7349:X 10 Dec 17:23:47.561 # +selected-slave slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379   (将一个slave提升为master)
    7349:X 10 Dec 17:23:47.561 * +failover-state-send-slaveof-noone slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379 (向145发送slaveofOnOne指令)
    7349:X 10 Dec 17:23:47.627 * +failover-state-wait-promotion slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379  (等待145的回应)
    7349:X 10 Dec 17:23:48.228 # +promoted-slave slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379  (成功将145提升为master)
    7349:X 10 Dec 17:23:48.228 # +failover-state-reconf-slaves master mymaster 10.10.101.146 6379 (修改配置)
    
    
  6. 145、146 的S 收到Leader(146 S)的通知,将master切换为145R

21880:X 10 Dec 17:23:48.285 # +config-update-from sentinel 10.10.101.146:26380 10.10.101.146 26380 @ mymaster 10.10.101.146 6379
21880:X 10 Dec 17:23:48.286 # +switch-master mymaster 10.10.101.146 6379 10.10.101.145 6379
  1. 145、146、147的S侦测到slave(147R、146R,注意,146R此时仍然被当做一个slave)

    7349:X 10 Dec 17:23:49.338 * +slave slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.145 6379
    7349:X 10 Dec 17:23:49.340 * +slave slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379
    
  2. 将146R客观下线(我们发现,对于slave并没有执行客观下线 +odown,也就是说:客观下线只适用于主服务器, 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商 。

7349:X 10 Dec 17:24:19.364 # +sdown slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379

用泳道图来描述,大概是这样子的

image.png

2. 重启down掉的master

原146R挂掉的时候,已经将145R提升了master,将146R退为slave,并标记为+down

重启146R

redis-server ./redis.conf

145S

2622:X 12 Dec 18:09:17.303 # -sdown slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379
2622:X 12 Dec 18:09:27.268 * +convert-to-slave slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379

147S

21880:X 12 Dec 18:09:17.287 # -sdown slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379

可以发现,一个slave的复活,只有一个-sdown

3. 关闭一个slave

我们现在shutdown掉146的 R

redis-cli -h 127.0.0.1 -p 6379 shutdown

145、147S

2622:X 12 Dec 18:24:27.177 # +sdown slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379

可以发现,slave down掉的时候S们并不需要协商,无须odown。

4. master正常,关闭一个Sentinel

执行以下指令

redis-cli -h 127.0.0.1 -p 26380 -a 123 shutdown

147 S 日志

21880:X 12 Dec 12:08:59.394 # +sdown sentinel 10.10.101.146:26380 10.10.101.146 26380 @ mymaster 10.10.101.145 6379

145 S 日志

2622:X 12 Dec 12:08:59.458 # +sdown sentinel 10.10.101.146:26380 10.10.101.146 26380 @ mymaster 10.10.101.145 6379

5. 重启down掉的sentinel

重新启动146的sentinel

redis-sentinel ./sentinel-26380.conf

145S

2622:X 12 Dec 18:12:43.730 * -dup-sentinel master mymaster 10.10.101.145 6379 #duplicate of 10.10.101.146:26380 or 99efa85df21767e8ee4a15a1894d01094bfd2ddb
2622:X 12 Dec 18:12:43.730 * +sentinel sentinel 10.10.101.146:26380 10.10.101.146 26380 @ mymaster 10.10.101.145 6379

147 S

21880:X 12 Dec 18:12:43.731 * -dup-sentinel master mymaster 10.10.101.145 6379 #duplicate of 10.10.101.146:26380 or 99efa85df21767e8ee4a15a1894d01094bfd2ddb
21880:X 12 Dec 18:12:43.731 * +sentinel sentinel 10.10.101.146:26380 10.10.101.146 26380 @ mymaster 10.10.101.145 6379

已挂掉的S重启,会提示-dup-sentinel,因为配置文件并不会把挂掉的配置移除,只是标记为+down

6. 结论

  • Redis下线分为主观下线(sdown)、客观下线(odown);
  • 当sentinel单位时间内监听不到slave的消息时,就会主观下线;监听不到master的消息时,先主观下线,然后由各个Sentinel协商,达到指定数量的Sentinel认定master下线,即可标记master客观下线;
  • 客观下线只适用于主服务器, 对于slave, Sentinel 在将它们判断为下线前不需要进行协商 。
  • redis master下线需要经过主观下线、协商、客观下线、选举Sentinel Leader、Leader发起投票、Leader指挥failover等过程;
  • master挂掉的时候,选举出新的master后,会把旧的master降级为slave,并标记主观下线(+sdwon);
  • 某个master/slave挂掉的时候,sentinel并不会将他们的信息移除,只是会标记为主观下线(+sdown),若该Redis实例重新上线的时候,将直接(-sdown)。

7. 小小的猜测

为什么slave down的时候,不需要客观下线呢?

我们知道,sentinel的数据是不分片的,只是冗余了几个slave。一般情况下,我们也不会在sentinel模式下对Redis做读写分离。每次需要操作Redis,从Sentinel中获取的实例都是Redis master节点。只要保证master是可用的,就一定不会有问题,所以也就不需要耗费时间去验证slave协商slave是否真的挂掉了。

附录1

145日志

[apps@mvxl8195 redis-3.0.0]$ tail -f 26379.log 
2622:X 21 Oct 07:12:21.028 # +sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 07:12:21.225 # -sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 07:43:28.463 # +sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 07:43:29.742 # -sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 07:48:44.978 # +sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 07:48:48.272 # -sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 07:53:04.249 # +sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 07:53:04.332 # -sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 08:33:29.834 # +sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
2622:X 21 Oct 08:33:36.789 # -sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
2622:X 10 Dec 17:23:47.228 # +sdown master mymaster 10.10.101.146 6379
2622:X 10 Dec 17:23:47.394 # +new-epoch 2
2622:X 10 Dec 17:23:47.395 # +vote-for-leader 22c7af0b9b4bdfbb79337ec9d46a90f925a2f308 2
2622:X 10 Dec 17:23:48.286 # +config-update-from sentinel 10.10.101.146:26380 10.10.101.146 26380 @ mymaster 10.10.101.146 6379
2622:X 10 Dec 17:23:48.286 # +switch-master mymaster 10.10.101.146 6379 10.10.101.145 6379
2622:X 10 Dec 17:23:48.287 * +slave slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.145 6379
2622:X 10 Dec 17:23:48.288 * +slave slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379
2622:X 10 Dec 17:24:18.362 # +sdown slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379

147日志

21880:X 21 Oct 05:15:22.731 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:15:35.515 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:33:42.970 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:34:14.079 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:35:40.013 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:36:11.227 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:38:16.866 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:38:18.895 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:54:08.848 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:55:07.052 # -sdown master mymaster 10.10.101.146 6
[apps@mvxl8197 redis-3.0.0]$ tail -f 26381.log 
21880:X 21 Oct 05:15:22.731 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:15:35.515 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:33:42.970 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:34:14.079 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:35:40.013 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:36:11.227 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:38:16.866 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:38:18.895 # -sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:54:08.848 # +sdown master mymaster 10.10.101.146 6
21880:X 21 Oct 05:55:07.052 # -sdown master mymaster 10.10.101.146 6
^C
[apps@mvxl8197 redis-3.0.0]$ tail -f 26381.log 
21880:X 21 Oct 05:15:22.731 # +sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:15:35.515 # -sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:33:42.970 # +sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:34:14.079 # -sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:35:40.013 # +sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:36:11.227 # -sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:38:16.866 # +sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:38:18.895 # -sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:54:08.848 # +sdown master mymaster 10.10.101.146 6379
21880:X 21 Oct 05:55:07.052 # -sdown master mymaster 10.10.101.146 6379
21880:X 10 Dec 17:23:47.381 # +new-epoch 2
21880:X 10 Dec 17:23:47.397 # +vote-for-leader 22c7af0b9b4bdfbb79337ec9d46a90f925a2f308 2
21880:X 10 Dec 17:23:48.285 # +config-update-from sentinel 10.10.101.146:26380 10.10.101.146 26380 @ mymaster 10.10.101.146 6379
21880:X 10 Dec 17:23:48.286 # +switch-master mymaster 10.10.101.146 6379 10.10.101.145 6379
21880:X 10 Dec 17:23:48.286 * +slave slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.145 6379
21880:X 10 Dec 17:23:48.287 * +slave slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379
21880:X 10 Dec 17:24:18.319 # +sdown slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379

146日志

7349:X 21 Oct 07:22:42.935 # +sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 07:22:43.037 # -sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 07:26:09.603 # +sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 07:26:09.979 # -sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 07:37:29.928 # +sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 07:37:31.268 # -sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 07:52:11.764 # +sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 07:52:27.137 # -sdown sentinel 10.10.101.147:26381 10.10.101.147 26381 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 08:51:55.420 # +sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
7349:X 21 Oct 08:51:56.738 # -sdown slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:47.243 # +sdown master mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:47.363 # +odown master mymaster 10.10.101.146 6379 #quorum 2/2
7349:X 10 Dec 17:23:47.363 # +new-epoch 2
7349:X 10 Dec 17:23:47.363 # +try-failover master mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:47.368 # +vote-for-leader 22c7af0b9b4bdfbb79337ec9d46a90f925a2f308 2
7349:X 10 Dec 17:23:47.393 # 10.10.101.145:26379 voted for 22c7af0b9b4bdfbb79337ec9d46a90f925a2f308 2
7349:X 10 Dec 17:23:47.397 # 10.10.101.147:26381 voted for 22c7af0b9b4bdfbb79337ec9d46a90f925a2f308 2
7349:X 10 Dec 17:23:47.431 # +elected-leader master mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:47.431 # +failover-state-select-slave master mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:47.561 # +selected-slave slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:47.561 * +failover-state-send-slaveof-noone slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:47.627 * +failover-state-wait-promotion slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:48.228 # +promoted-slave slave 10.10.101.145:6379 10.10.101.145 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:48.228 # +failover-state-reconf-slaves master mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:48.284 * +slave-reconf-sent slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:48.536 # -odown master mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:49.239 * +slave-reconf-inprog slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:49.239 * +slave-reconf-done slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:49.338 # +failover-end master mymaster 10.10.101.146 6379
7349:X 10 Dec 17:23:49.338 # +switch-master mymaster 10.10.101.146 6379 10.10.101.145 6379
7349:X 10 Dec 17:23:49.338 * +slave slave 10.10.101.147:6379 10.10.101.147 6379 @ mymaster 10.10.101.145 6379
7349:X 10 Dec 17:23:49.340 * +slave slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379
7349:X 10 Dec 17:24:19.364 # +sdown slave 10.10.101.146:6379 10.10.101.146 6379 @ mymaster 10.10.101.145 6379

Redis常用指令

redis-cli登录

redis-cli  -h 主机 -p 端口号 -a 密码 

启动redis-server

redis-server path(配置文件路径)

停止redis-server

redis-cli -h 主机 -p 端口号 -a 密码 shutdown

redis-cli下的指令

info  #查看redis相关信息
dbsize  #查看当前库中总数据条数
client list  #查看已连接的客户端信息