本文大纲
html
复制过程程序员
数据间的同步面试
全量复制redis
部分复制缓存
心跳安全
异步复制微信
总结网络
1、复制过程异步
Step 1:从节点执行 slaveof 命令。socket
Step 2:从节点只是保存了 slaveof 命令中主节点的信息,并无当即发起复制。
Step 3:从节点内部的定时任务发现有主节点的信息,开始使用 socket 链接主节点。
Step 4:链接创建成功后,发送 ping 命令,但愿获得 pong 命令响应,不然会进行重连。
Step 5:若是主节点设置了权限,那么就须要进行权限验证,若是验证失败,复制终止。
Step 6:权限验证经过后,进行数据同步,这是耗时最长的操做,主节点将把全部的数据所有发送给从节点。
Step 7:当主节点把当前的数据同步给从节点后,便完成了复制的创建流程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。
2、数据间的同步
上面说的复制过程,其中有一个步骤是“同步数据集”,这个就是如今讲的“数据间的同步”。
redis 同步有 2 个命令:sync 和 psync,前者是 redis 2.8 以前的同步命令,后者是 redis 2.8 为了优化 sync 新设计的命令。咱们会重点关注 2.8 的 psync 命令。
主从节点各自复制偏移量
主节点复制积压缓冲区
主节点运行 ID
参与复制的主从节点都会维护自身的复制偏移量。
主节点在处理完写入命令后,会把命令的字节长度作累加记录,统计信息在 info replication 中的 masterreploffset 指标中。
从节点每秒钟上报自身的的复制偏移量给主节点,所以主节点也会保存从节点的复制偏移量。
从节点在接收到主节点发送的命令后,也会累加自身的偏移量,统计信息在 info replication 中。
经过对比主从节点的复制偏移量,能够判断主从节点数据是否一致。
复制积压缓冲区是一个保存在主节点的一个固定长度的先进先出的队列,默认大小 1MB。
这个队列在 slave 链接是建立。这时主节点响应写命令时,不但会把命令发送给从节点,也会写入复制缓冲区。
他的做用就是用于部分复制和复制命令丢失的数据补救。经过 info replication 能够看到相关信息。
每一个 redis 启动的时候,都会生成一个 40 位的运行 ID。
运行 ID 的主要做用是用来识别 Redis 节点。若是使用 ip+port 的方式,那么若是主节点重启修改了 RDB/AOF 数据,从节点再基于偏移量进行复制将是不安全的。因此,当运行 id 变化后,从节点将进行全量复制。也就是说,redis 重启后,默认从节点会进行全量复制。
能够经过 debug reload 命令从新加载 RDB 并保持运行 ID 不变,从而有效的避免没必要要的全量复制。
缺点是:debug reload 命令会阻塞当前 Redis 节点主线程,所以对于大数据量的主节点或者没法容忍阻塞的节点,须要谨慎使用。通常经过故障转移机制能够解决这个问题。
命令格式为 psync{runId}{offset}
runId:从节点所复制主节点的运行 id
offset:当前从节点已复制的数据偏移量
流程说明:
从节点发送 psync 命令给主节点,runId 就是目标主节点的 ID,若是没有默认为 -1,offset 是从节点保存的复制偏移量,若是是第一次复制则为 -1.主节点会根据 runid 和 offset 决定返回结果:
若是回复 +FULLRESYNC {runId} {offset} ,那么从节点将触发全量复制流程。
若是回复 +CONTINUE,从节点将触发部分复制。
若是回复 +ERR,说明主节点不支持 2.8 的 psync 命令,将使用 sync 执行全量复制。
到这里,数据之间的同步就讲的差很少了,篇幅仍是比较长的。主要是针对 psync 命令相关之间的介绍。
3、全量复制
全量复制是 Redis 最先支持的复制方式,也是主从第一次创建复制时必须经历的的阶段。触发全量复制的命令是 sync 和 psync。以前说过,这两个命令的分水岭版本是 2.8,redis 2.8 以前使用 sync 只能执行全量不一样,2.8 以后同时支持全量同步和部分同步。
流程以下:
Step 1:发送 psync 命令(spync ?-1)
Step 2:主节点根据命令返回 FULLRESYNC
Step 3:从节点记录主节点 ID 和 offset
Step 4:主节点 bgsave 并保存 RDB 到本地
Step 5:主节点发送 RBD 文件到从节点
Step 6:从节点收到 RDB 文件并加载到内存中
Step 7:主节点在从节点接受数据的期间,将新数据保存到“复制客户端缓冲区”,当从节点加载 RDB 完毕,再发送过去。(若是从节点花费时间过长,将致使缓冲区溢出,最后全量同步失败)
Step 8:从节点清空数据后加载 RDB 文件,若是 RDB 文件很大,这一步操做仍然耗时,若是此时客户端访问,将致使数据不一致,可使用配置slave-server-stale-data 关闭.
Step 9:从节点成功加载完 RBD 后,若是开启了 AOF,会马上作 bgrewriteaof。
以上加粗的部分是整个全量同步耗时的地方。
注意:
如过 RDB 文件大于 6GB,而且是千兆网卡,Redis 的默认超时机制(60 秒),会致使全量复制失败。能够经过调大 repl-timeout 参数来解决此问题。
Redis 虽然支持无盘复制,即直接经过网络发送给从节点,但功能不是很完善,生产环境慎用。
4、部分复制
当从节点正在复制主节点时,若是出现网络闪断和其余异常,从节点会让主节点补发丢失的命令数据,主节点只须要将复制缓冲区的数据发送到从节点就可以保证数据的一致性,相比较全量复制,成本小不少。
当从节点出现网络中断,超过了 repl-timeout 时间,主节点就会中断复制链接。
主节点会将请求的数据写入到“复制积压缓冲区”,默认 1MB。
当从节点恢复,从新链接上主节点,从节点会将 offset 和主节点 id 发送到主节点。
主节点校验后,若是偏移量的数后的数据在缓冲区中,就发送 cuntinue 响应 —— 表示能够进行部分复制。
主节点将缓冲区的数据发送到从节点,保证主从复制进行正常状态。
5、心跳
主从节点在创建复制后,他们之间维护着长链接并彼此发送心跳命令。
心跳的关键机制以下:
中从都有心跳检测机制,各自模拟成对方的客户端进行通讯,经过 client list 命令查看复制相关客户端信息,主节点的链接状态为 flags = M,从节点的链接状态是 flags = S。
主节点默认每隔 10 秒对从节点发送 ping 命令,可修改配置 repl-ping-slave-period 控制发送频率。
从节点在主线程每隔一秒发送 replconf ack{offset} 命令,给主节点上报自身当前的复制偏移量。
主节点收到 replconf 信息后,判断从节点超时时间,若是超过 repl-timeout 60 秒,则判断节点下线。
注意:
为了下降主从延迟,通常把 redis 主从节点部署在相同的机房/同城机房,避免网络延迟带来的网络分区形成的心跳中断等状况。
6、异步复制
主节点不但负责数据读写,还负责把写命令同步给从节点,写命令的发送过程是异步完成,也就是说主节点处理完写命令后当即返回客户度,并不等待从节点复制完成。
异步复制的步骤很简单,以下:
Step 1:主节点接受处理命令。
Step 2:主节点处理完后返回响应结果 。
Step 3:对于修改命令,异步发送给从节点,从节点在主线程中执行复制的命令。
7、总结
本文主要分析了 Redis 的复制原理,包括复制过程,数据之间的同步,全量复制的流程,部分复制的流程,心跳设计,异步复制流程。
其中,能够看出,RDB 数据之间的同步很是耗时。
因此,Redis 在 2.8 版本退出了相似增量复制的 psync 命令,当 Redis 主从直接发生了网络中断,不会进行全量复制,而是将数据放到缓冲区(默认 1MB)里,再经过主从之间各自维护复制 offset 来判断缓存区的数据是否溢出。若是没有溢出,只须要发送缓冲区数据便可,成本很小;反之,则要进行全量复制。所以控制缓冲区大小很是的重要。
做者:五色花的博客
来源:https://www.cnblogs.com/luao/p/10682830.html
·END·
程序员的成长之路
路虽远,行则必至
本文原发于 同名微信公众号「程序员的成长之路」,回复「1024」你懂得,给个赞呗。
回复 [ 520 ] 领取程序员最佳学习方式
回复 [ 256 ] 查看 Java 程序员成长规划
往期精彩回顾