1.哨兵模式
试想一下,如果主从模式中,大半夜主节点挂了,运维从床上迷迷糊糊爬起来,打开电脑,手动升级处理,怕不是第二天就要上头条了。
哨兵模式的出现用于解决主从模式中无法自动升级主节点的问题,一个哨兵是一个节点,用于监控主从节点的健康,当主节点挂掉的时候,自动选择一个最优从节点升级为主节点。
但哨兵如果挂了怎么办?于是哨兵一般都会是一个集群,是集群高可用的心脏,一般由3-5个节点组成,即使个别节点挂了,集群还可以正常运行。
优点
- 可以在master挂掉后自动选举新的master
缺点
- master挂了,切换新的master会造成未来得及主从同步的数据丢失
- 大数据高并发,单个master内存仍存在上限
- 主从全量同步仍然要耗费大量时间
- 单个Redis只能利用CPU的单个核心,应对海量数据捉襟见肘
解决办法
- Redis集群方案
客户端连接Redis,会首先连接Sentinel,通过Sentinel查询master地址,然后再连接master进行数据交互。当master挂了,客户端重新跟Sentinel要master地址,连接新的master。
上图中可看,master挂了,原先的主从复制断开,客户端和master也断开。然后一个slave变成新的master,和其余的slave进行新的主从复制,客户端通过新的master继续交互,Sentinel持续监控已经挂掉的旧的master,一旦旧的master恢复,集群会变为下图,旧的master成为新的slave,从新的master建立主从复制关系。
2.哨兵模式的工作机制
- 一个Sentinel或Sentinel集群可以管理多个主从Redis,如果只有一个Redis,Sentinel没有意义
- master挂了,Sentinel在slave中选举一个升级为master,并修改配置文件
- 挂了的master恢复后,只能当slave,跟新选举的master主从复制
- Sentinel有可能会挂,所以Sentinel一般都是一个集群
- 每个Sentinel节点定期检测Redis数据节点、其余Sentinel节点是否可达
- 对于节点的故障是由多个Sentinel节点共同完成,有效防止误判
- Redis主从复制为异步,master挂了,从节点可能会丢失一部分信息,Sentinel无法保证消息完全不丢失,但可以做到尽量少丢失
- Sentinel.slave_for方法可以从连接池内采用轮询方案拿出一个slave地址,实现负载均衡
3.1 定时监控任务
- 每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最近的拓扑结构,可以感知新加入或故障转移的Redis数据节点
- 每隔2秒,每个Sentinel节点会与其他Sentinel节点通信,可以发现新的Sentinel节点,并与其他Sentinel节点交换对主节点的判断信息,方便故障转移及选举
- 每隔1秒,每个Sentinel节点会向主节点、从节点以及其他的Sentinel节点发送ping做一次心跳检测,来确认这些节点是否可达,实现对每个节点的监控
3.2 主观下线和客观下线
主观下线
当Sentinel节点ping其他节点,超时未回复,Sentinel节点就会对该节点做失败判定。主观下线是当前Sentinel节点的一家之言,存在误判可能
客观下线
当Sentinel主观下线的节点是master,该Sentinel会询问其他Sentinel对master的判断,当大部分Sentinel都对master的下线做了同意判断,那么这个判断就是比较客观的
3.3 Sentinel集群的领导者选举
Sentinel节点已经对master做了客观下线,但还不能立刻进行故障转移,因为故障转移工作只需要一个Sentinel节点来完成,因此在Sentinel集群中要选出一个leader来进行故障转移。
Redis使用了Raft算法实现领导者选举:
- 每个在线的Sentinel节点都有资格成为领导者,他要求其他节点来投自己一票
- 先收到谁的要求就给谁投票,但不能给自己投
- 首先拿到大多数(即一半+1)的票当选领导者
3.4 故障转移
- 排除主观下线的从节点
- 选择优先级高的从节点,如果没有再进行3
- 选择复制偏移量最大的从节点(复制的最完整),如果没有再进行4
- 选择runid最小的从节点
4. 哨兵模式的原理
1 多个sentinel发现并确认master有问题
2 选举触一个sentinel作为领导(raft算法)
3 选取一个slave作为新的master
4 通知其余slave成为新的master的slave
5 通知客户端主从变化
6 等待老的master复活成为新master的slave
哨兵:是一个进程---》启动使用redis-sentinel启动,有自己的配置文件,启动后,可以客户端连接(redis-cli),查看哨兵状态
4.1配置哨兵 (一主两从架构---》运行多个哨兵--》一般奇数个(3个))
配置哨兵配置文件:
python
port 26379
daemonize yes
dir /root/lqz/redis-6.2.9/data
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
# 2 配置3个配置文件,监听端口不一样(正常应该放在3台机器上)
# 3 启动哨兵
#启动三个哨兵
./src/redis-sentinel sentinel_26379.conf
./src/redis-sentinel sentinel_26380.conf
./src/redis-sentinel sentinel_26381.conf
# 4 演示故障
-把主库停止
-查看自动故障切换
-启动起原来主库,变成了从
4.2python 操作哨兵
python
import redis
from redis.sentinel import Sentinel
# 连接哨兵服务器(主机名也可以用域名)
# 10.0.0.101:26379
sentinel = Sentinel([('8.130.125.9', 26379),
('8.130.125.9', 26380),
('8.130.125.9', 26381)
],
socket_timeout=5)
print(sentinel)
# 获取主服务器地址
master = sentinel.discover_master('mymaster')
print(master)
# 获取从服务器地址
slave = sentinel.discover_slaves('mymaster')
print(slave)
##### 读写分离
# 获取主服务器进行写入
master = sentinel.master_for('mymaster', socket_timeout=0.5)
w_ret = master.set('foo', 'bar')
# slave = sentinel.slave_for('mymaster', socket_timeout=0.5)
# r_ret = slave.get('foo')
# print(r_ret)