Redis(七)Redis 主从复制及Redis 哨兵机制

285 阅读12分钟

Redis 主从复制

主从复制介绍

持久化保证了即使 Redis 服务重启也不会丢失数据,因为 Redis 服务重启后会将硬盘上持久化的数据恢复到内存中,但是当 Redis 服务器的硬盘损坏了可能会导致数据丢失,不过通过 Redis 的主从复制机制就可以避免这种单点故障

微信图片_20210814113619.png

  • 主 Redis 中的数据有两个副本( replication )即从 redis1 和从 redis2 ,即使一台 Redis 服务器宕机其它两台 Redis 服务也可以继续提供服务

  • 主 Redis 中的数据和从 Redis 上的数据保持实时同步,当主 Redis 写入数据时通过主从复制机制会复制到两个从 Redis 服务上

  • 只有一个主 Redis ,可以有多个从 Redis

  • 主从复制不会阻塞 master ,在同步数据时, master 可以继续处理 client 请求

实现原理

数据同步

Redis在2.8及以上版本使用psync命令完成主从数据同步,同步过程分为:全量复制和部分复制

  • 全量复制:一般用于初次复制场景,Redis早期支持的复制功能只有全量复制,它会把主节点全部数据一次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销

  • 部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发丢失数据给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销

部分复制是对老版复制的重大优化,有效避免了不必要的全量复制操 作。因此当使用复制功能时,尽量采用2.8以上版本的Redis

psync命令运行需要以下组件支持

  • 主Redis的复制偏移量(replication offset)和从Redis的复制偏移量

  • 主Redis的复制积压缓冲区(replication backlog)

  • Redis的运行ID(run ID)

runid

Redis 服务器的随机标识符(用于 Sentinel 和集群),重启后就会改变;当复制时发现和之前的 run_id不同时,将会对数据全量同步

复制偏移量

通过对比主从节点的复制偏移量,可以判断主从节点数据是否一致

  • 参与复制的主从节点都会维护自身复制偏移量。主节点(master)在处理完写入命令后,会把命令的字节长度做累加记录,统计信息在info relication中的master_repl_offset指标中

  • 从节点(slave)每秒钟上报自身的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量

  • 从节点在接收到主节点发送的命令后,也会累加记录自身的偏移量。统计信息在info relication中 slave_repl_offset指标中

全量同步

Redis 的全量同步过程主要分三个阶段

  • 同步快照阶段: Master 创建并发送快照给 Slave , Slave 载入并解析快照。 Master 同时将此阶段所产生的新的写命令存储到缓冲区

  • 同步写缓冲阶段: Master 向 Slave 同步存储在缓冲区的写操作命令

  • 同步增量阶段: Master 向 Slave 同步写操作命令

增量同步

  • Redis 增量同步主要指 Slave 完成初始化后开始正常工作时, Master 发生的写操作同步到Slave 的过程

  • 通常情况下, Master 每执行一个写命令就会向 Slave 发送相同的写命令,然后 Slave 接收并执行

主从配置

  • 主Redis配置 无需特殊配置

  • 从Redis配置 修改从服务器上的 redis.conf 文件

# replicaof <masterip> <masterport> 
# 表示当前【从服务器】对应的【主服务器】的IP是192.168.10.135,端口是6379。 
#4.0之前只能slaveof 4.0之后默认replicaof,slaveof都起作用 
slaveof 192.168.133.154 6379 
replicaof 192.168.133.154 6379

Redis 哨兵机制

Redis Sentinel 工作原理分析

为什么要用到哨兵

哨兵(Sentinel)主要是为了解决在主从复制架构中出现宕机的情况,主要分为两种情况

  • 从Redis宕机

    这个相对而言比较简单,在Redis中从库重新启动后会自动加入到主从架构中,自动完成同步数据。在Redis2.8版本后,主从断线后恢复的情况下实现增量复制

  • 主Redis宕机

    在从数据库中执行SLAVEOF NO ONE命令,断开主从关系并且提升为主库继续服务

    第二步,将主库重新启动后,执行SLAVEOF命令,将其设置为其他库的从库,这时数据就能更新回来

由于这个手动完成恢复的过程其实是比较麻烦的并且容易出错,所以Redis提供的哨兵(sentinel)的功能来解决

哨兵机制(sentinel)的高可用

Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器

微信图片_20210814130523.png

在Server1 掉线后

微信截图_20210814130601.png

升级Server2 为新的主服务器

微信截图_20210814224949.png

哨兵的定时监控

任务1:每个哨兵节点每10秒会向主节点和从节点发送info命令获取最新拓扑结构图,哨兵配置时只要配置对主节点的监控即可,通过向主节点发送info,获取从节点的信息,并当有新的从节点加入时可以马上感知到

微信截图_20210814130728.png

任务2:每个哨兵节点每隔2秒会向redis数据节点的指定频道上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其它哨兵节点的信息及对主节点的判断,其实就是通过消息publish和subscribe来完成的

微信截图_20210814130802.png

任务3:每隔1秒每个哨兵会向主节点、从节点及其余哨兵节点发送一次ping命令做一次心跳检测,这个 也是哨兵用来判断节点是否正常的重要依据

微信截图_20210814130816.png

主观下线:所谓主观下线,就是单个sentinel认为某个服务下线(有可能是接收不到订阅,之间的网络不通等等原因)。SDOWN

sentinel会以每秒一次的频率向所有与其建立了命令连接的实例(master,从服务,其他sentinel)发ping命令,通过判断ping回复是有效回复,还是无效回复来判断实例时候在线(对该sentinel来说是“主观在线”)

sentinel配置文件中的down-after-milliseconds设置了判断主观下线的时间长度,如果实例在down-after-milliseconds毫秒内,返回的都是无效回复,那么sentinel回认为该实例已(主观)下线,修改其flags状态为SRI_S_DOWN。如果多个sentinel监视一个服务,有可能存在多个sentinel的down-after-milliseconds配置不同,这个在实际生产中要注意

客观下线:当主观下线的节点是主节点时,此时该哨兵3节点会通过指令sentinel is-masterdown-by-addr寻求其它哨兵节点对主节点的判断,如果其他的哨兵也认为主节点主观线下了,则当认为主观下线的票数超过了quorum(选举)个数,此时哨兵节点则认为该主节点确实有问题,这样就客观下线了,大部分哨兵节点都同意下线操作,也就说是客观下线 ODOWN

微信截图_20210814131013.png

哨兵lerder选举流程

如果主节点被判定为客观下线之后,就要选取一个哨兵节点来完成后面的故障转移工作,选举出一个leader的流程如下

  • 每个在线的哨兵节点都可以成为领导者,当它确认(比如哨兵3)主节点下线时,会向其它哨兵发is-master-down-by-addr命令,征求判断并要求将自己设置为领导者,由领导者处理故障转移;

  • 当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者

  • 如果哨兵3发现自己在选举的票数num 大于等于 (sentinels)/2+1时,将成为领导者,如果没有超过,继续选举…………

如果Sentinel收到其他Sentinel的投票请求,在以下两种情况下会把自己的票投给请求的Sentinel实例

  • Sentinel的配置纪元小于或等于发送投票请求的Sentinel配置纪元

  • 在当前配置纪元中这是收到的第一个投票请求

微信截图_20210814131026.png

自动故障转移机制

  • 在从节点中选择新的主节点

    sentinel状态数据结构中保存了主服务的所有从服务信息,领头sentinel按照如下的规则从从服务列表中挑选出新的主服务

    • 过滤掉主观下线的节点

    • 选择slave-priority/ replica-priority最高的节点,(replica-priority 0的不选择)如果由则返回没有就继续选择

    • 选择出复制偏移量最大的系节点,因为复制偏移量越大则数据复制的越完整,如果由就返回了,没有就继续

    • 选择run_id最小的节点

      微信截图_20210814131337.png

  • 更新主从状态

    通过slaveof no one命令,让选出来的从节点成为主节点;并通过slaveof命令让其他节点成为其从节点

    将已下线的主节点设置成新的主节点的从节点,当其回复正常时,复制新的主节点,变成新的主节点的从节点

    同理,当已下线的服务重新上线时,sentinel会向其发送slaveof命令,让其成为新主的从

哨兵进程的作用

  • 监控( Monitoring ): 哨兵( sentinel ) 会不断地检查你的 Master 和 Slave 是否运作正常

  • 提醒( Notification ): 当被监控的某个 Redis 节点出现问题时, 哨兵( sentinel ) 可以通过 API向管理员或者其他应用程序发送通知

  • 自动故障迁移( Automatic failover ):当一个 Master 不能正常工作时,哨兵( sentinel ) 会开始一次自动故障迁移操作

哨兵配置

sentinel.conf

# 设置端口 
port 26379 
# 是否守护进程启动 
daemonize no 
# 守护进程运行的时候需要保留
pidfile pidfile /var/run/redis-sentinel.pid 
# 日志文件 
logfile "/root/log/sentinel.log" 
## sentinel monitor master-group-name hostname port quorum 
## quorum的解释如下: 
 ##(1)至少多少个哨兵要一致同意,master进程挂掉了,或者slave进程挂掉了,或者要启动一个故 障转移操作 
 ## (2)quorum是用来识别故障的,真正执行故障转移的时候,还是要在哨兵集群执行选举,选举一个 哨兵进程出来执行故障转移操作 
 ## (3)假设有5个哨兵,quorum设置了2,那么如果5个哨兵中的2个都认为master挂掉了; 2个哨兵 中的一个就会做一个选举,选举一个哨兵出来,执行故障转移; 如果5个哨兵中有3个哨兵都是运行的, 那么故障转移才会被允许执行。 
# 原文是:Note that whatever is the ODOWN quorum, a Sentinel will require to 
# be selected by the majority of the known Sentinels in order to 
# start a failover, so no failover can be performed in minority. 
sentinel monitor mymaster 127.0.0.1 6379 3 
# down-after-milliseconds,超过多少毫秒跟一个redis实例断了连接(ping不通),哨兵就可 能认为这个redis实例挂了 
sentinel down-after-milliseconds mymaster 30000 
# parallel-syncs,新的master别切换之后,同时有多少个slave被切换到去连接新master,重新 做同步,数字越低,花费的时间越多 
# 比如:master宕机了,4个slave中有1个切换成了master,剩下3个slave就要挂到新的master上 面去
# 这个时候,如果parallel-syncs是1,那么3个slave,一个一个地挂接到新的master上面去,1 个挂接完,而且从新的master sync完数据之后,再挂接下一个。 
# 如果parallel-syncs是3,那么一次性就会把所有slave挂接到新的master上去 
sentinel parallel-syncs mymaster 1 
#failover-timeout,执行故障转移的timeout超时时长,Default is 3 minutes. 
sentinel failover-timeout mymaster 180000

如果有一个sentinel

实际情况,其实单纯从代码的情况,其实1个Sentinel就能完成主观下线(sdown,Subjectively Down),客观下线(odown, Objectively Down) 的判断,自动发现 Sentinel 和从服务器,并且完成故障转移

如果有2个sentinel

如果哨兵集群仅仅部署了个2个哨兵实例,quorum=1。s1和s2中只要有1个哨兵认为master宕机就可以还行切换,同时s1和s2中会选举出一个哨兵来执行故障转移。同时这个时候,需要majority,也就是大多数哨兵都是运行的,2个哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=3),如果一个节点挂了那么哨兵也就挂了,哨兵只剩下一个,那么就无法完成故障转移

如果是经典的3节点哨兵集群

majority=2(majority不能配置,由redis自行计算所得。)如果M1所在机器宕机了,那么三个哨兵还剩下2个,S2和S3可以一致认为master宕机,然后选举出一个来执行故障转移。同时3个哨兵的majority是2,所以还剩下的2个哨兵运行着,就可以允许执行故障转移

这就是经典的sentinel3个节点的集群。节省资源的同时又满足了高可用