通过这篇文章你会知道如下:
- 如何配置主从关系?如何断开主从关系?如何将从节点变成主节点?
- 主从复制的拓扑结构以及相应的优缺点?
- 复制过程是如何的? 主从是如何进行数据同步的?
- 全量复制与部分复制过程是如何的?
-
配置复制的方式
- 在配置文件中加入slaveof {masterHost} {masterPort}随Redis启动生效。
- 在redis-server启动命令后加入--slaveof {masterHost} {masterPort}生效。
- 直接使用命令: slaveof{masterHost}{masterPort}生效
slaveof配置都是在从节点发起,在从节点上进行以上配置
-
从节点注意点
- slaveof no one 断开复制,从节点变成主节点,但是数据不会消失
- 从节点更换主节点,则数据会清空
- 默认情况下, 从节点使用slave-read-only=yes配置为只读模式,所以一般不修改从节点的信息
- 复制时传输数据的网络延迟,Redis为我们提供了repl-disable-tcp-nodelay参数用于控制是否关闭TCP_NODELAY, 默认关闭,如果关闭,则主节点的数据都发送给从节点,增加网络带宽,适合网络环境好;开启则会有间隔的发送数据,增大主从之间的延迟
-
主从拓扑结构
- 一主一从
用于主节点出现宕机时从节点提供故障转移支持, 当应用写命令并发量较高且需要持久化时, 可以只在从节点上开启AOF, 这样既保证数据安全性同时也避免了持久化对主节点的性能干扰 - 一主多从
利用多个从节点进行读写分离
读多的场景,可以分发读命令到从节点进行,减少主节点的压力,也可以减少一些耗时的读命令造成的慢查询压力。
写并发量较高的场景, 多个从节点会导致主节点写命令的多次发送从而过度消耗网络带宽, 同时也加重了主节点的负载影响服务稳定性。 - 树状主从
树状主从结构(又称为树状拓扑结构) 使得从节点不但可以复制主节点数据, 同时可以作为其他从节点的主节点继续向下层复制。 通过引入复制中间层, 可以有效降低主节点负载和需要传送给从节点的数据量。 当主节点需要挂载多个从节点时为了避免对主节点的性能干扰, 可以采用树状主从结构降低主节点压力
-
复制原理
-
复制过程
a.保存主节点信息
b.从节点(slave) 内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后, 会尝试与该节点建立网络连接
c. 发送ping命令,检测主从之间网络套接字是否可用,检测主节点当前是否可接受处理命令,从节点没有收到主节点的pong回复或者超时,从节点会断开复制连接, 下次定时任务会发起重连
d.权限验证
e.同步数据集。 主从复制连接正常通信后, 对于首次建立复制的场景, 主节点会把持有的数据全部发送给从节点
f.命令的持续复制 -
数据同步
A--参与复制的主从节点都会维护自身复制偏移量。 主节点(master) 在处369理完写入命令后, 会把命令的字节长度做累加记录, 统计信息在inforelication中的master_repl_offset指标中
B--从节点(slave) 每秒钟上报自身的复制偏移量给主节点, 因此主节点也会保存从节点的复制偏移量offset
C--从节点在接收到主节点发送的命令后, 也会累加记录自身的偏移量。 统计信息在info relication中的slave_repl_offset指标中
D--可以通过主节点的统计信息, 计算出master_repl_offset-slave_offset字节量, 判断主从节点复制相差的数据量 -
复制积压缓冲区
复制积压缓冲区是保存在主节点上的一个固定长度的队列, 默认大小为1MB, 当主节点有连接的从节点(slave) 时被创建, 这时主节点(master)响应写命令时, 不但会把命令发送给从节点, 还会写入复制积压缓冲区,用于部分复制和复制命令丢失的数据补救
-
全量复制
A-- 发送psync命令进行数据同步, 由于是第一次进行复制, 从节点没有复制偏移量和主节点的运行ID, 所以发送psync-1。
B--主节点根据psync-1解析出当前为全量复制, 回复+FULLRESYNC响应。
C-- 从节点接收主节点的响应数据保存运行ID和偏移量offset, 执行到当前步骤时从节点打印如下日志:
Full resync from master: 92d1cb14ff7ba97816216f7beb839efe036775b2:216789
D--主节点执行bgsave保存RDB文件到本地
E--主节点发送RDB文件给从节点, 从节点把接收的RDB文件保存在本地并直接作为从节点的数据文件,如果此时文件过大,超出repl-timeout时间,则会导致全量复制失败
MASTER <-> SLAVE sync: receiving 24777842 bytes from master
F--从节点接受RDB文件这段期间,主节点会继续响应命令,会这这期间的命令存入客户端缓冲区,当从完成接收文件后,会将缓冲区的命令发送给从,保证数据一致性,如果这期间高流量的写入会可能导致缓冲区溢出,主会关闭复制客户端连接,导致全量复制失败,可以设置clientoutput-buffer-limit slave参数调整缓冲区大小,主节点完成数据传输后,打印Synchronization with slave127.0.0.1: 6380succeeded
G--从接收完所有数据后,会清空自身数据 MASTER <-> SLAVE sync: Flushing old data
H--从节点清空数据后开始加载RDB文件 SLAVE sync: Loading DB in memory
I--从节点成功加载完RDB后, 如果当前节点开启了AOF持久化功能,它会立刻做bgrewriteaof操作, 为了保证全量复制后AOF持久化文件立刻可用。
主要的耗时阶段:
主节点bgsave时间。
RDB文件网络传输时间。
从节点清空数据时间。
从节点加载RDB的时间。
可能的AOF重写时间。 -
部分复制
含义:部分复制主要是Redis针对全量复制的过高开销做出的一种优化措施,使用psync{runId}{offset}命令实现。 当从节点(slave) 正在复制主节点(master) 时, 如果出现网络闪断或者命令丢失等异常情况时, 从节点会向主节点要求补发丢失的命令数据, 如果主节点的复制积压缓冲区内存在这部分数据则直接发送给从节点, 这样就可以保持主从节点复制的一致性。 补发的这部分数据一般远远小于全量数据
当主从之间的网络出现中断的时候,各自都会在日志中打印失去连接的信息,同时主节点继续响应命令,同时会将命令保存在复制积压缓冲区,当从节点再次连接到主节点时,主节点核实从节点发送的Id和偏移量,在自己的缓冲区中查询,如果偏移量后的数据在缓冲区,则发送给从节点 -
心跳
主节点默认每隔10秒对从节点发送ping命令, 判断从节点的存活性和连接状态。 可通过参数repl-ping-slave-period控制发送频率。
从节点在主线程中每隔1秒发送replconf ack{offset}命令, 给主节点上报自身当前的复制偏移量。
在info replication统
计中的lag信息中, lag表示与从节点最后一次通信延迟的秒数, 正常延迟应该在0和1之间。 如果超过repl-timeout配置的值(默认60秒) , 则判定从节点下线并断开复制客户端连接。 即使主节点判定从节点下线后, 如果从节点重新恢复, 心跳检测会继续进行
-
问题分析
-
读写分离,从节点读取的数据延迟
刚在主节点写入数据后立刻在从节点上读取可能获取不到。 需要业务场景允许短时间内的数据延迟。 对于无法容忍大量延迟场景, 可以编写外部监控程序监听主从节点的复制偏移量, 当延迟较大时触发报警或者通知客户端避免读取延迟过高的从节点 - 从节点读取数据之前会检查键的过期时间来决定是否返回数据,所以从节点读取不存在过期数据
-
规避全量复制
a--当对数据量较大且流量较高的主节点添加从节点时, 建议在低峰时进行操作, 或者尽量规避使用大数据量的Redis节点
b--主节点如果因故障重启,导致run id发生变化,会导致从节点进行全量复制,对于这种情况应该从架构上规避, 比如提供故障转移功能。 当主节点发生故障后, 手动提升从节点为主节点或者采用支持自动故障转移的哨兵或集群方案
c-- 复制积压缓冲区不足,当主从节点网络中断后, 从节点再次连上主节点时会发送psync{offset}{runId}命令请求部分复制, 如果请求的偏移量不在主节点的积压缓冲区内, 则无法提供给从节点数据, 因此部分复制会退化为全量复制。 这种需要合理是设计缓冲区大小