建立复制
配置复制的方式有以下三种:
1) 在配置文件中加入slaveof{masterHost}{masterPort}随Redis启动生效。 2) 在redis-server启动命令后加入--slaveof{masterHost}{masterPort}生效。 3) 直接使用命令: slaveof{masterHost}{masterPort}生效。
断开复制
从节点执行slaveof no one来断开复制
安全性
主节点会通过设置requirepass参数进行密码验证,这时所有的客户端访问必须使用auth命令实行校验。=
从节点与主节点的复制连接是通过一个特殊标识的客户端来完成,因此需要配置从节点的masterauth参数与主节点密码保持一致, 这样从节点才可以正确地连接到主节点并发起复制流程。
只读
默认情况下, 从节点使用slave-read-only=yes配置为只读模式。
可以通过命令config set slave-read-only 来动态设置是否只读。
生产环境不建议修改从节点的只读模式。
传输延迟
主从节点一般部署在不同机器上, 复制时的网络延迟就成为需要考虑的问题,Redis为我们提供了repl-disable-tcp-nodelay参数用于控制是否关闭TCP_NODELAY, 默认关闭。
参数说明如下:
·当关闭时,主节点产生的命令数据无论大小都会及时地发送给从节点, 这样主从之间延迟会变小, 但增加了网络带宽的消耗。 适用于主从之间的网络环境良好的场景, 如同机架或同机房部署。
·当开启时,主节点会合并较小的TCP数据包从而节省带宽。 默认发送时间间隔取决于Linux的内核, 一般默认为40毫秒。 这种配置节省了带宽但增大主从之间的延迟。 适用于主从网络环境复杂或带宽紧张的场景, 如跨机房部署。
注:
部署主从节点时需要考虑网络延迟、 带宽使用率、 防灾级别等因素,
如果要求低延迟时, 建议同机架或同机房部署并关闭repl-disable-tcp-nodelay;
如果考虑高容灾性, 可以同城跨机房部署并开启repl-disable-tcp-nodelay。
拓扑
Redis的复制拓扑结构可以支持单层或多层复制关系, 根据拓扑复杂性可以分为以下三种: 一主一从、 一主多从、 树状主从结构。
复制过程
在从节点执行slaveof命令后, 复制过程便开始运作, 下面详细介绍建立复制的完整流程。
1) 保存主节点(master) 信息。执行slaveof后从节点只保存主节点的地址信息便直接返回,这时建立复制流程还没有开始。 2) 从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后, 会尝试与该节点建立网络连接。 3) 发送ping命令。连接建立成功后从节点发送ping请求进行首次通信。 4) 权限验证。 如果主节点设置了requirepass参数, 则需要密码验证,从节点必须配置masterauth参数保证与主节点相同的密码才能通过验证; 如果验证失败复制将终止, 从节点重新发起复制流程。 5) 同步数据集。 主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点, 这部分操作是耗时最长的步骤。 6) 命令持续复制。 当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。 接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性。
数据同步
Redis在2.8及以上版本使用psync命令完成主从数据同步, 同步过程分为: 全量复制和部分复制。
·全量复制: 一般用于初次复制场景,Redis早期支持的复制功能只有全量复制,它会把主节点全部数据一次性发送给从节点, 当数据量较大时,会对主从节点和网络造成很大的开销。
·部分复制: 用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许, 主节点会补发丢失数据给从节点。 因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销。
注:部分复制是对老版复制的重大优化,有效避免了不必要的全量复制操作。因此当使用复制功能时,尽量采用2.8以上版本的Redis。
psync命令运行需要以下组件支持:
·主从节点各自复制偏移量。
·主节点复制积压缓冲区。
·主节点运行id。
psync命令
从节点使用psync命令完成部分复制和全量复制功能。
命令格式:psync{runId}{offset}
参数含义如下:
·runId: 从节点所复制主节点的运行id。
·offset: 当前从节点已复制的数据偏移量。
psync命令运行流程:
1) 从节点(slave) 发送psync命令给主节点, 参数runId是当前从节点保存的主节点运行ID, 如果没有则默认值为, 参数offset是当前从节点保存的复制偏移量, 如果是第一次参与复制则默认值为-1。 2) 主节点(master) 根据psync参数和自身数据情况决定响应结果: ·如果回复+FULLRESYNC{runId}{offset}, 那么从节点将触发全量复制流程。 ·如果回复+CONTINUE, 从节点将触发部分复制流程。 ·如果回复+ERR, 说明主节点版本低于Redis2.8,无法识别psync命令,从节点将发送旧版的sync命令触发全量复制流程。
全量复制
全量复制是Redis最早支持的复制方式, 也是主从第一次建立复制时必须经历的阶段。
1) 从节点发送psync命令进行数据同步,由于是第一次进行复制,从节点没有复制偏移量和主节点的运行ID,所以发送psync-1。 2) 主节点根据psync-1解析出当前为全量复制,回复+FULLRESYNC响应。 3) 从节点接收主节点的响应数据保存运行ID和偏移量offset。 4) 主节点执行bgsave保存RDB文件到本地。 5) 主节点发送RDB文件给从节点, 从节点把接收的RDB文件保存在本地并直接作为从节点的数据文件。 6) 对于从节点开始接收RDB快照到接收完成期间,主节点仍然响应读写命令, 因此主节点会把这期间写命令数据保存在复制客户端缓冲区内,当从节点加载完RDB文件后, 主节点再把缓冲区内的数据发送给从节点,保证主从之间数据一致性。
如果主节点创建和传输RDB的时间过长, 对于高流量写入场景非常容易造成主节点复制客户端缓冲区溢出。
默认配置为clientoutput-buffer-limit slave 256MB 64MB 60, 如果60秒内缓冲区消耗持续大于64MB或者直接超过256MB时, 主节点将直接关闭复制客户端连接, 造成全量同步失败。 7) 从节点接收完主节点传送来的全部数据后会清空自身旧数据。 8) 从节点清空数据后开始加载RDB文件,对于较大的RDB文件,这一步操作依然比较耗时, 可以通过计算日志之间的时间差来判断加载RDB的总耗时。 9) 从节点成功加载完RDB后,如果当前节点开启了AOF持久化功能,它会立刻做bgrewriteaof操作, 为了保证全量复制后AOF持久化文件立刻可用。
通过分析全量复制的所有流程,会发现全量复制是一个非常耗时费力的操作。 它的时间开销主要包括:
·主节点bgsave时间。
·RDB文件网络传输时间。
·从节点清空数据时间。
·从节点加载RDB的时间。
·可能的AOF重写时间
部分复制
部分复制主要是Redis针对全量复制的过高开销做出的一种优化措施,使用psync{runId}{offset}命令实现。
当从节点(slave) 正在复制主节点(master) 时,如果出现网络闪断或者命令丢失等异常情况时,从节点会向主节点要求补发丢失的命令数据,如果主节点的复制积压缓冲区内存在这部分数据则直接发送给从节点,这样就可以保持主从节点复制的一致性。 补发的这部分数据一般远远小于全量数据, 所以开销很小。
流程说明:
1) 当主从节点之间网络出现中断时,如果超过repl-timeout时间,主节点会认为从节点故障并中断复制连接。 2) 主从连接中断期间主节点依然响应命令,但因复制连接中断命令无法发送给从节点, 不过主节点内部存在的复制积压缓冲区, 依然可以保存最近一段时间的写命令数据,默认最大缓存1MB。 3) 当主从节点网络恢复后,从节点会再次连上主节点。 4) 当主从连接恢复后,由于从节点之前保存了自身已复制的偏移量和主节点的运行ID。 因此会把它们当作psync参数发送给主节点,要求进行部分复制操作。 5) 主节点接到psync命令后首先核对参数runId是否与自身一致,如果一致,说明之前复制的是当前主节点; 之后根据参数offset在自身复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中 则对从节点发送+CONTINUE响应, 表示可以进行部分复制。 6) 主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态。
心跳
主从心跳判断机制:
1) 主从节点彼此都有心跳检测机制,各自模拟成对方的客户端进行通信,通过client list命令查看复制相关客户端信息, 主节点的连接状态为flags=M,从节点连接状态为flags=S。 2) 主节点默认每隔10秒对从节点发送ping命令,判断从节点的存活性和连接状态。 可通过参数repl-ping-slave-period控制发送频率。 3) 从节点在主线程中每隔1秒发送replconf ack{offset}命令,给主节点上报自身当前的复制偏移量。
异步复制
主节点不但负责数据读写, 还负责把写命令同步给从节点。 写命令的发送过程是异步完成, 也就是说主节点自身处理完写命令后直接返回给客户端, 并不等待从节点复制完成。
主节点复制流程:
1) 主节点6379接收处理命令。 2) 命令处理完之后返回响应结果。 3) 对于修改命令异步发送给从节点, 从节点在主线程中执行复制的命令。