0032【Redis】简单玩玩从Redis单机扩展到一主二从三哨兵模式
二 一主二从三哨兵
端口配置:
主:6371
从1:6372
从2:6373
哨兵1:26371
哨兵2:26372
哨兵3:26373
2.1 一主
2.1.1 配置
port 6371
bind 192.168.0.101
dir /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/3-data
pidfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/2-pid/redis-6371-master.pid
logfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/5-logs/redis-6371-master.log
appendfilename "appendonly-6371-master.aof"
dbfilename dump-6371-master.rdb
requirepass "gzst2022"
masterauth "gzst2022"
2.1.2 启动
/Users/chyzhong/01-worktools/08-redis-6.0.8/bin/redis-server /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/1-conf/redis-6371-master.conf
2.2 二从
2.2.1 从1配置
port 6372
bind 192.168.0.101
dir /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/3-data
pidfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/2-pid/redis-6372-slave.pid
logfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/5-logs/redis-6372-slave.log
appendfilename appendonly-6372-slave.aof
dbfilename dump-6372-slave.rdb
requirepass "gzst2022"
masterauth "gzst2022"
slaveof 192.168.0.101 6371
2.2.2 从2配置
port 6373
bind 192.168.0.101
dir /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/3-data
pidfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/2-pid/redis-6373-slave.pid
logfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/5-logs/redis-6373-slave.log
appendfilename appendonly-6373-slave.aof
dbfilename dump-6373-slave.rdb
requirepass "gzst2022"
masterauth "gzst2022"
slaveof 192.168.0.101 6371
2.2.3 启动
/Users/chyzhong/01-worktools/08-redis-6.0.8/bin/redis-server /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/1-conf/redis-6372-slave.conf
/Users/chyzhong/01-worktools/08-redis-6.0.8/bin/redis-server /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/1-conf/redis-6373-slave.conf
2.3 三哨兵
2.3.1 哨兵1配置
port 26371
bind 192.168.0.101
sentinel monitor mymaster 192.168.0.101 6371 2
sentinel auth-pass mymaster gzst2022
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000
protected-mode no
daemonize yes
pidfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/2-pid/redis-26371-sentinel.pid
dir /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/3-data
logfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/5-logs/redis-26371-sentinel.log
2.3.2 哨兵2配置
port 26372
bind 192.168.0.101
sentinel monitor mymaster 192.168.0.101 6371 2
sentinel auth-pass mymaster gzst2022
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000
protected-mode no
daemonize yes
pidfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/2-pid/redis-26372-sentinel.pid
dir /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/3-data
logfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/5-logs/redis-26372-sentinel.log
2.3.3 哨兵3配置
port 26373
bind 192.168.0.101
sentinel monitor mymaster 192.168.0.101 6371 2
sentinel auth-pass mymaster gzst2022
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000
protected-mode no
daemonize yes
pidfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/2-pid/redis-26373-sentinel.pid
dir /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/3-data
logfile /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/5-logs/redis-26373-sentinel.log
2.3.4 启动
/Users/chyzhong/01-worktools/08-redis-6.0.8/bin/redis-server /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/1-conf/redis-26371-sentinel.conf --sentinel
/Users/chyzhong/01-worktools/08-redis-6.0.8/bin/redis-server /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/1-conf/redis-26372-sentinel.conf --sentinel
/Users/chyzhong/01-worktools/08-redis-6.0.8/bin/redis-server /Users/chyzhong/01-worktools/08-redis-6.0.8-cluster/1-conf/redis-26373-sentinel.conf --sentinel
另外配置内部会自动生成 sentinel myid 值。
2.4 测试redis运行情况
2.4.1 测试主库
cd /Users/chyzhong/01-worktools/08-redis-6.0.8/bin
->redis-cli -h 192.168.0.101 -p 6371 -a gzst2022
->info replication
或者:
-> redis-cli -h 192.168.0.101 -p 6371 -a gzst2022 info replication
role:master
connected_slaves:2
slave0:ip=192.168.0.101,port=6372,state=online,offset=51471,lag=1
slave1:ip=192.168.0.101,port=6373,state=online,offset=51471,lag=1
master_replid:ed3f6f9e37f49953cfc89bb7957630414b3dd8e6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:51626
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:51626
2.4.2 测试从库
->redis-cli -h 192.168.0.101 -p 6372 -a gzst2022 info replication
->redis-cli -h 192.168.0.101 -p 6373 -a gzst2022 info replication
role:slave
master_host:192.168.0.101
master_port:6371
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:68503
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:ed3f6f9e37f49953cfc89bb7957630414b3dd8e6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:68503
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:68503
role:slave
master_host:192.168.0.101
master_port:6371
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:73057
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:ed3f6f9e37f49953cfc89bb7957630414b3dd8e6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:73057
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:73043
2.4.3 测试哨兵
->redis-cli -h 192.168.0.101 -p 26371 -a gzst2022
->info sentinel
或者:
--> redis-cli -h 192.168.0.101 -p 26371 -a gzst2022 info sentinel
异常:
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=sdown,address=192.168.0.101:6371,slaves=0,sentinels=1
正常:
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.0.101:6371,slaves=2,sentinels=3
->redis-cli -h 192.168.0.101 -p 26372 -a gzst2022
->info sentinel
或者:
-> redis-cli -h 192.168.0.101 -p 26372 -a gzst2022 info sentinel
异常:
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=sdown,address=192.168.0.101:6371,slaves=0,sentinels=1
正常:
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.0.101:6371,slaves=2,sentinels=3
->redis-cli -h 192.168.0.101 -p 26373 -a gzst2022
->info sentinel
或者:
-> redis-cli -h 192.168.0.101 -p 26373 -a gzst2022 info sentinel
异常:
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=sdown,address=192.168.0.101:6371,slaves=0,sentinels=1
正常:
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.0.101:6371,slaves=2,sentinels=3
2.4.4 telnet 测试端口
telnet 192.168.0.101 26371
telnet 192.168.0.101 26372
telnet 192.168.0.101 26373
2.5 异常
2.5.1 命令异常
1. status=sdown.....,slaves=0,sentinels=1
是因为哨兵配置文件没有配置sentinel auth-pass mymaster gzst2022
2. redis哨兵启动报错No such master with specified name
原因是配置的顺序,也就是我们监听的时候,是需要先配置监听master,给master取一个名字叫mymaster,才能配置这个认证节点的密码。但是认配置是密码在前面,监听配置在后面,这样就会报这个错,调整一下即可。
2.5.2 Java异常
1. NOAUTH Authentication required.. Trying next one.
解决:哨兵不要设置密码。
2. 警告: Cannot get master address from sentinel running @ 192.168.0.101:26372. Reason: redis.clients.jedis.exceptions.JedisDataException: NOAUTH Authentication required.. Trying next one.
Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: All sentinels down, cannot determine where is mymaster master is running...
2.6 应用
2.6.1 Java工具类
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(10);
jedisPoolConfig.setMaxIdle(5);
jedisPoolConfig.setMinIdle(5);
Set<String> sentinelSet = new HashSet<>();
sentinelSet.add("192.168.0.101:26371");
sentinelSet.add("192.168.0.101:26372");
sentinelSet.add("192.168.0.101:26373");
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinelSet, jedisPoolConfig, "gzst2022");
Jedis jedis = pool.getResource();
jedis.set("mykey", "myvalue");
String myvalue = jedis.get("mykey");
System.out.println(myvalue);
2.6.2 SpringBoot配置
2.6.2.1 yaml配置
spring:
redis:
sentinel:
nodes: 192.168.0.101:26371,192.168.0.101:26372,192.168.0.101:26373
master: mymaster
database: 6
timeout: 10000
password: gzst2022
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
2.6.2.2 Java代码
2.6.2.2.1 配置类
注意:配置的密码。
package com.tiannan.demo.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.redisson.config.SentinelServersConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Configuration
@EnableAutoConfiguration
public class RedisConfig {
@Autowired
RedisProperties redisProperties;
@Bean
public JedisPoolConfig getRedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMaxIdle());
jedisPoolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMinIdle());
jedisPoolConfig.setMaxWaitMillis(redisProperties.getJedis().getPool().getMaxWait().getSeconds());
return jedisPoolConfig;
}
@Bean
public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
redisSentinelConfiguration.setMaster(redisProperties.getSentinel().getMaster());
redisSentinelConfiguration.setDatabase(redisProperties.getDatabase());
redisSentinelConfiguration.setSentinels(getSentinelNodes());
redisSentinelConfiguration.setPassword(redisProperties.getPassword());
JedisConnectionFactory objJedisConnectionFactory = new JedisConnectionFactory(redisSentinelConfiguration, jedisPoolConfig);
return objJedisConnectionFactory;
}
@Bean
public JedisSentinelPool getJedisPool() {
Set<String> newNodes = new HashSet<>();
for (int i = 0; i < redisProperties.getSentinel().getNodes().size(); i++) {
newNodes.add(redisProperties.getSentinel().getNodes().get(i));
}
JedisSentinelPool pool = new JedisSentinelPool(redisProperties.getSentinel().getMaster(), newNodes, getRedisPoolConfig(), Long.valueOf(redisProperties.getTimeout().toMillis()).intValue(), redisProperties.getPassword(), redisProperties.getDatabase());
return pool;
}
@Bean
public Set<RedisNode> getSentinelNodes() {
Set<RedisNode> nodos = new HashSet<>();
for (int i = 0; i < redisProperties.getSentinel().getNodes().size(); i++) {
String[] split = redisProperties.getSentinel().getNodes().get(i).split(":");
nodos.add(new RedisNode(split[0], Integer.parseInt(split[1])));
}
return nodos;
}
@Bean
public RedissonClient createSentinelRedissonClient() {
Config config = new Config();
List<String> newNodes = new ArrayList<>();
for (int i = 0; i < redisProperties.getSentinel().getNodes().size(); i++) {
newNodes.add("redis://" + redisProperties.getSentinel().getNodes().get(i));
}
SentinelServersConfig serverConfig = config.useSentinelServers()
.addSentinelAddress(newNodes.toArray(new String[0]))
.setMasterName(this.redisProperties.getSentinel().getMaster())
.setReadMode(ReadMode.SLAVE)
.setTimeout(60000)
.setRetryAttempts(3)
.setRetryInterval(60000)
.setPingConnectionInterval(60000)
.setDatabase(redisProperties.getDatabase())
.setPassword(redisProperties.getPassword());
return Redisson.create(config);
}
}
2.6.2.2.2 服务类
package com.tiannan.demo.service;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
@Service
public class JedisService {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
JedisSentinelPool jedisSentinelPool;
public Jedis getResource() {
return jedisSentinelPool.getResource();
}
public void returnResource(Jedis jedis) {
if(jedis != null){
//edisPool.returnResourceObject(jedis);
jedis.close();
}
}
public void set(String key, String value) {
Jedis jedis = null;
try{
jedis = getResource();
jedis.set(key, value);
logger.info("Redis set success - " + key + ", value:" + value);
} catch (Exception e) {
e.printStackTrace();
logger.error("Redis set error: "+ e.getMessage() +" - " + key + ", value:" + value);
}finally{
if(jedis!=null){
returnResource(jedis);
}
}
}
public String get(String key) {
String result = null;
Jedis jedis=null;
try{
jedis = getResource();
result = jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
logger.error("Redis set error: "+ e.getMessage() +" - " + key + ", value:" + result);
}finally{
if(jedis!=null){
returnResource(jedis);
}
}
return result;
}
}
2.6.2.2.3 测试类
package com.tiannan.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.tiannan.demo.service.JedisService;
@SpringBootTest
class SpringBootRedis04SentinelApplicationTests {
@Autowired
private JedisService jedisService;
@Test
public void test01() {
jedisService.set("username", "张三");
String sex = jedisService.get("username");
System.out.println(sex);
}
}
|