一、主从复制
1.1 什么是主从复制
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。
前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点
默认情况下,每台redis服务器都是主节点;且一个主节点可以有多个从节点(或者没有),但一个从节点只有一个主。
1.2 主从复制的作用
1)数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2)故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
3)负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4)高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
主从库采用的是读写分离的方式
1.3 主从复制原理
分为全量复制与增量复制
1.3.1 全量复制
发生在第一次复制时
第一阶段是主从库间建立连接、协商同步的过程。
第二阶段,主库将所有数据同步给从库。
第三个阶段,主库会把第二阶段执行过程中新收到的写命令,再发送给从库。
1.3.2 增量复制
只会把主从库网络断连期间主库收到的命令,同步给从库
1.3.3 同步流程
1)一个从数据库启动后,会向主数据库发送SYNC命令。
2)主数据库在接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。在该持久化过程中会生成一个.rdb的快照文件。
3)在主数据库快照执行完成后, Redis 会将快照文件和所有缓存的命令以 .rdb 快照文件的形式发送给从数据库 。
4)从数据库收到主数据库的 .rdb 照文件后,载入该快照文件到本地。
5)从数据库执行载入后的 .rdb 照文件,将数据写入内存中。以上过程被称为复制初始化
6)在 制初始化结束后, 主数据库在每次收到写命令时都会将命令同步给从数据库,从而保证主从数据库的数据一致性。
二、哨兵机制
2.1 哨兵机制介绍
2.1.1 集群逻辑图
下图是一个典型的哨兵集群监控的逻辑图
Redis Sentinel包含了若个Sentinel节点,这样做也带来了两个好处:
1)对于节点的故障判断是由多个Sentinel节点共同完成,这样可以有效地防止误判
2)即使个别Sentinel节点不可用,整个Sentinel集群依然是可用的。
2.1.2 哨兵机制实现的功能
Redis-Sentinel是在master-slave机制上加入监控机制哨兵Sentinel实现的。Sentinel主要功能就是为Redis Master-Slave集群提供:
1)监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
2)提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
3)自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
4)配置中心:在Redis Sentinel模式中,客户端在初始化的时候连接的是Sentinel节点集合,从中获取主节点信息。
其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置中心和通知功能,则需要在与客户端的交互中才能体现。
在Sentinel集群中,一个最小的Master-Slave单元包含一个master和一个slave服务器。当master失效后,sentinel自动将slave提升为master,从而可以减少管理员的人工切换slave的操作过程。
2.2 哨兵机制原理
2.2.1 监控
Sentinel节点需要监控master、slave以及其它Sentinel节点的状态。这一过程是通过Redis的pub/sub系统实现的。Redis Sentinel一共有三个定时监控任务,完成对各个节点发现和监控:
1)监控主从拓扑信息:每隔10秒,每个Sentinel节点,会向master和slave发送INFO命令获取最新的拓扑结构
2)Sentinel节点信息交换:每隔2秒,每个Sentinel节点,会向Redis数据节点的__sentinel__:hello频道上,发送自身的信息,以及对主节点的判断信息。这样,Sentinel节点之间就可以交换信息
3)节点状态监控:每隔1秒,每个Sentinel节点,会向master、slave、其余Sentinel节点发送PING命令做心跳检测,来确认这些节点当前是否可达。
2.2.2 下线
2.2.2.1 下线流程
1)每个Sentinel以每秒一次的频率向它所知的Master,Slave以及其他Sentinel实例发送一个PING命令。
2)如果一个实例(instance)距离最后一次有效恢复PING命令的时间超过own-after-milliseconds选项所指定的值,则这个实例会被Sentinel标为主观下线(Sentinel Leader PING命令确认)。
3)当有足够的Sentinel(大于等于文件配置的值)在指定的时间范围内确认Master的确进入了主观下线状态,则Master会被标记为客观下线。
2.2.2.2 主观下线
每个Sentinel节点,每隔1秒会对数据节点发送ping命令做心跳检测,当这些节点超过down-after-milliseconds没有进行有效回复时,Sentinel节点会对该节点做失败判定,这个行为叫做主观下线。
2.2.2.3 客观下线
客观下线,是指当大多数Sentinel节点,都认为master节点宕机了,那么这个判定就是客观的,叫做客观下线。
那么这个大多数是指多少呢?这其实就是分布式协调中的quorum判定了,大多数就是过半数,比如哨兵数量是5,那么大多数就是5/2+1=3个,哨兵数量是10大多数就是10/2+1=6个。
注:Sentinel节点的数量至少为3个,否则不满足quorum判定条件。
2.2.3 哨兵选举
如果发生了客观下线,那么哨兵节点会选举出一个Leader来进行实际的故障转移工作。Redis使用了Raft算法来实现哨兵领导者选举,大致思路如下:
1)每个Sentinel节点都有资格成为领导者,当它主观认为某个数据节点宕机后,会向其他Sentinel节点发送sentinel is-master-down-by-addr命令,要求自己成为领导者;
2)收到命令的Sentinel节点,如果没有同意过其他Sentinel节点的sentinelis-master-down-by-addr命令,将同意该请求,否则拒绝(每个Sentinel节点只有1票);
3)如果该Sentinel节点发现自己的票数已经大于等于MAX(quorum, num(sentinels)/2+1),那么它将成为领导者;
4)如果此过程没有选举出领导者,将进入下一次选举。
2.2.4 故障转移
1)向被选中的从服务器发送slave of no one命令,让它转变为主服务器
2)通过发布/订阅功能,将更新后的配置传播给所有其他Sentinel,其他Sentinel对他们自己的配置进行更新。
3)向所有Slave下达slave of 命令,指向新的主
4)redis-slave 向master重新建立连接,master向所有slave节点发送rdb,保持数据同步
5)在上述转移过程中,伴随着Redis本地配置文件的自动重写,这样即便是实例重启配置也不会丢失
6)原有的master在恢复后降级为slave与新的master全量同步
注:Leader Sentinel节点,会从新的master节点那里得到一个configuration epoch,本质是个version版本号,每次主从切换的version号都必须是唯一的。其他的哨兵都是根据version来更新自己的master配置。
1)Sentinel自动故障迁移使用raft算法来选举Sentinel-leader。
2)超过半数投票选出leader,Sentinel Leader用于下达故障转移的指令。
3)如果某个Leader挂了,则使用raft从剩下的Sentinel中选出leader。
2.2.5 redis哨兵主备切换的数据丢失问题
2.2.5.1 主从异步复制导致的数据丢失
Redis master 和slave 数据复制是异步的,这样就有可能会出现部分数据还没有复制到slave中,master就挂掉了,那么这部分的数据就会丢失了。
2.2.5.2 脑裂导致的数据丢失
脑裂其实就是网络分区导致的现象,比如,我们的master机器网络突然不正常了发生了网络分区,和其他的slave机器不能正常通信了,其实master并没有挂还活着好好的呢,但是哨兵可不是吃闲饭的啊,它会认为master挂掉了啊,那么问题来了,client可能还在继续写master的呀,还没来得及更新到新的master呢,那这部分数据就会丢失。
2.2.5.3 解决方案
上面的两个数据丢失的问题,那我们该怎么去解决呢?其实也很简单,只需要在配置中加两个配置就行了,如下:
min-slaves-to-write 1 # 要求至少一个slave
min-slaves-max-lag 10 # 数据复制和同步的延迟不能超过10s
我们不能只是去解决问题,我们要知道为什么这么做就可以解决问题,下面我们就来分析下,加上了这两个配置是怎么解决我们数据丢失问题的。
核心思想就是,一旦所有的slave节点,在数据复制和同步时延迟了超过10秒的话,那么master它就不会再接客户端的请求了,这样就会有效减少大量数据丢失的发生。
2.2.5.3.1 如何减少异步复制数据的丢失
现在当我们的slave在数据复制的时候,发现返回的ACK时延太长达到了 min-slaves-max-lag 配置,这个时候就会认为如果master宕机就会导致大量数据丢失,所以就提前进行了预测,就不再去接收客户端的任何请求了,来将丢失的数据降低在可控范围内。
2.2.5.3.2 如何减少脑裂数据的丢失
1)如果master出现了脑裂,和其他的slave失去了通信,不能继续给指定数量的slave发送数据。
2)slave超过10秒没有给自己返回ack消息。
3)master就会拒绝客户端的写请求
三、总结
今天我们学习了Redis 主从集群机制和Redis Sentinel 机制的基本使用和底层知识原理介绍,同时在使用哨兵机制过程中对于可能出现的数据丢失进行相关避坑方案讲解,希望帮助大家能更好的掌握Redis的主从机制和哨兵机制。