李代桃僵——Sentinel
Redis提供了一种方案-Redis Sentinel模式,来及解决故障发生时,可以自动进行主从切换。程序不用重启,仿佛什么事业没有发生一样。
Sentinel负责持续监控从节点的健康,当主节点挂掉时,自动选择一个最优的从节点切换成为主节点。客户端连接集群时,会首先连接Sentinel,通过Sentinel来查询主节点的地址,然后再连接主节点进行数据交互。当主节点发送故障时,客户端会重新向Sentinel要地址,Sentinel会将最新的主节点地址告诉客户端。如此应用程序将无需重启自动完成节点切换。
如果主节点挂掉了,原先的主从复制也断开了,客户端和损坏的主节点也断开了。一个从节点被提升为新的主节点,其他从节点开始和新的主节点简历复制关系。客户端通过新的主节点继续进行交互。Sentinel会持续监控已经挂掉了的主节点。
原先挂掉的主节点现在变成了从节点,从新的主节点那里建立复制关系。
消息丢失
Redis主从采用异步复制,意味着当主节点挂掉时,从节点可能没有收到全部的同步消息,这部分未同步的消息就丢失了。如果主从延迟特别大,那么丢失的数据就可能特别多。Sentinel无法保证消息完全不丢失,但是也能尽量保证消息少丢失。
min-slaves-to-write 1
min-slaves-max-lag 10
第一个参数表示主节点必须至少有一个从节点在进行正常复制,否则就停止对外写服务,丧失可用性
第二个参数,单位是秒,表示10s内没有收到从节点的反馈,意味着从节点同步不正常,要么是网络断开了,要么是一直没有反馈
Sentinel基本用法
客户端如何使用Sentinel?标准流程应该是客户端可以通过Sentinel发现主从节点的地址,然后通过这些地址建立相应的连接来进行数据存取操作
Sentinel的默认端口是26379,不同于Redis的默认端口6379,通过Sentinel对象的discover_xxx可以发现主从地址。主地址只有一个,从地址可以有多个。
通过xxx_for方法可以从连接池中拿出一个连接来使用,因为从地址有多个,Redis客户端对从地址采用轮询方案。
当Sentinel进行主从切换时,客户端是如何知道地址变更的?
在建立连接的时候进行主节点地址变更判断。连接池建立连接时,回去查询主节点的地址,然后跟内存中的主节点地址进行比较,如果变更了,就断开所有连接,重新使用新地址建立新连接,如果是旧的主节点挂掉了,那么所有正在使用的连接都会被关闭,然后在重连上用上新地址。
在重连的过程中,Sentinel主动进行主从切换,但主节点并没有挂掉,而之前的主节点连接已经建立了且在使用中,没有新连接需要建立,那么这个连接会捕获一个ReadOnlyError,当有修改性指令会抛出,没有修改性指令,连接不会得到切换,因为数据不会被破坏,所以即使不切换也没关系。
Master挂掉,会选择哪个Slave
当哨兵集群选举出哨兵Leader后,由哨兵Leader从Redis从节点中选择一个Redis节点作为主节点
- 过滤故障的节点
- 选择优先级slave-priority最大的从节点作为主节点
- 选择复制偏移量最大的从节点作为主节点,数据偏移量记录写了多少数据,主服务器会把偏移量同步给从服务器,当主从的偏移量一致,则数据是完全相同的
- 选择runid最小的从节点作为主节点。Redis每次启动的时候生成随机的runnid作为Redis的标识