在分布式系统中为解决单点问题,通常会把数据复制多个副本部署到其他机器,满足故障恢复和负载均衡等需求,redis使用复制功能来保证了高可用
建立复制
复制的redis节点分为主节点(master)和从节点(slave),主从对应是一对多的关系,配置方式有三种
1. 在配置文件中加入 slaveof {masterHost} {masterport} 随redis启动生效
2. 在redis-server启动命令后加入 --slaveof {masterHost} {masterPort} 生效
3. 直接使用命令 slaveof {masterHost} {masterPort} 也可用来切换新的主节点(切换后从节点会清空原来的所有数据)
info replication 可以查看复制节点的信息
slaveof no one 断开复制,从节点晋升为主节点
传输延迟
主从节点一般部署在不同机器上,复制时的网络延迟必须要考虑到,redis提供的参数repl-disable-tcp-nodelay 用于控制是否关闭TCP_NODELAY 默认为no 关闭
当关闭时:主节点产生的命令数据无论大小都会及时发送给从节点,这样主从之间延迟会变小,但增加了网络带宽的消耗,适用于主从之间的网络环境良好的情况,如同机房部署
当开启时:主节点会合并较小的tcp数据包,从而节省带宽,但是延迟会变大,适用于主从网络环境复制或带宽紧张的情况,如异地部署
原理
在从节点执行slaveof 后,过程如下
1.保存主节点信息
执行slaveof后从节点只保存主节点的地址信息后便直接返回,此时建立复制的流程还没有开始
2.从节点内部通过每秒运行的定时任务维护复制相关的逻辑,当定时任务发现存在新的主节点后,会尝试与该主节点建立网络socket连接 (如果从节点无法建立连接,定时任务讲无限期重试,直到成功)
3.发送ping命令,尝试第一次与主节点通信,主要目的是检测主从网络socket是否可用和主节点当前是否可接受处理命令
如果没有收到主节点的pong回复或者超时,从节点会断开复制连接,下次定时任务时重试
4.权限验证。如果主节点设置了requirepass 参数,则需要密码验证,从节点必须配置masterauth 参数保证与主节点相同的密码才能通过验证,验证失败,复制终止
5.同步数据集。主从复制连接正常通信后,对于首次建立的复制场景,主节点会把所有的数据全部发送给从节点,耗时最长
6.命令持续复制(异步)。有写命令时,持续同步到从节点
数据同步
redis在2.8后采用复制命令psync进行数据同步 (psync {run_id} {offset})
全量复制: 一般用于首次复 制,当数据量较大时,会对主从节点和网络造成很大开销
部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,主节点会补发丢失的数据给从节点,可避免全量复制的过高开销
部分复制时,psync 需要带上
1.主从节点各自的复制偏移量 : master_repl_offset ,slave_repl_offset
2.主节点的复制积压缓冲区
3.主节点运行id run_id ,如果只识别host 和port 那么当主节点更换RDB文件时,从节点还使用原来的偏移量复制,会造成数据错误,,,因此每次主节点重启时,都会进行全量复制,可使用redis-cli debug reload 每次重启run_id 不变
全量复制流程
- 发送psync同步命令,第一次没有主节点运行ID会默认为?,没有复制偏移量默认为-1 。所以发送psync ? -1
- 主节点解析出命令为全量复制,回复 +FULLRESYNC响应,带上run_id 和offset
- 从节点接收到主节点的回复后,保存run_id 和offset
- 主节点执行bgsave保存RDB文件到本地
- 主节点发送RDB文件给从节点,从节点把接收的RDB文件保存在本地,并直接作为从节点的数据文件(这一步涉及RDB文件的传输,如果RDB文件太大,会导致传输耗时,超过6G时,可能会导致传输时间超过repl-timeout的值,进而从节点会放弃接受RDB文件并清理已下载的临时RDB文件,导致全量复制识别,建议可调整repl-timeout 的值,默认60秒)
- 对于从节点从开始接受RDB快照,到接受 完毕,主节点依然会有读写操作,此段时间内,主节点会把写命令保存在复制积压缓冲区,当从节点完成接收时,主节点再发送给从节点,保证了主从一致性
- 从节点接收完主节点的全部数据后会清空自身旧数据
- 清空旧数据后开始加载RDB文件(对于较大的RDB文件,此步骤也是很耗时)
- 从节点加载完RDB后,如果当前节点开启了AOF持久化功能,他会立即做bgrewriteaof 操作,保证了全量复制后AOF立即可用
心跳
主从建立复制后,他们之间会维护一个长连接并彼此发送心跳命令
主对从:ping,从对主:replconf ack {offset}
1.主从彼此都有心跳检测机制,可通过client list 查看复制的相关信息
2.主节点每个10秒发送ping命令,判断从节点的存活性和连接状态,可通过repl-ping-slave-period 控制发送频率
3.从节点每隔1秒发送replconf ack {offset} 命令,给主节点上报自身当前复制偏移量 ,主节点根据此命令判断从节点超时时间,通过info replication 中的 lag字段(表示与从节点最后一次通信延迟的秒数)正常延迟在0-1之间
关于在实际中可以遇到的问题
1.读写分离
主从复制除了做备份以为,最主要的就是用来做读写分离,降低单点的压力
1.复制延迟
由于主从复制的异步特性,会导致一段时间内主从数据的不一致问题,这需要业务场景允许短时间数据延迟,对于零容忍延迟,可使用外部程序从主节点的复制积压缓冲区中取数据,和mysql主从复制中延迟问题的解决方案差不多
2.读到过期数据
当主节点存储大量的过期数据时,如缓冲数据,redis内部需要维护过期数据的删除策略
1.惰性删除:主节点每次处理命令时,都会检测键是否过期超时,如果超时则执行del删除命令,之后的del命令也会发送给从节点,为确保主从数据一致性,从节点不会主动删除过期数据
2.定时删除:redis主节点在内部定时任务会采样一定数据键,发现有过期数据键时,执行del键命令,在大量数据超时并且从节点没有收到del命令时,在redis3.2版本后,从节点在读取数据之前会检测键是否过期,来决定是否发送数据
2.主从配置不一致
对于有关内存的命令必须主从一致,maxmemory,hash-max-ziplist-entries 等参数
3.规避全量复制
1.第一次复制:不可避免,建议低峰时操作
2.节点运行ID不匹配:如果主节点宕机重启,会导致run_id 变化,引起全量复制,这种情况要在架构上避免,可使用故障转移功能,在主节点发生故障后,从节点能晋升为主节点
3.复制及压缓冲区不足:主节点网络中断后,此时主节点会把写命令放入复制积压缓冲区,如果时间长,复制积压缓冲区内存不够,导致从节点再次连接时尝试部分复制,从复制积压缓冲区找不到偏移量,此时会退化成全量复制,【需要根据网络中断时间, 和写数据量分析出合理的复制积压缓冲区大小,避免再次连接后找不到偏移量的问题】
4. 复制风暴问题
1.单主节点复制风暴
一个主机上挂载多个从节点情况,当主节点恢复后,导致多个从节点发起全量复制,主节点会创建RDB快照,发送给多个从节点,从而导致主节点的带宽消耗严重变大,造成主从延迟变大,严重可能会断开复制【可架构树状结构,减轻主节点的复制压力】
2.单机器复制风暴
单台机器部署多个redis【多个主从】实例,当这台机器出现故障或者网络延迟时,恢复正常后,会有大量从节点对这台机器的主节点进行全量复制,导致当前机器带宽消耗,IO消耗,【应该把主节点部署到多台机器】。【避免恢复后,密集的复制】
原文地址:https://www.cnblogs.com/bigyu/p/10554751.html