一、主从复制了解
定义:主从复制是指将一个redis服务器(又叫主节点master)的数据复制到其他的redis服务器(又叫从节点slave)上。其主要是为了解决数据的多机备份(数据副本)以及性能的扩展(扩展读性能),为高可用、负债均衡等做基础。想想如果是单机应用,当服务器宕机则无法提供服务,且一台机器容量十分有限。有了主从复制则当一个节点损坏(指不可恢复的硬件损坏)时,数据因为有备份,可以方便恢复。
主从复制过程中有如下规则:
作用:数据冗余备份、故障恢复(主节点故障可由从节点提供服务)、负债均衡(配合读写分离,主节点写从节点读,分担服务器负载来提高并发处理量)、实现高可用及集群的基础。
二、实现主从复制的方式
开启主从复制完全由从节点发起,主节点不做任何操作,有两种方式:slaveof 命令、配置
另外,当从节点不想做从节点,即要与主节点脱离关系,可以执行命令 slaveof no one 。此时从节点将断开复制,但是已存在的数据不会删除,只是不会再根据以前的主节点修改数据。当redis成为从节点时,会自动把其原来的数据清空。
三、主从信息查看
我们可以在节点执行 info replication 命令来查看节点的主从信息。
可以在节点执行 info server 命令来查看节点的启动信息。
上面查看到的信息中,run_id以及偏移量是两个比较重要的概念,其对下面全量复制和部分复制等有重要作用。
四、全量复制与部分复制
全量复制流程:
全量复制需要耗费的时间:
全量复制发生场景及避免(因为全量复制耗费时长和资源):
部分复制流程:
场景:在redis主从结构中,主从一般部署在不同的机器,即主从之间必须通过网络进行数据传输。当网络异常时,master节点将有部分数据没有同步到slave,一段时间后从节点重新连上主节点,这是就会出现不少数据未同步。当数据量差距不是特别大时,将进行部分复制来减少消耗。流程如下:
五、复制缓冲区与复制积压缓冲区
(1)复制缓冲区
全量复制时使用到的一个缓冲区,每个从节点都会有一个该缓冲区,其主要存放全量复制过程中主节点开始执行bgsave到从节点载入rdb文件这个时间段中主节点的写命令。但是当主节点数据量太大或者网络延迟太大导致上面的时间段太长,即要写入的数据超过缓冲区的大小,导致主节点断开与从节点的连接。可能还会引起全量复制->复制缓冲区溢出导致连接中断->重连->全量复制->复制缓冲区溢出导致连接中断的循环。
复制缓冲区的大小由client-output-buffer-limit slave {hard limit} {soft limit} {soft seconds}配置,默认值为client-output-buffer-limit slave 256MB 64MB 60,其含义是:如果buffer大于256MB,或者连续60s大于64MB,则主节点会断开与该从节点的连接。
(2)复制积压缓冲区
主节点维护的一个缓冲区,在主节点开始有从节点时创建(不管几个从节点都只有一个),其是长度固定且为先进先出的队列,默认大小为1MB。主要用来备份主节点最近发送给从节点的写命令,同时还会存储该写命令对应的偏移量(offset),当主从节点offset的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。由于该缓冲区长度有限,因此备份的命令也有限,又因为其为先进先出的队列,所以先进入缓冲区的命令会随着命令的增加被挤出缓冲区。因为部分复制效率高,所以为了能够提高部分复制的几率,可以适当增加积压缓冲区的大小,即设置配置 repl-backlog-size 的大小。
(3)总结
六、其他
(1)主从redis故障影响:
(2)读写分离作用
主从中的读写分离是为了将读操作分摊到多个服务,减轻master的压力,但是读写分离有可能有导致复制数据延迟、读到过期数据
(3)复制风暴
当只有一个主节点且主节点重启,则runid会发生变化,如果有很多个从节点,则会一起对主节点发起全量复制,这将对主节点的性能有一个很大的损耗。所以做主从时要合理规划网络结构。
(4)master宕机导致redis无法提供写服务问题可通过sentinel进行处理
主从模式中,master节点挂了以后,redis就不能对外提供写服务了,其他slave不能自动升级为master,所以一般主从模式还会添加sentinel。当sentinel发现master节点挂了以后,sentinel就会从slave中重新选举一个master。sentinel会在slave中选择一个做为master,并修改它们的配置文件,其他slave的配置文件也会被修改,比如slaveof属性会指向新的master。当旧的master节点重启后将不再是master,而是做为slave接收新的master节点的同步数据。当使用sentinel模式时,客户端连接的是sentinel的ip和端口,由sentinel来提供具体的功能实现,这样当master节点挂掉以后,sentinel就会感知并将新的master节点提供给使用者。
(5)主从模式中会读取到过期数据的原因
因为redis有两种删除策略:
结合上面两种删除策略,因为从节点不会主动对数据进行修改删除操作(由主节点控制),而主节点又没有及时将过期数据删除,所以客户端很容易就获取到从节点中过期的数据。好在redis3.2处理了这个问题,在从节点读数据时会判断是否过期,过期将不返回。
(6)主从数据不一致
主节点在给从节点发送写命令时是异步的,即不会等待从节点的回复,所以由于网络、性能、命令执行频率等原因导致主从节点很难保持实时的一致性,延迟在所难免。这里我们讲讲主节点中repl-disable-tcp-nodelay配置对延迟的影响。
repl-disable-tcp-nodelay no:该配置默认为no,主要用来控制主节点是否禁止与从节点的TCP_NODELAY。设置为no则不禁止TCP_NODELAY,此时TCP会立马将主节点的数据发送给从节点,带宽增加但延迟变小。设置为yes时,TCP会对包进行合并从而减少带宽,但是发送的频率会降低导致从节点数据延迟增加,一致性变差;具体发送频率与操作系统有关,默认配置为40ms。所以一般还是使用默认的no。
七、主从复制涉及的配置
slaveof
repl-disable-tcp-nodelay no:同命令传播阶段的延迟有关
masterauth
slave-read-only yes:从节点设置为只读;默认为yes。
repl-backlog-size 1mb:复制积压缓冲区的大小设置,默认1MB
client-output-buffer-limit slave 256MB 64MB 60:全量复制过程中主节点复制缓冲区大小设置
repl-timeout 60:与各个阶段主从节点连接超时判断有关
repl-ping-slave-period 10:与命令传播阶段主从节点的超时判断有关
repl-backlog-ttl 3600:当主节点没有从节点时,复制积压缓冲区保留的时间,这样当断开的从节点重新连进来时,可以进行全量复制;默认3600s。如果设置为0,则永远不会释放复制积压缓冲区。
repl-diskless-sync no:作用于全量复制阶段,控制主节点是否使用diskless复制(无盘复制)。所谓diskless复制,是指在全量复制时,主节点不再先把数据写入RDB文件,而是直接写入slave的socket中,整个过程中不涉及硬盘;diskless复制在磁盘IO很慢而网速很快时更有优势。需要注意的是,截至Redis3.0,diskless复制处于实验阶段,默认是关闭的。
repl-diskless-sync-delay 5:该配置作用于全量复制阶段,当主节点使用diskless复制时,该配置决定主节点向从节点发送之前停顿的时间,单位是秒;只有当diskless复制打开时有效,默认5s。之所以设置停顿时间,是基于以下两个考虑:(1)向slave的socket的传输一旦开始,新连接的slave只能等待当前数据传输结束,才能开始新的数据传输 (2)多个从节点有较大的概率在短时间内建立主从
八、命令传播阶段的心跳机制(参考 https://www.cnblogs.com/kismetv/p/9236731.html)
主从节点在命令传播时维持着心跳机制:PING和REPLCONF ACK。心跳机制对于主从复制的超时判断、数据安全等有作用。
1.主->从:PING
每隔指定的时间,主节点会向从节点发送PING命令,这个PING命令的作用,主要是为了让从节点进行超时判断。
PING发送的频率由repl-ping-slave-period参数控制,单位是秒,默认值是10s。
关于该PING命令究竟是由主节点发给从节点,还是相反,有一些争议;因为在Redis的官方文档中,对该参数的注释中说明是从节点向主节点发送PING命令,如下图所示:
但是根据该参数的名称(含有ping-slave),以及代码实现,我认为该PING命令是主节点发给从节点的。相关代码如下:
2. 从->主:REPLCONF ACK
在命令传播阶段,从节点会向主节点发送REPLCONF ACK命令,频率是每秒1次;命令格式为:REPLCONF ACK {offset},其中offset指从节点保存的复制偏移量。REPLCONF ACK命令的作用包括:
(1)实时监测主从节点网络状态:该命令会被主节点用于复制超时的判断。此外,在主节点中使用info Replication,可以看到其从节点的状态中的lag值,代表的是主节点上次收到该REPLCONF ACK命令的时间间隔,在正常情况下,该值应该是0或1,如下图所示:
(2)检测命令丢失:从节点发送了自身的offset,主节点会与自己的offset对比,如果从节点数据缺失(如网络丢包),主节点会推送缺失的数据(这里也会利用复制积压缓冲区)。注意,offset和复制积压缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。
(3)辅助保证从节点的数量和延迟:Redis主节点中使用min-slaves-to-write和min-slaves-max-lag参数,来保证主节点在不安全的情况下不会执行写命令;所谓不安全,是指从节点数量太少,或延迟过高。例如min-slaves-to-write和min-slaves-max-lag分别是3和10,含义是如果从节点数量小于3个,或所有从节点的延迟值都大于10s,则主节点拒绝执行写命令。而这里从节点延迟值的获取,就是通过主节点接收到REPLCONF ACK命令的时间来判断的,即前面所说的info Replication中的lag值。