一、简介:
在分布式系统中为了解决单点问题,通常会把数据复制多个副本部署到其他机器,满足故障恢复和负载均衡等需求。Redis
也是如此,它为我们提 供了复制功能,实现了相同数据的多个Redis
副本。复制功能是高可用
Redis的基础
二、Redis的复制拓扑结构
1.一主一从结构
一主一从结构是最简单的复制拓扑结构,用于主节点出现宕机时从节点提供故障转移支持
2.一主多从结构(又称为星形拓扑结构)
使得应用端可以利用多个从节点实现读写分离
。对于读占比较大的场景,可以把读命令发送到从节点来分担主节点压力。同时在日常开发中如果需要执行一些比较耗时的读命令,如:keys
、
sort
等,可以在其中一台从节点上执行,防止慢查询对主节点造成阻塞从而影响线上服务的稳定性。对于写并发量较高的场景,多个从节点会导致主节点写命令的多次发送从而过度消耗网络带宽,同时也加重了主节点的负载影响服务稳定性
3.树状主从结构
树状主从结构(又称为树状拓扑结构)使得从节点不但可以复制主节点数据,同时可以作为其他从节点的主节点继续向下层复制。通过引入复制中间层,可以有效降低主节点负载和需要传送给从节点的数据量。数据写入节点A
后会同步到
B
和
C
节点,
节点再把数据同步到
D
和
E
节点,数据实现了一层一层的向下复制。当主节点需要挂载多个从节点时为避免对主节点的性能干扰,可以采用树状主从结构降低主节点压力。
三、配置
1.建立复制
参与复制的
Redis
实例划分为主节点(
master
)和从节点(
slave
)。默认 情况下,Redis
都是主节点。每个从节点只能有一个主节点,而主节点可以 同时具有多个从节点。复制的数据流是单向的,只能由主节点复制到从节 点。配置复制的方式有以下三种
(1)
在配置文件中加入
slaveof{masterHost}{masterPort}
随
Redis
启动生效。
(2)在
redis-server
启动命令后加入
--slaveof{masterHost}{masterPort}
生效。
(3)直接使用命令:
slaveof{masterHost}{masterPort}
生效。
2.断开复制
slaveof
命令不但可以建立复制,还可以在从节点执行
slaveof no one
来断开与主节点复制关系。例如在6380
节点上执行
slaveof no one
来断开复制
3.只读配置
默认情况下,从节点使用
slave-read-only=yes
配置为只读模式。由于复制只能从主节点到从节点,对于从节点的任何修改主节点都无法感知,修改从节点会造成主从数据不一致。因此建议线上不要修改从节点的只读模式
4.传输延迟配置
主从节点一般部署在不同机器上,复制时的网络延迟就成为需要考虑的 问题,Redis
为我们提供了
repl-disable-tcp-nodelay
参数用于控制是否关闭 TCP_NODELAY,默认关闭
当关闭时,主节点产生的命令数据无论大小都会及时地发送给从节点,这样主从之间延迟会变小,但增加了网络带宽的消耗。适用于主从之间的网络环境良好的场景,如同机架或同机房部署。
当开启时,主节点会合并较小的
TCP
数据包从而节省带宽。默认发送时间间隔取决于Linux
的内核,一般默认为
40
毫秒。这种配置节省了带宽但增大主从之间的延迟。适用于主从网络环境复杂或带宽紧张的场景,如跨机房部署。
四、主从复制流程
1.保存主节点(master)信息:执行slaveof后从节点只保存主节点的地址信息便直接返回,这时建立复制流程还没有开始
2.从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑, 当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接
3.发送ping命令。用来检测主从之间网络套接字是否可用和主节点当前是否可接受处理命令,如果发送ping命令后,从节点没有收到主节点的pong回复或者超时,比如网络超时或者主节点正在阻塞无法响应命令,从节点会断开复制连接
4. 权限验证:如果主节点设置了requirepass参数,则需要密码验证, 从节点必须配置masterauth参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程
5.同步数据集。主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤,后面会详讲
6.命令持续复制。当主节点把当前的数据同步给从节点后,便完成了 复制的建立流程。接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性
![](https://img-blog.csdnimg.cn/20210421084313830.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poYW5nMDkwOTA2MDY=,size_16,color_FFFFFF,t_70)
五、数据同步方式
1.全量复制
一般用于初次复制场景,
Redis
早期支持的复制功能只有全量复制,它会把主节点全部数据一次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销。
1.1.全量复制流程
(1)发送
psync
命令进行数据同步,由于是第一次进行复制,从节点没有 复制偏移量和主节点的运行ID
,所以发送
psync-1
。
(2)主节点根据
psync-1
解析出当前为全量复制,回复
+FULLRESYNC
响 应。
(3)从节点接收主节点的响应数据保存运行
ID
和偏移量
offset
2.部分复制
用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发丢失数据给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过 高开销
2.1部分复制流程
(1)复制偏移量:
参与复制的主从节点都会维护自身复制偏移量。
主节点(master)在处理完写入命令后,会把命令的字节长度做累加记录,统计信息在info relication中的master_repl_offset指标中
从节点(
slave
)每秒钟上报自身的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量
从节点在接收到主节点发送的命令后,也会累加记录自身的偏移量。统计信息在info relication
中的
slave_repl_offset
指标中
(2)复制积压缓冲区
复制积压缓冲区是保存在主节点上的一个固定长度的队列,默认大小为1MB,当主节点有连接的从节点(
slave
)时被创建,这时主节点(
master)响应写命令时,不但会把命令发送给从节点,还会写入复制积压缓冲区。如果从节点和主节点间发生了网络断连,等从节点再次连接后,可以从复制积压缓冲区中同步尚未复制的命令操作。对主从同步的影响:如果从节点和主节点间的网络断连时间过长,复制积压缓冲区可能被新写入的命令覆盖。此时,从节点就没有办法和主节点进行增量复制了,而是只能进行全量复制。针对这个问题,应对的方法是调大复制积压缓冲区的大小
由于缓冲区本质上是先进先出的定长队列,所以能实现保存最近已复制 数据的功能,用于部分复制和复制命令丢失的数据补救。复制缓冲区相关统计信息保存在主节点的
info replication
中,
使用复制积压缓冲区主要是为了防止部分复制中如果直接使用从节点的缓存区接受主节点传输过来的数据可能会被撑满,导致内存不足的问题,所以引入复制积压缓冲区,如果复制积压缓冲区也满了就先终止主从复制,消化了再继续
(3)主节点运行ID
每个
Redis
节点启动后都会动态分配一个
40
位的十六进制字符串作为运行ID
。运行
ID
的主要作用是用来唯一识别
Redis
节点,比如从节点保存主节 点的运行ID
识别自己正在复制的是哪个主节点。如果只使用
ip+port
的方式识 别主节点,那么主节点重启变更了整体数据集(如替换RDB/AOF
文件), 从节点再基于偏移量复制数据将是不安全的,因此当运行ID
变化后从节点将 做全量复制
3.异步复制
主节点不但负责数据读写,还负责把写命令同步给从节点。写命令的发 送过程是异步完成,也就是说主节点自身处理完写命令后直接返回给客户端,并不等待从节点复制完成
主节点复制流程:
1
)主节点
接收并处理命令。
2
)命令处理完之后返回响应结果。
3
)对于修改命令异步发送给
从节点,从节点在主线程中执行复制 的命令。由于主从复制过程是异步的,就会造成从节点的数据相对主节点存在延迟。
六、心跳检测机制
主从节点在建立复制后,它们之间维护着长连接并彼此发送心跳命令
主从心跳判断机制:
1
)主从节点彼此都有心跳检测机制,各自模拟成对方的客户端进行通信,通过client list
命令查看复制相关客户端信息,主节点的连接状态为 flags=M,从节点连接状态为
flags=S
。
2
)主节点默认每隔
10
秒对从节点发送
ping
命令,判断从节点的存活性和连接状态。可通过参数repl-ping-slave-period
控制发送频率。
3
)从节点在主线程中每隔
1
秒发送
replconf ack{offset}
命令,给主节点上报自身当前的复制偏移量。
七、读写分离
1.简介
对于读占比较高的场景,可以通过把一部分读流量分摊到从节点 (slave
)来减轻主节点(
master
)压力,同时需要注意永远只对主节点执行写操作
2.读写分离会产生的问题
(1)数据延迟
Redis复制数据的延迟由于异步复制特性是无法避免的,延迟取决于网 络带宽和命令阻塞情况,比如刚在主节点写入数据后立刻在从节点上读取可 能获取不到。需要业务场景允许短时间内的数据延迟。
解决方案:
当延迟较大时触发报警或者通知客户端避免读取延迟过高的从节点
(2)读到过期的数据
当主节点存储大量设置超时的数据时,如缓存数据,
Redis
内部需要维护过期数据删除策略,删除策略主要有两种:惰性删除和定时删除
惰性删除
:
主节点每次处理读取命令时,都会检查键是否超时,如果超 时则执行del
命令删除键对象,之后
del
命令也会异步发送给从节点。需要注 意的是为了保证复制的一致性,从节点自身永远不会主动删除超时数据
定时删除
:
Redis
主节点在内部定时任务会循环采样一定数量的键,当 发现采样的键过期时执行del
命令,之后再同步给从节点
3.2版本以前如果此时数据大量超时,主节点采样速度跟不上过期速度且主节点没有 读取过期键的操作,那么从节点将无法收到del命令。
3.从节点故障问题
对于从节点的故障问题,需要在客户端维护可用从节点列表,当从节点 故障时立刻切换到其他从节点或主节点上。这个过程类似上文提到的针对延 迟过高的监控处理,需要开发人员改造客户端类库
八、规避全量复制
全量复制是一个非常消耗资源的操作,前面做了具体说明。因此如何规避全量复制是需要关注重点,以下是全量复制的场景
1.第一次建立复制
由于是第一次建立复制,从节点不包含任何主节点 数据,因此必须进行全量复制才能完成数据同步。对于这种情况全量复制无 法避免
2.节点运行ID不匹配
当主从复制关系建立后,从节点会保存主节点的 运行ID
,如果此时主节点因故障重启,那么它的运行
ID
会改变,从节点发现主节点运行ID
不匹配时,会认为自己复制的是一个新的主节点从而进行全量复制
规避方案:对于这种情况应该从架构上规避,比如提供故障转移功能。当主节点发生故障后,手动提升从节点为主节点或者采用支持自动故障转移的哨兵或集群方案(后面章节会详细介绍)
3.复制积压缓冲区不足
当主从节点网络中断后,从节点再次连上主节点时会发送 psync {offset} {runId} 命令请求部分复制,如果请求的偏移量不在主节点的积压缓冲区内,则无法提供给从节点数据,因此部分复制会退化为全量复制
解决方案:
针对这种情况需要根据网络中断时长,写命令数据量分析出合理的积压缓冲区大小。网络中断一般有闪断、机房割接、网络分区等情况。这时网络中断的时长一般在分钟级(net_break_time)。写命令数据量可以统计高峰期主节点每秒inforeplication的master_repl_offset差值获取(write_size_per_minute)。积压缓冲区默认为1MB,对于大流量场景显然不够,这时需要增大积压缓冲区,保证repl_backlog_size>net_break_time*write_size_per_minute,从而避免因复制积压缓冲区不足造成的全量复制。
九、规避复制风暴
复制风暴是指大量从节点对同一主节点或者对同一台机器的多个主节点 短时间内发起全量复制的过程。复制风暴对发起复制的主节点或者机器造成 大量开销,导致CPU
、内存、带宽消耗。因此我们应该分析出复制风暴发生的场景,提前采用合理的方式规避。规避方式有如下几个。
1.单主节点复制风暴
单主节点复制风暴一般发生在主节点挂载多个从节点的场景。当主节点 重启恢复后,从节点会发起全量复制流程,这时主节点就会为从节点创建 RDB快照,如果在快照创建完毕之前,有多个从节点都尝试与主节点进行全
量同步,那么其他从节点将共享这份RDB
快照。这点
Redis
做了优化,有效避免了创建多个快照。但是,同时向多个从节点发送RDB
快照,可能使主节 点的网络带宽消耗严重,造成主节点的延迟变大,极端情况会发生主从节点 连接断开,导致复制失败。
解决方案:
首先可以减少主节点(master
)挂载从节点(
slave
)的数量,
或者采用树状复制结构,加入中间层从节点用来保护主节点
2.单机器复制风暴
由于
Redis
的单线程架构,通常单台机器会部署多个
Redis
实例。当一台机器(machine
)上同时部署多个主节点(
master)时如果这台机器出现故障或网络长时间中断,当它重启恢复后,会有大量从节点(slave)针对这台机器的主节点进行全量复制,会造成当前机器网络带宽耗尽
解决方案:
(1)应该把主节点尽量分散在多台机器上,避免在单台机器上部署过多的主节点。
(2)当主节点所在机器故障后提供故障转移机制,避免机器恢复后进行密集的全量复制。