目录
1.基本概念
(1)哨兵(Sentinel)机制核心作用
主服务器出现问题的时候,客户端才会询问哨兵;
正常情况下,客户端直接和主服务器直接连接。
(2)核心运作流程
- 服务器发现和监控检查流程
实现方式:
#运行客户端
[root@localhost redis]# ./bin/redis-cli -p 26380
#客户端发送命令,向哨兵询问主服务器信息:
127.0.0.1:26380> SENTINEL get-master-addr-by-name mymaster
1) "192.168.11.130"
2)"6380"
#哨兵读取配置文件,监控redis实例
[root@localhost redis]# cat conf/sentinel-26380.conf
-
故障切换流程
实现方式 :7大核心概念 -
①哨兵如何知道Redis主从信息(自动发现机制)
哨兵配置文件中,保存着主从集群中master的信息,可以通过info replication
命令,进行主从信息自动发现。 -
②什么是master主观下线
主观下线:单个哨兵
自身认为redis实例已经不能提供服务
检测机制:哨兵向redis发送ping请求,+PONG、 -LOADING、 -MASTERDOWN这三种情况视为正常,其他回复均视为无效。 -
③什么是客观下线
客观下线:一定数量值
的哨兵认为master已经下线
检测机制:当哨兵主观认为master下线后,则会 通过SENTINEL is-master-down-by-addr
命令询问其他哨兵是否认为
master已经下线,如果达成共识(达到quorum个数),则会认为master节点客观下线,开始故障转移流程。
对应配置文件的配置项:sentinel monitor mymaster 192.168.11.131 6380 2 -
④哨兵之间如何通信(哨兵之间的自动发现)
-
⑤哪个哨兵负责故障转移?(哨兵领导选举机制)
基于Raft算法实现的选举机制,流程简述如下:
拉票阶段:每个哨兵节点都希望自己成为领导者;
sentinel节点接收到拉票命令后,如果没有接收到或同意过其他sentinel节点的请求,就同意该sentinel的请求(每个sentinel只持有一个同意票数);
如果sentinel节点发现自己的票数已经超过一半的数值,那么它就成为领导者,去执行故障转移;
投票结束后,如果超过failover-timeout的时间内,没进行实际的故障转移操作,则重新拉票选举。
点击查看raft协议图示
- ⑥slave选举机制
从服务器示例中,按顺序依次筛选:
slave节点状态,非S_DOWN,O_DOWN,DISCONNECTED
判断规则:(down-after-milliseconds * 10)+milliseconds_since_master_is_in_SDOWN_state
SENTINEL slaves mymaster
优先级
redis.conf中一个配置项:slave-priority值越小,优先级越高
数据同步情况
Replication offset processed
最小的run id
run id比较方案:字典顺序,ASCII码
- ⑦最终主从切换的过程
针对即将成为master的slave节点,将其撤出主从集群
自动执行:slaveof NO ONE
针对其他slave节点,使它们成为新master的从属
自动执行:slaveof new_master_host new_master_port
哨兵服务部署方案
不建议
两个哨兵;客观下线=主管下线,哨兵可能会出现误判。
建议
1主2从,2个哨兵。
但是1主2从仍然会出现问题:
网络分区下,可能会出现数据不一致或丢失。Redis集群非强一致。
网络不通时,可能出现两个主服务器;网络联通后,选择最新的主服务器,每次会生成一个版本。
高可用每次选举都会有一次版本更新,选择版本高的服务器。
2.配置服务器集群、哨兵高可用集群
(1)下载安装Redis
$ wget http://download.redis.io/releases/redis-6.0.5.tar.gz
$ tar xzf redis-6.0.5.tar.gz
$ cd redis-6.0.5
$ make
(2)创建文件夹
mdkir /usr/local/redis/conf
mdkir /usr/local/redis/data
mdkir /usr/local/redis/logs
(3)准备服务器配置文件
#配置文件进行了精简
#后台启动的意思
daemonize yes
#端口号(如果同一台服务器上启动,注意修改为不同端口
port 6380
#IP绑定,redis不建议对公网开放,直接绑定0.0.0.0可以
bind 0.0.0.0
#这个文件会自动生成(如果同一台服务器上启动,注意修改为不同端口)
pidfile "/var/run/redis_6380.pid"
# Generated by CONFIG REWRITE
user default on nopass ~* +@all
dir "/usr/local/redis"
(4)配置主从并查看主从服务器集群
做个软连接 就可以完成后就可以全局使用
#前面是redis安装的路径,后面是将redis-server放在/usr/local/bin/redis下
#服务端
[root@localhost ~]# ln -s /root/redis-6.0.5/src/redis-server /usr/local/redis/bin/redis-server
#客户端
[root@localhost ~]# ln -s /root/redis-6.0.5/src/redis-cli /usr/local/redis/bin/redis-cli
- 启动三个Redis
[root@localhost redis]# /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6380.conf
[root@localhost redis]# /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6381.conf
[root@localhost redis]# /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6382.conf
- 配置为1主2从
[root@localhost redis]#/usr/local/redis/bin/redis-cli -p 6381 slaveof 192.168.11.131 6380
[root@localhost redis]#/usr/local/redis/bin/redis-cli -p 6382 slaveof 192.168.11.131 6380
- 检查集群
[root@localhost redis]# /usr/local/redis/bin/redis-cli -p 6380 info Replication
(5)准备哨兵配置文件
#配置文件:sentinel.conf,在sentinel运行期间是会被动态修改的
#sentinel如果重启时,根据这个配置来回复之前所监控的redis集群的状态
#绑定Ip
bind 0.0.0.0
#后台运行
daemonize yes
#默认yes,设指定密码或者指定IP的情况下,外网无法访问
protected-mode no
#哨兵的端口,客户端通过这个端口来发现redis
port 26380
#哨兵指定自己的IP,手动设置也可以自动发现,用于与其他哨兵通信
#sentinel announce-ip
#临时文件夹
dir "/tmp"
#日志
logfile "/usr/local/redis/logs/sentinel-26380.log"
#sentinel监控的master的名字叫做mymaster,初始地址为192.168.11.131 6380,2代表两个以及两个
#以上的哨兵任务死亡,才认为真正的死亡
sentinel monitor mymaster 192.168.11.131 6380 2
#发送心跳PING来确认master是否存活
#如果master在一定时间范围内不回应PING,或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用了
sentinel down-after-milliseconds mymaster 1000
#如果在该时间(ms)内未能完成failover操作,则任务该failover事变
sentinel failover-timeout mymaster 3000
#指定了在执行故障转移时,最多可以有多个从Redsi示例在同步新的主示例,在从Rdis
#实例较多的情况下,这个数字越小,同步时间越长,完成故障转移所需的时间也就是越长
sentinel parallel-syncs mymaster 1
(6)启动哨兵集群
/usr/local/redis/bin/redis-server /usr/local/redis/conf/sentinel-26380.conf --sentinel
/usr/local/redis/bin/redis-server /usr/local/redis/conf/sentinel-26381.conf --sentinel
/usr/local/redis/bin/redis-server /usr/local/redis/conf/sentinel-26382.conf --sentinel
此时服务器和哨兵集群就搭建完成了。
3.测试哨兵集群高可用性能
测试代码
- 哨兵集群代码
@Configuration
@Profile("sentinel")
class SentinelRedisAppConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
System.out.println("使用哨兵版本");
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master("mymaster")
// 哨兵地址
.sentinel("192.168.11.131", 26380)
.sentinel("192.168.11.131", 26381)
.sentinel("192.168.11.131", 26382);
return new LettuceConnectionFactory(sentinelConfig);
}
}
- 哨兵集群 单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
@ActiveProfiles("sentinel") // 设置profile
public class SentinelTests {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void test() throws InterruptedException {
// 每个一秒钟,操作一下redis,看看最终效果
int i = 0;
while (true) {
i++;
stringRedisTemplate.opsForValue().set("test-value", String.valueOf(i));
System.out.println("修改test-value值为: " + i);
Thread.sleep(1000L);
}
}
}
测试一:停掉主服务
程序是否正常运行:是。
测试二:停掉哨兵
程序是否正常运行:是。
此时redis和客户端正常连接,客户端不需要哨兵,因此停掉哨兵不影响程序。
测试三:停掉主服务器+哨兵
程序是否正常运行:是。
客户端按照程序中,配置的哨兵的顺序,去找哨兵,发现哨兵挂掉了。
短暂时间内,出现了警告信息,但是经过客户端的多次重试,去找下一个哨兵,最终实现了程序继续正常运行
- 生产环境部署redis集群,一般放在不同的服务器,不同机柜,甚至不同机房。尽量保证服务器不会因硬件故障而挂掉。
- 客户端不知道连接哪个主服务器的时候,哨兵才发挥作用。
4、哨兵选举过程
哨兵选举
哨兵选举时候的日志文件
监控其他服务器:查看哨兵选举变更主服务器后,其他服务器的变化