Redis主从同步
主从同步
- Redis采用读写分离的方式,首先封住数据来源只有一个。 (一致性)
- 第一次同步
- slave 通过命令
replicaof 127.0.0.1 6379与master建立联系 - 链接建立后slave会发送
psync ? -1获取拉取数据范围(?: 第一次链接不知道master的runId(每台服务启动时生成的随机id) -1: 标识全量复制) - master接收到
psync消息后回应+FULLRESYNC runID, offset标识此次是全量复制 - master fock子进程生成RDB 发送给slave
- slave收到RDB文件后清除内存数据后同步RDB
- slave 通过命令
master fock子进程后 产生的数据更新都会被缓存在 slave的buffer(replacetion buffer)中,同步给slave来保证数据同步。

-
数据同步
master每执行一个更新命令就会往replacetion buffer插入一条,并通过与slave建立的长链接(避免频繁建立链接的开销)发送到slave -
长链接断开后从链接怎么办: repl_backlog_buffer就来了
master每执行一个更新命令再给repl_backlog_buffer中插入一条用作备份,同时master维护master_repl_offset,slave维护slave_repl_offset。
从链后slave发送偏移量到master,master计算根当前进度差了多少,然后将差了的写入到replcation buffer发送到slave。
这里需要注意repl_backlog_buffer到设计是环形的(redo log一样),所以slave停机太久可能造成数据已被覆盖,这个时候就会促发(第一次同步)的方案啦。
repl_backlog_buffer大小调整repl_buffer_size -
repl_backlog_buffer:它是为了从库断开之后,如何找到主从差异数据而设计的环形缓冲区,从而避免全量同步带来的性能开销。如果从库断开时间太久,repl_backlog_buffer环形缓冲区被主库的写命令覆盖了,那么从库连上主库后只能进行一次全量同步,所以repl_backlog_buffer配置尽量大一些,可以降低主从断开后全量同步的概率。
-
replication buffer:Redis和客户端通信也好,和从库通信也好,Redis都需要给分配一个 内存buffer进行数据交互,客户端是一个client,从库也是一个client,我们每个client连上Redis后,Redis都会分配一个client buffer,所有数据交互都是通过这个buffer进行的:Redis先把数据写到这个buffer中,然后再把buffer中的数据发到client socket中再通过网络发送出去,这样就完成了数据交互。所以主从在增量同步时,从库作为一个client,也会分配一个buffer,只不过这个buffer专门用来传播用户的写命令到从库,保证主从数据一致,我们通常把它叫做replication buffer。
- 如果主从在传播命令时,因为某些原因从库处理得非常慢,那么主库上的这个buffer就会持续增长,消耗大量的内存资源,甚至OOM。所以Redis提供了client-output-buffer-limit参数限制这个buffer的大小,如果超过限制,主库会强制断开这个client的连接,也就是说从库处理慢导致主库内存buffer的积压达到限制后,主库会强制断开从库的连接,此时主从复制会中断,中断后如果从库再次发起复制请求,那么此时可能会导致恶性循环,引发复制风暴,这种情况需要格外注意。
哨兵
解决分布式系统下master节点不可用。
-
哨兵怎么实现的?
- 基于Redis的
pub/sub - 当执行
sentinel monitor <master-name> <ip> <port> <quorum>启动哨兵时会执行SUBSCRIBE __sentinel__:hello,同时将自己的地址发布上去 - 再有哨兵加入集群时之前订阅的哨兵节点会收到master节点推来的新节点加入消息。从而建立链接
![]()
- 基于Redis的
-
哨兵如何知道从库地址?
![]()
-
当发生master节点不可用由哪个哨兵节点执行替换流程?
- 当发现master在
down-after-milliseconds时长内不可用时会向其他节点发送is-master-down-by-addr命令,超过(配制的)quorum赞成后进入Leader选举出执行操作的节点。 - 每个节点都可能得到 “超过(配制的)
quorum赞成”,所以每个节点都可能发出leader选举操作。
(发起leader选举的节点那一票投给自己 )- 假设3个节点a,b,c。 节点a,b同时发起leader选举,假设c先收到a的投票请求,那么c就会给a投一票,后续收到的请求就都反对。 节点a在得到票数大于半数节点且大于
quorum数后将成为leader节点。 - 假设3个节点a,b,c。 节点a,b, c同时发起leader选举, 那么三个节点都达不到成为leader的条件,集群会等待(哨兵故障转移超时时间的 2 倍)后超时,重新发起新一轮选举。
(leader选举也是很依赖网络环境的,假设有一台网络环境不好,也可能导致整个集群达不到成为leader的必要条件)
可以适当调大down-after-milliseconds避免误判
- 假设3个节点a,b,c。 节点a,b同时发起leader选举,假设c先收到a的投票请求,那么c就会给a投一票,后续收到的请求就都反对。 节点a在得到票数大于半数节点且大于
- 当发现master在
-
客户端可以查到当前主从替换走到哪个流程了么?
哨兵其实也是运行的Redis,所以也可以通过pub/sub方案获取进度
![]()
哨兵会PING集群下的节点,发现节点在down-after-milliseconds时长内不可用标记为“主观不可用”,如果标记的节点是master节点。就开始启用主从替换流程。这里为了确定master是真的不可用了,哨兵服务可能会存在多个,这个时候哨兵就会联系集群中其他实例,如果 认为master不可用的实例数大于 实例数/2+1,就会标记为客观不可用(认为master节点不可用)。
- 主从替换流程
主从替换期间系统写功能将停止使用;
- 排除
排除历史不可用次数大于down-after-milliseconds次的; - 打分
slave-priority优先级最高的从库直接成为master
slave_repl_offset最接近master_repl_offset的打分最高
实例ID最小的优先
- 选出新的master节点后通知从库和客户端
- 通知从库: 执行
replicaof命令指向新的master节点 - 通知客户端:
- 哨兵会将master几点的新地址写入自己
pubsub中,客户端通过订阅这个pubsub可以感知到master节点发生变化近而更换操作地址。 - 也可以通过
sentinel get-master-addr-by-name主动拉取最新的master地址
- 哨兵会将master几点的新地址写入自己
- 通知从库: 执行



浙公网安备 33010602011771号