redis 哨兵(主从)

本文详细介绍了如何配置Redis Sentinel实现主从切换。首先,展示了主从配置文件及启动脚本,接着分析了哨兵配置文件中的关键参数,如quorum。通过模拟主Redis宕机,展示了哨兵如何自动选举新的主节点。最后,提供了Spring Boot应用中使用哨兵连接Redis的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主配置文件内容

port 8001
appendonly no
bind 192.168.59.129
requirepass "123456"
maxmemory 200mb
masterauth "123456"

另外两从配置文件

port 8002
appendonly no
bind 192.168.59.129
requirepass "123456"
maxmemory 200mb
masterauth "123456"
slaveof 192.168.59.129 8001
port 8003
appendonly no
bind 192.168.59.129
requirepass "123456"
maxmemory 200mb
masterauth "123456"

slaveof 192.168.59.129 8001

写一个启动脚本和停止脚本

start.sh

/home/redis-4.0.10/src/redis-server /home/redis-sentinel/redis8001.conf &
/home/redis-4.0.10/src/redis-server /home/redis-sentinel/redis8002.conf &
/home/redis-4.0.10/src/redis-server /home/redis-sentinel/redis8003.conf &

stop.sh

ps -ef | grep redis | grep -v grep | cut -c 9-15 | xargs kill -9

停止脚本的功能为,查询所有redis的pid,然后kill、如果服务器上面有不需要停止的redis不能这样用,这个会杀掉所有redis进程

执行start.sh 输出内容如下:

查看目前redis的启动状态 

启动完成之后、查询8001 8002 8003的状态

从信息看到8001为主redis 8002 8003为从redis

 

接下来配置哨兵

哨兵配置文件

sentinel monitor mymaster 192.168.59.129 8001 1
bind 192.168.59.129  
port 26879
sentinel failover-timeout mymaster 6000
sentinel auth-pass mymaster 123456

配置简单解析:第一行设置监控的实例名“mymaster” ip port + quorum , quorum为投票数量,当哨兵为集群的时候(比如哨兵为5个,那么设置值为3,如果哨兵为3个,那么设置值为2 ) 比如哈:有5个哨兵集群,并且quenum = 3,那么当5个哨兵中的3个哨兵都连接不上主redis的时候(并且时间达到了第四行配置的毫秒),他们3个就认为主redis挂了,然后就会对从redis进行选举,选举一个做主redis、当之前挂掉的主redis重新起来之后,就会降级为新的主redis的从redis.(我这里测试就是用了一个哨兵,所以quorum值也设置为1了)

最后一行配置 :因为主从redis都配置了密码所以,哨兵需要授权才能连接上主redis,这个设置为主redis的授权密码:

sentinel auth-pass mymaster 123456

接下来启动哨兵

/home/redis-4.0.10/src/redis-sentinel ./sentinel-single.conf &

从启动log中,能看到目前监控的主redis以及quorum值,当前的从redis等信息、(另外哨兵是不需要设置监控的从redis的,哨兵连接上主redis之后,会自动获取到从redis的信息)

接下来手动让主redis宕掉,模拟生产环境的情况

哨兵监测到8001已经宕掉了,然后选取了8003作为新的主redis

查看验证一下,是否现在8003为主reids

# Replication
role:master
connected_slaves:1
slave0:ip=192.168.59.129,port=8002,state=online,offset=158245,lag=1
master_replid:16cb18086466e4e40dc91e7dcb8f39b29712a9cc
master_replid2:e0d50a2843d0af2cd4304e4c415eb1131685fdbb
master_repl_offset:158245
second_repl_offset:149189
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:158245

查看8003目前是猪redis,从redis为8002(8001已经宕掉了),下面再讲8001启动,再查看信息

8003(主redis)信息如下

哨兵的日志

 

最后贴上 java 端 (spring boot)调用哨兵redis的代码

配置文件:SentinelRedisConfigurer.java


@Configuration
public class SentinelRedisConfigurer {

	@Bean(value = "sentinelConnnectionFactory")
	public RedisConnectionFactory sentinelConnnectionFactory() {
		Set<String> clusterNodes = new HashSet<>();
		clusterNodes.add("192.168.59.129:26879"); //指定哨兵的ip:port

		RedisSentinelConfiguration configuration = new RedisSentinelConfiguration("mymaster", clusterNodes);//设置住redis名称(就是哨兵配置里面配置的名称)
		configuration.setPassword(RedisPassword.of("123456")); //设置授权密码
		
		return new LettuceConnectionFactory(configuration);
	}
	@Bean(value="sentinelTemplate")
	public RedisTemplate<String, String> sentinelTemplate(@Qualifier("sentinelConnnectionFactory") RedisConnectionFactory factory){
		StringRedisTemplate redisTemplate = new StringRedisTemplate();
		redisTemplate.setConnectionFactory(factory);
		Jackson2JsonRedisSerializer<Object> jsonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
		
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jsonSerializer.setObjectMapper(om);
		
		redisTemplate.setValueSerializer(jsonSerializer);
		return redisTemplate;
	}
}

测试代码 TestSentinel.java

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SentinelRedisConfigurer.class)
public class TestSentinel {

	@Resource(name = "sentinelTemplate")
	private RedisTemplate<String, String> template1;
	@Resource(name = "sentinelConnnectionFactory")
	private RedisConnectionFactory sentinelConnnectionFactory;
	
	private String key = "hello8";
	@Test
	public void test1() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				while(true) {
					try {
						Thread.sleep(1000);
						template1.opsForValue().set(key, "world");
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				while(true) {
					try {
						Thread.sleep(1000);
						System.out.println(template1.opsForValue().get(key));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		});
		t1.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

启动之后、输入日志:

当停止主redis之后会在一段时间内会输出错误日志(这段时间内,哨兵还没有选举出主redis所以会输出错误日志),然后又可以正常访问了(哨兵已经选举出新的主redis)

key:hello874, value: world74
key:hello875, value: world75
key:hello876, value: world76
key:hello877, value: world77
key:hello878, value: world78
key:hello879, value: world79
key:hello880, value: world80
key:hello881, value: world81
key:hello882, value: world82
key:hello883, value: world83
key:hello884, value: world84
key:hello885, value: world85
2018-07-24 11:17:27.421  INFO 15500 --- [xecutorLoop-1-2] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was /192.168.59.129:8003
2018-07-24 11:17:28.430  WARN 15500 --- [ioEventLoop-4-4] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.59.129:8003
2018-07-24 11:17:32.919  INFO 15500 --- [xecutorLoop-1-7] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.59.129:8003
2018-07-24 11:17:33.936  WARN 15500 --- [ioEventLoop-4-6] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.59.129:8003
2018-07-24 11:17:38.118  INFO 15500 --- [xecutorLoop-1-3] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.59.129:8003
2018-07-24 11:17:39.129  WARN 15500 --- [ioEventLoop-4-6] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.59.129:8003
2018-07-24 11:17:43.318  INFO 15500 --- [xecutorLoop-1-5] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.59.129:8003
2018-07-24 11:17:44.328  WARN 15500 --- [ioEventLoop-4-2] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.59.129:8003
2018-07-24 11:17:48.518  INFO 15500 --- [xecutorLoop-1-6] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.59.129:8003
2018-07-24 11:17:49.534  WARN 15500 --- [ioEventLoop-4-4] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.59.129:8003
2018-07-24 11:17:57.817  INFO 15500 --- [xecutorLoop-1-7] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.59.129:8003
2018-07-24 11:17:58.828  WARN 15500 --- [ioEventLoop-4-6] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.59.129:8003
2018-07-24 11:18:15.218  INFO 15500 --- [xecutorLoop-1-8] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.59.129:8003
2018-07-24 11:18:15.238  INFO 15500 --- [ioEventLoop-4-8] i.l.core.protocol.ReconnectionHandler    : Reconnected to 192.168.59.129:8001
key:hello886, value: world86
key:hello887, value: world87
key:hello888, value: world88
key:hello889, value: world89
key:hello890, value: world90
key:hello891, value: world91
key:hello891, value: world91
key:hello892, value: world93
key:hello893, value: world93
key:hello894, value: world94
key:hello895, value: world95
key:hello896, value: world96
key:hello897, value: world97
key:hello898, value: world98

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值