Redis中主从同步机制的示例分析

76次阅读
没有评论

共计 4365 个字符,预计需要花费 11 分钟才能阅读完成。

丸趣 TV 小编给大家分享一下 Redis 中主从同步机制的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

之前的文章中详细分析了 redis 的特性和核心原理,从本篇开始将对 redis 的部署结构和运行模式进行分析解读。真正生产环境当中我们基本不会使用单节点的 redis 来提供服务,至少是主从结构的哨兵或者集群模式,以保障 redis 服务的可靠性。本篇就来详细解读下 redis 的主从同步机制。

一、Redis 主从有两种结构模型:

1.1 主从复制

一主 N 从的这种复制结构复制关系只有一级,也是使用最多的形式,通常搭建哨兵或者集群结构的 redis 都是采用的这种复制结构,能够通过一级从节点的复制关系很好的保证服务的可用性,做到异常情况主从切换。

1.2 级联复制

级联复制结构的复制关系可以有多级,一个主节点的从节点可以是下属从节点的主节点。级联复制结构的应用相对比较少,这种结构能够在有多个从节点的结构下一定程度上缓解主节点的复制压力。

二、Redis 主从关系的建立

redis 的主从同步始于命令 SLAVEOF host port,通过这个命令能够建立主从关系,SLAVEOF 命令用于在 Redis 运行时动态地修改复制功能的行为。通过执行 SLAVEOF host port 命令,可以将当前服务器转变为指定服务器的从属服务器 (slave server)。如果当前服务器已经是某个主服务器(master server) 的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。另外,对一个从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。利用 SLAVEOF NO ONE 不会丢弃同步所得数据集这个特性,在没有搭建哨兵和集群的情况下,可以在主服务器失败的时候,将从属服务器用作新的主服务器,从而实现无间断运行。

下图为主从关系建立流程:

注意:

根据上执行流程这里有一个需要注意点,当我们对一个已有主从关系的节点执行 slaveof 命令时,会结束掉现有的主从关系并清空节点下的所以数据,在生成环境当中这是比较威胁的操作。有没有更安全的方式了?上面介绍 slavelof 命令的时候提到可以传递 NO ONE 参数,也就是执行 SLAVEOF NO ONE 命令,这个命令是只会结束主从复制关系不会清空数据的,相对安全很多。

三、数据同步

建立好主从关系后就要进入主从数据同步的过程了,这里主要分三种情况,刚建立主从关系后的数据全量同步;初始化同步完成后的命令传播阶段;主从关系异常中断重连后的同步方式选择,这里会有全量和增量同步两种场景。

3.1 全量同步

当 slave 节点启动后或断开重连后(重连不满足增量同步条件),会向 master 数据库发送 SYNC 命令。

master 节点收到 SYNC 命令后会开始在后台保存快照(即 RDB 持久化,在主从复制时,会无条件触发 RDB),并将保存快照期间接收到的命令缓存起来。

master 节点执行 RDB 持久化完成后,向所有 slave 节点发送快照 RDB 文件,并在发送快照期间继续记录被执行的写命令。

slave 节点收到快照文件后丢弃所有旧数据(会清空所有数据),载入收到的快照。

master 节点快照发送完毕、slave 节点载入快照完毕后,master 节点开始向 slave 节点发送缓冲区中的写命令。

slave 节点完成对快照的载入,开始接收命令请求,并执行来自主数据库缓冲区的写命令。(从数据库初始化完成)

master 节点每执行一个写命令就会向 slave 节点发送相同的写命令,slave 节点接收并执行收到的写命令。(命令传播操作,slave 节点初始化完成后的操作)

全量同步流程如下图:

在 redis2.8 之前,从节点无论是初始化还是断线重连后都是采用全量同步的方式,在 2.8 之后版本,引入 PSYNC 命令,在从节点断线重连后会判断是否采用增量同步。

3.2 增量同步

PSYNC 具备了数据全量重同步和增量同步模式。

全量重同步:跟旧版复制基本是一致的,可以理解为“全量”复制。

部分重同步:salve 断开又重新连时,在命令传播阶段,只需要发送与 master 断开这段时间执行的写命给 slave 即可,可以理解为“增量”复制。

PSYNC 执行过程中比较重要的概念有 3 个:runid、offset(复制偏移量)以及复制积压缓冲区。

1.runid

每个 Redis 服务器都会有一个表明自己身份的 ID。在 PSYNC 中发送的这个 ID 是指之前连接的 Master 的 ID,如果没保存这个 ID,PSYNC 的命令会使用”PSYNC ? -1”这种形式发送给 Master,表示需要全量复制。

2.offset(复制偏移量)

在主从复制的 Master 和 Slave 双方都会各自维持一个 offset。Master 成功发送 N 个字节的命令后会将 Master 里的 offset 加上 N,Slave 在接收到 N 个字节命令后同样会将 Slave 里的 offset 增加 N。Master 和 Slave 如果状态是一致的那么它的的 offset 也应该是一致的。

3. 复制积压缓冲区

复制积压缓冲区是由 Master 维护的一个固定长度环形积压队列(FIFO 队列),它的作用是缓存已经传播出去的命令。当 Master 进行命令传播时,不仅将命令发送给所有 Slave,还会将命令写入到复制积压缓冲区里面。PSYNC 执行过程和 SYNC 的区别在于:salve 连接时,判断是否需要全量同步,全量同步的逻辑过程和 SYNC 一样。PSYNC 执行步骤如下:

客户端向服务器发送 SLAVEOF 命令,即 salve 向 master 发起连接请求时,slave 根据自己是否保存 Master runid 来判断是否是第一次连接。

如果是第一次同步则向 Master 发送 PSYNC ? -1 命令来进行完整同步;如果是重连接,会向 Master 发送 PSYNC runid offset 命令(runid 是 master 的身份 ID,offset 是从节点同步命令的全局迁移量)。

Master 接收到 PSYNC 命令后,首先判断 runid 是否和本机的 id 一致,如果一致则会再次判断 offset 偏移量和本机的偏移量相差有没有超过复制积压缓冲区大小,如果没有那么就给 Slave 发送 CONTINUE,此时 Slave 只需要等待 Master 传回失去连接期间丢失的命令。如果 runid 和本机 id 不一致或者 offset 差距超过了复制积压缓冲区大小,那么就会返回 FULLRESYNC runid offset,Slave 将 runid 保存起来,并进行全量同步。

主节点在命令传播时,主数据库会将每一个写命令传递给从数据库的同时,都会将写命令存放到积压队列,并记录当前积压队列中存放命令的全局偏移量 offset。当 salve 重连接时,master 会根据从节点传的 offset 在环形积压队列中找到断开这段时间执行的命令,并同步给 salve 节点,达到增量同步结果。

PSYNC 执行流程如下图:

从以上 PSYNC 的执行流程可以看出当 slave 节点断线重连以后判断是否采用增量同步的核心是 slave 的 offset 偏移量和 master 的偏移量相差有没有超过复制积压缓冲区大小,那么这个大小是由以下参数来配置的。复制积压缓冲区本质上是一个固定长度的循环队列,默认情况下积压队列的大小为 1MB,可以通过配置文件设置队列大小:设置复制积压缓冲区大小,积压队列越大,允许主从数据库断线的时间就越长

repl-backlog-size 1mb

Redis 同时也提供了当没有 slave 需要同步的时候,多久可以释放环形队列,默认一小时,没有 salve 连接时,多久释放一次复制积压缓冲区

repl-backlog-ttl 3600

四、主从复制策略

Redis 采用了乐观复制的策略,也就是在一定程度内容忍主从数据库的内容不一致,但是保持主从数据库数据的最终一致性。具体来说,Redis 在主从复制的过程中,本身就是异步的,在主从数据库执行完客户端请求后会立即将结果返回给客户端,并异步的将命令同步给从数据库,但是这里并不会等待从数据库完全同步之后,再返回客户端。这一特性虽然保证了主从复制期间性能不受影响,但是也会产生一个数据不一致的时间窗口,如果在这个时间窗口期间网络突然断开连接,就会导致两者数据不一致。如果不在配置文件中添加其他策略,那就默认会采用这种方式。为了防止主从不一致不可控,redis 提供了以下两个参数来做约束:

min-slaves-to-write 3
min-slaves-max-lag 10

当 slave 数量小于 min-slaves-to-write,且延迟小于等于 min-slaves-max-lag 时,master 停止写入操作。

还有一个参数也会影响主从之间的延时:

repl-disable-tcp-nodelay:

设置成 yes,则 redis 会合并小的 TCP 包从而节省带宽,但会增加同步延迟,造成 master 与 slave 数据不一致。设置成 no,则 redis master 会立即发送同步数据,几乎没有延迟。

Redis 的主从同步无论那种场景可以抽象为以下七个步骤:

1. 建立 socket 连接

从服务器根据设置的套接字创建连向主服务器的套接字连接,主服务器接收从服务器的套接字连接之后,为该套接字创建响应的客户端状态,并将此时的从服务器看做是主服务器的客户端,也就是该从服务器同时具备服务器与客户端两个身份。

2. 发送 PING 命令

PING 命令主要有两种作用:虽然建立了套接字连接,但是还未使用过,通过发送 PING 命令检查套接字的读写状态是否正常;通过发送 PING 命令检查主服务器能否正常处理命令请求,能处理主服务器回复 PONG。

3. 身份验证

从服务器接收到主服务器返回的“PONG”回复,接下来就需要考虑身份验证的事。如果从服务器设置了 masterauth 选项,那么进行身份验证,如果从服务器没有设置 masterauth 选项,那么不进行身份验证。

4. 发送端口信息

在身份验证步骤之后,从服务器将执行命令 REPLCONF listening-port,向主服务器发送从服务器的监听端口号。

5. 数据同步

从服务器向主服务器发送 SYNC 命令、PSYNC 命令,执行同步操作。

6. 命令传播

主从服务器就会进入命令传播阶段,主服务器只要将自己执行的写命令发送给从服务器,而从服务器只要一直执行并接收主服务器发来的写命令。

以上是“Redis 中主从同步机制的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-19发表,共计4365字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)