一、架构
Redis 提供了主从库模式,以保证数据副本的一致,主从库之间采用的是「读写分离」的方式。
- 读操作:主库、从库都可以接收;
- 写操作:首先到主库执行,然后,主库将写操作同步给从库。
为什么要采用读写分离的方式呢? 如果说从库也可以像主库一样,可以接收到写请求的话,一个直接的问题就是「数据不一致」。如果要保持这个数据在所有redis实例上一致,就要涉及到加锁等一系列操作, 但这会带来巨额的开销。采用「读写分离」,所有数据的修改只会在主库上进行,不用协调三个实例。 主库有了最新的数据后,会同步给从库,这样,主从库的数据就是一致的。
二、数据同步
1、全量同步
主从节点的第一次同步是全量同步的方式,这个过程中会生成RDB文件。 master如何判断slave是不是第一次来同步数据?
- Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
- offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据 流程
2、增量同步
一般在slave重启后,需要做增量同步
增量同步失败 repl_baklog是一个环形数组,只要master和slave之间的offset没有超过整个环的长度,就可以做增量同步(replid一致的情况下)。若offset超出一个环的长度(slave和master的数据差太多),则只能做全量同步。repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。
优化主从集群 要尽量避免全量同步:
- Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
- 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
- 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
3、总结
三、哨兵
1、功能
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:
- 监控:Sentinel 会不断检查您的master和slave是否按预期工作
- 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
- 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
2、心跳机制
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
- 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
- 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
3、选举master
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的: - 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
- 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举(默认值大家都一样是1)
- 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
- 最后是判断slave节点的运行id大小(redis启动的时候自动生成的id),越小优先级越高。
4、故障转移
当选中了其中一个slave为新的master后(例如slave1),故障的转移的步骤如下:
- sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
- sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
- 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
|