Redis 主从复制

  前言

  主从复制就是把主节点(master)上的数据复制到从节点(slave)上,以满足故障恢复和负载均衡等需求,复制功能是高可用 Redis 的基础。

  复制设置

  我们在本机建两个实例(Redis 多实例可以参考:Windows 下安装多个Redis 实例),一个端口为6380的作为主节点,一个端口为6381的作为从节点。由于主节点配置了密码,我们需要在从节点配置文件里设置主节点的密码masterauth。

  建立复制一共有三种方式
  1.在配置文件中设置

  2.在Redis 启动时设置,命令如下
  redis-server.exe --service-start --service-name redis6381 --slaveof {masterHost}{masterPort}

  3.在Redis 启动后设置,命令如下
  slaveof {masterHost} {masterPort}
  我们以启动后设置为例:

  执行后两个节点之间就建立了复制关系,使用 info replication 命令查看复制相关状态

  同样我们也可以在主节点查看复制状态

  首次复制时主节点会把所有数据发送给从节点,然后主节点会持续地把写命令发送给从节点, 保证主从数据一致性。
  在主节点执行命令

  在从节点执行命令

  可以看到复制已经开始了。
  每个从节点只能有一个主节点, 而主节点可以同时具有多个从节点。 复制的数据流是单向的, 只能由主节点复制到从节点,所以修改从节点会造成主从数据不一致,默认情况下,从节点使用slave-read-only yes配置为只读模式,当你尝试修改数据时会出现如下错误

  正常情况下线上不要修改从节点的只读模式。

  延迟设置

  一般主从节点都部署在不同机器上,这样就得考虑网络的延迟问题, Redis为我们提供了repl-disable-tcp-nodelay参数用于控制是否关闭TCP_NODELAY(tcp不延迟传输), 默认关闭(禁用Nagle算法)。

  ·当设置为no时,tcp不延迟传输,主节点产生的命令数据无论大小都会及时地发送给从节点, 这样主从之间延迟会变小,但增加了网络带宽的消耗。适用于主从之间的网络环境良好的场景,如同机架或同机房部署。
  ·当设置为yes时,tcp延迟传输(启用Nagle算法),主节点会合并较小的TCP数据包从而节省带宽。默认发送时间间隔取决于Linux的内核,一般默认为40毫秒。这种配置节省了带宽但增大主从之间的延迟。适用于主从网络环境复杂或带宽紧张的场景,如跨机房部署。

  断开复制

  在从节点上执行 slaveof no one 可以断开与主节点复制关系,从节点断开复制后并不会抛弃原有数据, 只是无法再获取主节点上的数据变化。
  在从节点上执行 slaveof {newMasterIp} {newMasterPort} 命令可以切换新的主节点,这时从节点会删除当前所有数据,然后对新的主节点进行数据复制。

  复制过程

  在从节点执行slaveof命令后, 复制过程便开始运作,主要有以下六个步骤
  1) 保存主节点(master) 信息。
  slaveof 是一个异步命令,执行后从节点保存主节点的地址信息便直接返回。
  2)建立主从socket连接
  从节点根据保存的主节点信息,创建连接主节点的 socket 连接,如果从节点无法建立连接, 定时任务会无限重试直到连接成功或者执行 slaveof no one取消复制。连接失败时,可以在从节点执行info replication查看master_link_down_since_seconds指标,它会记录与主节点连接失败的系统时间。
  3) 发送ping命令。
  发送ping请求主要目的有两个:
  ·检测主从之间网络套接字是否可用。
  ·检测主节点当前是否可接受处理命令。
  4) 权限验证。 如果主节点设置了requirepass参数,则需要密码验证,从节点必须配置masterauth参数保证与主节点相同的密码才能通过验证。
  5)同步数据集。
  主从复制连接正常通信后,首次连接将会执行全量复制。
  6)命令持续复制。
  主从节点数据同步后,主节点会持续地把写命令发送给从节点, 保证主从数据一致性。

  复制原理

  全量复制  

  主从节点首次连接将会进行全量复制。执行 slaveof 127.0.0.1 6380 命令后我们可以打开日志文件,查看日志信息。
  打开从节点日志文件server_log_6381.txt

  打开主节点日志文件server_log_6380.txt

  从以上信息可以看到主要复制过程有这么几个步骤。
  1)双方建立连接。
  2)从节点向主节点发送 SYNC 命令。
  3)主节点收到 SYNC 命令,开始执行 BGSAVE 命令,在后台生成 RDB 文件,同时使用一个缓冲区记录从现在开始的所有写命令。
  4)主节点执行完 BGSAVE 命令后将生成的 RDB 文件发送给从节点,从节点接收 RDB 文件,清空旧数据,然后加载这个 RDB 文件。
  5)主节点将积压缓冲区里记录的写命令发送给从节点,从节点接收这些命令并执行。
  以上就是首次复制的过程,接下来主节点会持续地把写命令发送给从节点, 保证主从数据一致性。
  但是从上面我们也看到 SYNC 命令是一个比较消耗资源的操作,当主从节点断开重连后,从节点会再次执行 SYNC 命令(重复以上2、3、4、5步骤),而实际上我们仅仅需要同步断开期间的数据。Redis 从 2.8 后提供了一个新的命令 PSYNC,可以进行全量复制和部分复制,它的全量复制和SYNC 命令一样,部分复制可以在主从节点断线重连后只同步断开期间的数据,这样就极大的节约了服务器资源。

  在步骤 4)主从节点之间需要传送 RDB 文件,如果 RDB 文件过大,可调大repl-timeout参数以免同步数据超时。

  无盘复制

  如果 RDB 文件过大,还可以使用无盘复制,Redis 从 2.8.18 版开始支持无盘复制。 生成的RDB 文件不保存到硬盘而是直接通过网络发送给从节点,通过repldiskless-sync参数控制,默认关闭。

  psync 命令

  psync {run Id} {offset},run Id 表示所复制主节点的运行id,offset 从节点已复制的数据偏移量。
  从节点(slave) 发送psync命令给主节点,
  如果主节点回复+FULLRESYNC {runId} {offset}, 那么从节点将触发全量复制;
  如果回复+CONTINUE, 从节点将触发部分复制流程;
  如果回复+ERR, 说明主节点版本低于Redis2.8, 无法识别psync命令,从节点将发送旧版的sync命令触发全量复制流程。

  部分复制

  部分复制需要以下数据支持:
  1.主从节点各自复制偏移量(replication offset)。
  2.主节点复制积压缓冲区(replication backlog)。
  3.主节点运行id(run id)。

  复制偏移量

  主从节点都会维护自身复制偏移量,当主节点向从节点发送 n 个字节的数据时,就将自己的偏移量加 n。从节点接收主节点发送过来的 n 个字节的数据时,就将自己的偏移量加 n。使用info replication 命令查看偏移量。
  从节点查看slave_repl_offset

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

  通过对比主从节点的复制偏移量, 可以判断主从节点数据是否一致。如果执行部分同步,主从节点如何同步断开期间的数据呢,这就需要用到复制积压缓冲区。

  复制积压缓冲区

  复制积压缓冲区是保存在主节点上的一个固定长度先进先出的队列, 默认大小为1MB,在主节点有连接的从节点(slave) 时被创建。当主节点(master)响应写命令时, 不但会把命令发送给从节点, 还会写入复制积压缓冲区,换句话说复制积压缓冲区保存了最新的一定长度的数据。当从节点重新连接上主节点时,会把自己的复制偏移量 offset 发送给主节点,如果 offset 之后的数据仍然在复制积压缓冲区中,则主从节点进行部分复制,否则则进行全量复制。所以复制积压缓冲区的大小需要恰当的设置,可以根据公式 second * write_size_per_second 来估算:
  second:表示从节点断线后重新连接上主节点的所需的平均时间(秒)。
  write_size_per_second:主节点平均每秒产生的写命令数量(协议格式的写命令的长度总和)。
  修改复制积压缓冲区大小

  主节点运行ID

  每个 Redis 节点启动后都会动态分配一个40位的十六进制字符串作为运行ID。 运行ID的主要作用是用来唯一识别Redis节点, 从节点在初次连接上主节点时会保存主节点的运行ID,以便识别自己正在复制的是哪个主节点。 需要注意的是 Redis 关闭再启动后, 运行ID会随之改变。如果运行ID变化从节点将做全量复制。
  使用 info server 命令查看节点的运行ID

  心跳

  主从节点在建立复制后, 它们之间维护着长连接并彼此发送心跳命令。
  主节点默认每隔10秒对从节点发送ping命令, 判断从节点的存活性和连接状态。 可通过参数repl-ping-slave-period控制发送频率。
  从节点在主线程中每隔1秒发送replconf ack {offset}命令, 给主节点上报自身当前的复制偏移量。 replconf命令主要作用如下:
  1)监测主从节点网络状态
  主从节点通过发送和接收 replconf 命令来检查两者之间的网络连接。在主节点执行 info replication 命令,查看lag信息。

  lag表示距从节点最后一次向主节点发送 replconf ack 命令到现在过了多少秒, 正常延迟应该在0和1之间。
  2)检测命令丢失
  从节点会上报自身复制偏移量,如果主节点对比发现数据丢失(主节点发送给从节点的写命令丢失),会从复制积压缓冲区中拉取丢失数据发送给从节点。
  3)辅助实现 min-slaves 配置选项

  若配置以上设置则表示在从节点少于三个或者三个从节点的延迟(lag)都大于或等于10秒时,主节点将拒绝执行写命令。

 

  参考书籍:

  《Redis开发与运维》

  《Redis设计与实现》

  《Redis深度历险:核心原理和应用实践》

posted @ 2020-04-08 21:21  王行简  阅读(187)  评论(0编辑  收藏  举报