在前面讲的master/slave模式,在一个典型的一主多从的系统中,slave在整个体系中起到了数据冗余备份和读写分离的作用。当master遇到异常终端后,需要从slave中选举一个新的master继续对外提供服务,这种机制在前面提到过N次,比如在zk中通过leader选举、kafka中可以基于zk的节点实现master选举。所以在redis中也需要一种机制去实现master的决策,redis并没有提供自动master选举功能,而是需要借助一个哨兵来进行监控。
定义
什么是哨兵
顾名思义,哨兵的作用就是监控Redis系统的运行状况,它的功能包括几个
\1.监控(Monitoring): 监控master和slave是否正常运行
\2. 自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。
- 提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
为了解决master选举问题,又引出了一个单点问题,也就是哨兵的可用性(哨兵挂了)如何解决,在一个一主多从的Redis系统中,可以使用多个哨兵进行监控任务以保证系统足够稳定。此时哨兵不仅会监控master和slave,同时还会互相监控;这种方式称为哨兵集群,哨兵集群需要解决故障发现、和master决策的协商机制问题。
sentinel之间会相互感知
sentinel节点之间会因为共同监视同一个master从而产生了关联,一个新加入的sentinel节点需要和其他监视相同
master节点的sentinel相互感知,首先:
\1. 需要相互感知的sentinel都向他们共同监视的master节点订channel:sentinel:hello
\2. 新加入的sentinel节点向这个channel发布一条消息,包含自己本身的信息,这样订阅了这个channel的sentinel就可以发现这个新的sentinel
\3. 新加入得sentinel和其他sentinel节点建立长连接。
master的故障发现
sentinel节点会定期向master节点发送心跳包来判断存活状态,一旦master节点没有正确响应,sentinel会把master设置为“主观不可用状态”,然后它会把“主观不可用”发送给其他所有的sentinel节点去确认,当确认的sentinel节点数大于>quorum时,则会认为master是“客观不可用”,接着就开始进入选举新的master流程;
但是,这里又会遇到一个问题,就是sentinel中,本身是一个集群,如果多个节点同时发现master节点达到客观不可用状态,那谁来决策选择哪个节点作为maste呢?
这个时候就需要从sentinel集群中选择一个leader来做决策。而这里用到了一致性算法Raft算法、它和Paxos算法类似,都是分布式一致性算法。但是它比Paxos算法要更容易理解;
Raft和Paxos算法一样,也是基于投票算法,只要保证过半数节点通过提议即可;
动画演示地址:http://thesecretlivesofdata.com/raft/
配置实现
通过在这个配置的基础上增加哨兵机制。在其中任意一台服务器上创建一个sentinel.conf文件(在redis文件中,也会存在一个sentinel.conf的示例文件),文件内容
sentinel monitor name ip port quorum
其中name表示要监控的master的名字,这个名字是自己定义。 ip和port表示master的ip和端口号。 最后一个1表示最低通过票数,也就是说至少需要几个哨兵节点统一才可以,后面会具体说明:
port 6040 //哨兵自己的端口号
sentinel monitor mymaster 192.168.11.131 6379 1
sentinel down-after-milliseconds mymaster 5000 --表示如果5s内mymaster没响应,就认为SDOWN
sentinel failover-timeout mymaster 15000 --表示如果15秒后,mysater仍没活过来,则启动failover,从剩下的slave中选一个升级为master
两种方式启动哨兵
redis-sentinel sentinel.conf
redis-server /path/to/sentinel.conf --sentinel
启动如上图
哨兵监控一个系统时,只需要配置监控master即可,哨兵会自动发现所有slave;
这时候,我们把master关闭,等待指定时间后(默认是30秒),会自动进行切换,会输出如下消息
shutdown
+sdown表示哨兵主管认为master已经停止服务了,+odown表示哨兵客观认为master停止服务了。如图所示:
关于主观和客观,每个sentinel以每秒一次向他所记录的master或slave其他的sentinel相互ping,检测是否存活。
超过down-after-milliseconds的时间,则标记为主观下线。然后其他的sentinel也要开始确认是否主观下线,如果超过一定确认变更为客观下线。
接着哨兵开始进行故障恢复,挑选一个slave升级为master
+try-failover表示哨兵开始进行故障恢复
+failover-end 表示哨兵完成故障恢复
+slave表示列出新的master和slave服务器,我们仍然可以看到已经停掉的master,哨兵并没有清楚已停止的服务的实例,这是因为已经停止的服务器有可能会在某个时间进行恢复,恢复以后会以slave角色加入到整个集群中。
即使是使用哨兵,此时的Redis集群的每个数据库依然存有集群中的所有数据,从而导致集群的总数据存储量受限于可用存储内存最小的节点,形成了木桶效应。而因为Redis是基于内存存储的,所以这一个问题在redis中就显得尤为突出了
在redis3.0之前,我们是通过在客户端去做的分片,通过hash环的方式对key进行分片存储。分片虽然能够解决各个节点的存储压力,但是导致维护成本高、增加、移除节点比较繁琐。
因此redis3中,就出现支持集群。
总结几点
1.性能,内存撑不住。
2.只有一个master,并发上不去。
3.Master一挂的过程是无法写入的,重启的过程需要一秒或几秒,如果做的是秒杀的业务,在几秒内秒杀结束,redis挂了,会影响前台的业务。大公司已经不会再用哨兵模式了。
网友评论