哨兵机制
- 为什么需要哨兵机制
- 哨兵机制的原理是什么
- 如何配置哨兵机制
- 总结
- 问题
- JavaAPI连接主从+ 哨兵
为什么需要哨兵机制
- 在上面讲到的Redis集群-主从复制模式下
- 可以实现容灾备份和读写分离
- 但是做不到真正的高可用
- 如Master挂了,整个集群就只能提供读服务了, 不能够提供写服务
- 所以需要有一个新的方案来解决这个问题
- 这个方案就是Redis提出的哨兵机制Sentinel
哨兵机制的原理是什么
- 如下图:
- 在配置好了Master-Slave的基础之上,再增加一些哨兵进程
- 用来监控各个节点(主要监控当前的Master节点)
- 当有节点(Master)挂了,就会从该Master下属的Slave节点中选取一个作为新的Master(选取规则就不一定,很随机)
- 注意:哨兵只做监控和选择slave作为新的master,哨兵不是备胎不会替代成为master
其实哨兵本质是就是一个后台进程,不断的和redis服务做通信/心态检测
如何配置哨兵机制
- 1.三台机器修改哨兵配置文件
cd /export/servers/redis/conf
vim sentinel.conf
- 2.node01上
#修改bind配置,每台机器修改为自己对应的主机名
bind node01
#配置sentinel服务后台运行
daemonize yes
#修改三台机器监控的主节点,现在主节点是node01服务器
sentinel monitor mymaster node01 6379 2
#sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,node01代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作
# sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
# sentinel auth-pass <master-name> <password>
- 2.node02上
#修改bind配置,每台机器修改为自己对应的主机名
bind node02
#配置sentinel服务后台运行
daemonize yes
#修改三台机器监控的主节点,现在主节点是node01服务器
sentinel monitor mymaster node01 6379 2
#sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,node01代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作
# sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
# sentinel auth-pass <master-name> <password>
- 3.node03上
#修改bind配置,每台机器修改为自己对应的主机名
bind node03
#配置sentinel服务后台运行
daemonize yes
#修改三台机器监控的主节点,现在主节点是node01服务器
sentinel monitor mymaster node01 6379 2
#sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,node01代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作
# sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
# sentinel auth-pass <master-name> <password>
- 4.重启三台redis
/export/servers/redis/bin/redis-server /export/servers/redis/conf/redis_6379.conf
- 5.启动三台机器上的哨兵
/export/servers/redis/bin/redis-sentinel /export/servers/redis/conf/sentinel.conf
- 6.查看启动情况
ps -ef | grep redis
- 7.使用客户端连接
/export/servers/redis/bin/redis-cli -h node01
/export/servers/redis/bin/redis-cli -h node02
/export/servers/redis/bin/redis-cli -h node03
- 8.查看各自的角色
- 9.干掉node01上的master
ps -ef | grep redis
kill -9 redis-server的进程号
- 10.过几秒观察发现node02或node03变成了master
- 11.再次启动node01的redis会发现他只能做slave了
总结
- 开发中一般都是 主从+ 哨兵 就可以满足大部分场景
- 如果还需对redis做扩展可以再使用后面讲解的Redis集群-Cluster-终极版集群
问题
- 之前是java代码连接的还是单机的redis
- 那么开发中一般都是主从+ 哨兵 ,那么该如何连接呢?
JavaAPI连接主从+ 哨兵
@Test
public void testMasterSlaveAndSentinel(){
//1.创建连接池配置对象
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(100);//设置最大连接
jedisPoolConfig.setMaxIdle(10);//设置最大空闲连接数
jedisPoolConfig.setMinIdle(5);//设置最小空闲连接数
jedisPoolConfig.setMaxWaitMillis(2000);//最大等待时间
jedisPoolConfig.setTestOnCreate(true);
jedisPoolConfig.setTestOnBorrow(true);
jedisPoolConfig.setTestOnReturn(true);
//2.创建连接池对象
//准备哨兵地址,注意哨兵的默认端口是26379
Set<String> sentinels = new HashSet<>(Arrays.asList("node01:26379","node02:26379","node03:26379"));
JedisSentinelPool jedisSentinelPool = new JedisSentinelPool("mymaster", sentinels, jedisPoolConfig);
//3.从连接池中获取连接对象jedis
Jedis jedis = jedisSentinelPool.getResource();
//4.操作
String pong = jedis.ping();
System.out.println(pong);
//5.归还连接
jedis.close();
}
- JedisUtil也可以进行相应的修改
package cn.hanjiaxiaozhi;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Author hanjiaxiaozhi
* Date 2020/7/7 16:43
* Desc 封装jedis工具类
* 工具类一般都是使用类名.方法名就可以使用
* 也就是说不需要创建对象就可以使用,那么该类最好设计成一个抽象类,因为抽象类别人不能直接new
* 然后里面的方法设置为静态方法即可,这样别人就可以直接使用类名.方法名
*/
public abstract class JedisUtil {
//将连接池对象提取出来,只需要在类初始化的时候创建一次即可
private static JedisSentinelPool jedisSentinelPool;
//static静态代码块只会在类被加载(第一次被使用的时候执行)
static{
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(100);//设置最大连接
jedisPoolConfig.setMaxIdle(10);//设置最大空闲连接数
jedisPoolConfig.setMinIdle(5);//设置最小空闲连接数
jedisPoolConfig.setMaxWaitMillis(2000);//最大等待时间
jedisPoolConfig.setTestOnCreate(true);
jedisPoolConfig.setTestOnBorrow(true);
jedisPoolConfig.setTestOnReturn(true);
//jedisPool = new JedisPool(jedisPoolConfig, "node01", 6379);
Set<String> sentinels = new HashSet<>(Arrays.asList("node01:26379","node02:26379","node03:26379"));
jedisSentinelPool = new JedisSentinelPool("mymaster", sentinels, jedisPoolConfig);
}
public static Jedis getJedis(){
return jedisSentinelPool.getResource();
}
}