四、哨兵(Sentinel)模式
1、哨兵是什么能干嘛?
反客为主的自动版,能够自动监控master是否发生故障,如果故障了会根据投票数从slave中挑选一个作为master,其他的slave会自动转向同步新的master,实现故障自动转义。
2、哨兵(Sentinel)模式原理
多个哨兵之间也存在互相监控,这就形成了多哨兵模式,现在对该模式的工作过程进行讲解,介绍如下:
对上对述过程做简单总结:
3、搭建1主2从3个哨兵
下面我们来实现1主2从以及3个sentinel的配置,当从的挂掉之后,要求最少有2个sentinel认为主的挂掉了,才进行故障转移。
为了方便,我们在一台机器上进行模拟,通过端口来区分6个不同的节点(1个master、2个slave、3个sentinel),节点配置信息如下
3.1、创建3个sentinel配置文件
我们直接就是基于上面的 1主2从 的 主从复制 配置然后给他配置3个sentinel哨兵。
(1)创建sentinel1的配置文件:sentinel-26379.conf
在/opt/redis-stable/config目录创建 sentinel-26379.conf 文件,内容如下
cd /opt/redis-stable/config/
touch sentinel-26379.conf
vi sentinel-26379.conf
bind 0.0.0.0
# 配置文件目录
dir /opt/redis-stable/config/
# 日志文件位置
logfile "./sentinel-26379.log"
# pid文件
pidfile /var/run/sentinel_26379.pid
# 是否后台运行
daemonize yes
# 端口
port 26379
# 监控主服务器master的名字:mymaster,IP:127.0.0.1,port:6379,最后的数字2表示当Sentinel集群中有2个Sentinel认为master存在故障不可用,则进行自动故障转移
sentinel monitor mymaster 127.0.0.1 6379 2
# master响应超时时间(毫秒),Sentinel会向master发送ping来确认master,如果在20秒内,ping不通master,则主观认为master不可用
sentinel down-after-milliseconds mymaster 20000
# 故障转移超时时间(毫秒),如果3分钟内没有完成故障转移操作,则视为转移失败
sentinel failover-timeout mymaster 180000
# 故障转移之后,进行新的主从复制,配置项指定了最多有多少个slave对新的master进行同步,那可以理解为1是串行复制,大于1是并行复制
sentinel parallel-syncs mymaster 1
# 指定mymaster主的密码(没有就不指定)
sentinel auth-pass mymaster 123456
(2)创建sentinel2的配置文件:sentinel-26380.conf
touch sentinel-26380.conf
vi sentinel-26380.conf
bind 0.0.0.0
# 配置文件目录
dir /opt/redis-stable/config/
# 日志文件位置
logfile "./sentinel-26380.log"
# pid文件
pidfile /var/run/sentinel_26380.pid
# 是否后台运行
daemonize yes
# 端口
port 26380
# 监控主服务器master的名字:mymaster,IP:127.0.0.1,port:6379,最后的数字2表示当Sentinel集群中有2个Sentinel认为master存在故障不可用,则进行自动故障转移
sentinel monitor mymaster 127.0.0.1 6379 2
# master响应超时时间(毫秒),Sentinel会向master发送ping来确认master,如果在20秒内,ping不通master,则主观认为master不可用
sentinel down-after-milliseconds mymaster 20000
# 故障转移超时时间(毫秒),如果3分钟内没有完成故障转移操作,则视为转移失败
sentinel failover-timeout mymaster 180000
# 故障转移之后,进行新的主从复制,配置项指定了最多有多少个slave对新的master进行同步,那可以理解为1是串行复制,大于1是并行复制
sentinel parallel-syncs mymaster 1
# 指定mymaster主的密码(没有就不指定)
sentinel auth-pass mymaster 123456
(3)创建sentinel3的配置文件:sentinel-26381.conf
touch sentinel-26381.conf
vi sentinel-26381.conf
bind 0.0.0.0
# 配置文件目录
dir /opt/redis-stable/config/
# 日志文件位置
logfile "./sentinel-26381.log"
# pid文件
pidfile /var/run/sentinel_26381.pid
# 是否后台运行
daemonize yes
# 端口
port 26381
# 监控主服务器master的名字:mymaster,IP:127.0.0.1,port:6379,最后的数字2表示当Sentinel集群中有2个Sentinel认为master存在故障不可用,则进行自动故障转移
sentinel monitor mymaster 127.0.0.1 6379 2
# master响应超时时间(毫秒),Sentinel会向master发送ping来确认master,如果在20秒内,ping不通master,则主观认为master不可用
sentinel down-after-milliseconds mymaster 20000
# 故障转移超时时间(毫秒),如果3分钟内没有完成故障转移操作,则视为转移失败
sentinel failover-timeout mymaster 180000
# 故障转移之后,进行新的主从复制,配置项指定了最多有多少个slave对新的master进行同步,那可以理解为1是串行复制,大于1是并行复制
sentinel parallel-syncs mymaster 1
# 指定mymaster主的密码(没有就不指定)
sentinel auth-pass mymaster 123456
3.2、启动3个sentinel
启动sentinel有2种方式
下面我们使用方式2来启动3个sentinel
/opt/redis-stable/src/redis-sentinel /opt/redis-stable/config/sentinel-26379.conf
/opt/redis-stable/src/redis-sentinel /opt/redis-stable/config/sentinel-26380.conf
/opt/redis-stable/src/redis-sentinel /opt/redis-stable/config/sentinel-26381.conf
分别对3个sentinel执行下面命令,查看每个sentinel的信息
sentinel1 的信息如下,其他2个sentinel的信息这里就不列了,大家自己去看一下
3.3、使用Redis DeskTop连接sentinel
使用windows当中的Redis DeskTop客户端可以通过连接哨兵来操作redis。
本质上他就是通过哨兵来获取到的Redis的主机,然后相当于是直接连接的Redis主机!
3.4、验证故障自动转移是否成功
(1)在master中执行下面命令,停止master
(2)等待2分钟,等待完成故障转移
sentinel中我们配置 down-after-milliseconds 的值是20秒,表示判断主机下线时间是20秒,所以我们等2分钟,让系统先自动完成故障转移。
(3)查看slave1的主从信息,如下
(4)查看slave2的主从信息,如下
slave2变成master了,且slave2变成slave1的从库了,完成了故障转移。
(5)redis的配置文件以及哨兵的配置文件都发生了变化:
(6)下面验证下slave1和slave2是否同步
在slave2中执行下面命令
127.0.0.1:6381>set address china
OK
在slave1中执行下面命令,查询一下address的值,效果如下,说明slave2和slave1同步正常
3.4、恢复旧的master自动俯首称臣
当旧的master恢复之后,会自动挂在新的master下面,咱们来验证下是不是这样的。
(1)执行下面命令,启动旧的master
2)执行下面命令,连接旧的master
(3)执行下面命令,查看其主从信息:info replication
效果如下,确实和期望的一致。
4、Sentinel支持的命令
哨兵节点作为运行在特殊模式下的redis节点,其支持的命令与普通的redis节点不同。在运维中,我们可以通过这些命令查询或修改哨兵系统;不过更重要的是,哨兵系统要实现故障发现、故障转移等各种功能,离不开哨兵节点之间的通信,而通信的很大一部分是通过哨兵节点支持的命令来实现的。下面介绍哨兵节点支持的主要命令。
(1)基础查询:通过这些命令,可以查询哨兵系统的拓扑结构、节点信息、配置信息等。
(2)增加/移除对主节点的监控
(3)强制故障转移
五、Jedis连接Sentinel模式
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import java.util.HashSet;
import java.util.Set;
public class SentinelDemo {
private static JedisSentinelPool jedisSentinelPool;
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
//最大空闲连接数, 默认8个
config.setMaxIdle(8);
//最大连接数, 默认8个
config.setMaxTotal(8);
//最小空闲连接数, 默认0
config.setMinIdle(0);
//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
config.setMaxWaitMillis(3000);
//在获取连接的时候检查有效性,表示取出的redis对象可用, 默认false
config.setTestOnBorrow(true);
//redis服务器列表
SetString> sentinels = new HashSet();
sentinels.add(new HostAndPort("192.168.115.78", 26379).toString());
sentinels.add(new HostAndPort("192.168.115.78", 26380).toString());
sentinels.add(new HostAndPort("192.168.115.78", 26381).toString());
//初始化连接池
jedisSentinelPool = new JedisSentinelPool("mymaster", sentinels, config, "123456");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 从池中获取一个Jedis对象
Jedis jedis = jedisSentinelPool.getResource();
String aaa = jedis.get("aaa");
System.out.println(aaa);
jedis.close();
}
}
六、SpringBoot整合Sentinel模式
(1)引入redis的maven配置
(2)application.properties中配置redis sentinel信息
(3)使用RedisTemplate工具类操作redis
springboot中使用RedisTemplate来操作redis,需要在我们的bean中注入这个对象,代码如下:
private RedisTemplate redisTemplate;
// 用下面5个对象来操作对应的类型
this.redisTemplate.opsForValue(); //提供了操作string类型的所有方法
this.redisTemplate.opsForList(); // 提供了操作list类型的所有方法
this.redisTemplate.opsForSet(); //提供了操作set的所有方法
this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法
this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法
(4)RedisTemplate示例代码
public class RedisController {
private RedisTemplate redisTemplate;
/**
* string测试
*
* @return
*/
public String stringTest() {
this.redisTemplate.delete("name");
this.redisTemplate.opsForValue().set("name", "路人");
String name = this.redisTemplate.opsForValue().get("name");
return name;
}
/**
* list测试
*
* @return
*/
public List listTest() {
this.redisTemplate.delete("names");
this.redisTemplate.opsForList().rightPushAll("names", "刘德华", "张学友",
"郭富城", "黎明");
List courses = this.redisTemplate.opsForList().range("names", 0,
-1);
return courses;
}
/**
* set类型测试
*
* @return
*/
public Set setTest() {
this.redisTemplate.delete("courses");
this.redisTemplate.opsForSet().add("courses", "java", "spring",
"springboot");
Set courses = this.redisTemplate.opsForSet().members("courses");
return courses;
}
/**
* hash表测试
*
* @return
*/
public Map
this.redisTemplate.delete("userMap");
Map map = new HashMap();
map.put("name", "路人");
map.put("age", "30");
this.redisTemplate.opsForHash().putAll("userMap", map);
Map
this.redisTemplate.opsForHash().entries("userMap");
return userMap;
}
/**
* zset测试
*
* @return
*/
public Set zsetTest() {
this.redisTemplate.delete("languages");
this.redisTemplate.opsForZSet().add("languages", "java", 100d);
this.redisTemplate.opsForZSet().add("languages", "c", 95d);
this.redisTemplate.opsForZSet().add("languages", "php", 70);
Set languages =
this.redisTemplate.opsForZSet().range("languages", 0, -1);
return languages;
}
/**
* 查看redis机器信息
*
* @return
*/
public String info() {
Object obj = this.redisTemplate.execute(new RedisCallback
public Object doInRedis(RedisConnection connection) throws
DataAccessException {
return connection.execute("info");
}
});
return obj.toString();
}
5)访问的时候出现如下异常
解决方案:在redis.conf 当中将no-writes-on-bgsave-error设置为 no
版权声明:本文内容始发于CSDN>作者:怪 咖@,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
始发链接:https://blog.csdn.net/weixin_43888891/article/details/131039418
在此特别鸣谢原作者的创作。
此篇文章的所有版权归原作者所有,商业转载建议请联系原作者,非商业转载请注明出