Redis复制过程详解
主从复制简介
主从复制是为了达成高可用,即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用。
一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
主从复制的作用
读写分离:主节点写,从节点读,提高服务器的读写负载能力
数据冗余︰主从复制实现了数据的热备份,一种数据冗余方式。
故障恢复︰当主节点出现问题时,从节点可以升级为主节点继续提供服务。提供故障恢复的能力。
高可用的基石则是集群高可用。
一、复制过程
阶段一:建立连接
步骤1:设置master的地址和端口,保存master信息
步骤2:建立socket连接
步骤3:发送ping命令(定时器任务)
步骤4:身份验证
步骤5:发送slave端口信息
至此,主从连接成功!
master和slave详细连接流程
slave:1.发送指令:slaveof ip port
master:2.接收到指令,响应从节点PONG。
slave:3.保存master的IP与端口
slave:4.根据保存的信息创建连接master的socket
slave:5.周期性发送命令:ping
master:6.响应pong
slave:7.发送指令:auth password
master:8.验证授权
slave:9.发送指令:replconf listening-port <port-number>
master:10.保存slave的端口号
阶段二:数据同步
在slave初次连接master后,复制master中的所有数据到slave
步骤1:请求同步数据
步骤2:创建RDB同步数据
步骤3:恢复RDB同步数据
步骤4:请求部分同步数据
步骤5:恢复部分同步数据
至此,数据同步工作完成!
master和slave详细同步流程
slave:1.发送指令:psync2
master:2.执行bgsave
master:3.第一个slave连接时,创建命令缓冲区
master:4.生成RDB文件,通过socket发送给slave
slave:5.接收RDB,清空数据,执行RDB文件恢复过程。
slave:6.发送命令告知RDB恢复已经完成
master:7.发送复制缓冲区信息
slave:8.接收信息,执行bgrewriteaof,恢复数据
其中1-5属于全量复制,6-8属于部分复制
数据同步阶段master说明
1:如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行。
2:复制缓冲区大小设定不合理,会导致数据溢出,如进行全量复制周期太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态。 repl-backlog-size 20mb
3:master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执行bgsave命令和创建复制缓冲区
数据同步阶段slave说明
1:为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务。slave-serve-stale-data no, 从服务器将阻塞所有请求,有客户端请求时返回“SYNC with master in progress”; yes则slave可以相应请求。
2:多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,建议在业务低峰期执行。
3:slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,可能导致深度越高的slave与最顶层master间数据同步延迟较大,数据一致性变差,一般情况下不建议配置。
阶段三:命令传播
当master数据库状态被修改后,主从服务器数据库状态是不一致,master将同步rdb阶段接收到的数据变更命令发送给slave,slave接收命令后执行命令。
命令传播阶段出现了断网现象:
网络闪断闪连:忽略
短时间网络中断:部分复制
长时间网络中断:全量复制
部分复制的三个核心要素
服务器的运行id(runid)
主服务器的复制积压缓冲区
主从服务器的复制偏移量
通过offset区分不同的slave当前数据传播的差异
master记录已发送的信息对应的offset
slave记录已接收的信息对应的offset
2、主从节点各自复制偏移量
参与复制的主从节点都会维护自身的复制偏移量。
主节点在处理完写入命令后,会把命令的字节长度做累加记录,统计信息在 info replication 中的 masterreploffset 指标中。
从节点每秒钟上报自身的的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量。
从节点在接收到主节点发送的命令后,也会累加自身的偏移量,统计信息在 info replication 中。
通过对比主从节点的复制偏移量,可以判断主从节点数据是否一致。
3、主节点复制积压缓冲区
复制积压缓冲区是一个保存在主节点的一个固定长度的先进先出的队列,默认大小 1MB。
这个队列在 slave 连接时创建。这时主节点响应写命令时,不但会把命令发送给从节点,也会写入复制缓冲区。
他的作用就是用于部分复制和复制命令丢失的数据补救。通过 info replication 可以看到相关信息。
4、主节点运行ID
每个 redis 启动的时候,都会生成一个 40 位的运行 ID。
运行 ID 的主要作用是用来识别 Redis 节点。如果使用 ip+port 的方式,那么如果主节点重启修改了 RDB/AOF 数据,从节点再基于偏移量进行复制将是不安全的。所以,当运行 id 变化后,从节点将进行全量复制。也就是说,redis 重启后,默认从节点会进行全量复制。
5、如果在重启时不改变运行ID呢?
可以通过 debug reload 命令重新加载 RDB 并保持运行 ID 不变,从而有效的避免不必要的全量复制。
缺点是:debug reload 命令会阻塞当前 Redis 节点主线程,因此对于大数据量的主节点或者无法容忍阻塞的节点,需要谨慎使用。一般通过故障转移机制可以解决这个问题。
从节点发送 psync 命令给主节点,runId 就是目标主节点的 ID,如果没有默认为 -1,offset 是从节点保存的复制偏移量,如果是第一次复制则为 -1.主节点会根据 runid 和 offset 决定返回结果:
如果回复 +FULLRESYNC {runId} {offset} ,那么从节点将触发全量复制流程。
如果回复 +CONTINUE,从节点将触发部分复制。
如果回复 +ERR,说明主节点不支持 2.8 的 psync 命令,将使用 sync 执行全量复制。
二、部分复制
当从节点正在复制主节点时,如果出现网络闪断和其他异常,从节点会让主节点补发丢失的命令数据,主节点只需要将复制缓冲区的数据发送到从节点就能够保证数据的一致性,相比较全量复制,成本小很多。
当从节点出现网络中断,超过了 repl-timeout 时间,主节点就会中断复制连接。
主节点会将请求的数据写入到“复制积压缓冲区”,默认 1MB。
当从节点恢复,重新连接上主节点,从节点会将 offset 和主节点 id 发送到主节点。
主节点校验后,如果偏移量的数后的数据在缓冲区中,就发送 cuntinue 响应 —— 表示可以进行部分复制。
主节点将缓冲区的数据发送到从节点,保证主从复制进行正常状态。
三、心跳
主从节点在建立复制后,他们之间维护着长连接并彼此发送心跳命令。
心跳的关键机制如下:
主从都有心跳检测机制,各自模拟成对方的客户端进行通信,通过 client list 命令查看复制相关客户端信息,主节点的连接状态为 flags = M,从节点的连接状态是 flags = S。
主节点默认每隔 10 秒对从节点发送 ping 命令,可修改配置 repl-ping-slave-period 控制发送频率。
从节点在主线程每隔一秒发送 replconf ack{offset} 命令,给主节点上报自身当前的复制偏移量。
主节点收到 replconf 信息后,判断从节点超时时间,如果超过 repl-timeout 60 秒,则判断节点下线。
心跳阶段注意事项:
当slave多数掉线,或延迟过高时
master为保障数据稳定性,将拒绝所有信息同步
min-slaves-to-write 2
min-slaves-max-lag 8
slave数量少于2个,或者所有slave的延迟都大于等于8秒时,强制关闭master写功能,停止数据同步.
四、异步复制
主节点不但负责数据读写,还负责把写命令同步给从节点,写命令的发送过程是异步完成,也就是说主节点处理完写命令后立即返回客户度,并不等待从节点复制完成。
五、常见问题
1、频繁的全量复制
一旦master重启,runid将发生变化,会导致全部slave的全量复制操作
优化调整方案:
1:master内部创建master_replid变量,使用runid相同的策略生成,长度41位,并发送给所有slave
2:在master关闭时执行命令shutdown save,进行RDB持久化,将runid与offset保存到RDB文件中
repl-id repl-offset 通过redis-check-rdb命令可以查看该信息
3:master重启后加载RDB文件,恢复数据,重启后,将RDB文件中保存的repl-id与repl-offset加载到内存中
master_repl_id=repl master_repl_offset =repl-offset 通过info命令可以查看该信息
2、频繁的全量复制
网络环境不佳,出现网络中断,slave不提供服务。原因复制缓冲区过小,断网后slave的offset越界,触发全量复制
解决办法:
评估rdb数据量大小,评估传输slave的大致时间h。
评估日常redis写入量x/s,x*h = 大致的量,为了保险,建议设置成2倍该大小。
3、频繁的网络中断
master的CPU占用过高或slave频繁断开连接
问题原因:
slave每1秒发送REPLCONF ACK命令到master,当slave接到了慢查询时(keys * ,hgetall等),会大量占用CPU性能。master每1秒调用复制定时函数replicationCron(),比对slave发现长时间没有进行响应
解决方案:
通过设置合理的超时时间,repl-timeout seconds
优化慢查询。
4、频繁的网络中断
slave与master连接断开
问题原因:
master发送ping指令频度较低
master设定超时时间较短
ping指令在网络中存在丢包
解决方案:
提高ping指令发送的频度,repl-ping-slave-period seconds,超时时间repl-time的时间至少是ping指令频度的5到10倍,否则slave很容易判定超时。
5、数据不一致
多个slave获取相同数据不同步
问题原因:
网络信息不同步,数据发送有延迟
解决方案:
优化主从间的网络环境,通常放置在同一个机房部署,如使用云等云服务器时要注意此现象
监控主从节点延迟(通过offset)判断,如果slave延迟过大,暂时屏蔽程序对该slave的数据访问slave-serve-stale-data yes|no
开启后仅响应info、slaveof等少数命令。注意如果开启,则客户端会受到错误。