Redis主从复制

redis主从复制是为了打造高性能、高可用的redis必不可少的一个功能,当主节点挂掉时可以通过把从节点切换成主节点来继续为客户端提供服务达到高可用;也可以通过读写分离达到高性能redis。

一、建立复制与断开复制

1、可以用过slaveof配置项在从节点redis上配置其所属的主节点

2、客户端在从节点上通过slaveof命令动态设置当前redis所属的主节点

3、在从节点使用slaveof no one命令可以断开与主节点的复制关系

4、slaveof命令可以实现动态切换主节点,slaveof {newMasterIp} {new MasterPort},切主操作与新主节点建立复制关系后会清除当前redis节点中的所有数据,然后重新对新主节点的数据进行全量复制(下面会介绍全量复制与部分复制)

5、当master设置了密码时,需要在从节点配置masterauth参数和主节点的密码相同才能通过验证。

关于断开复制:并不会清除之前从主节点复制来的数据,只是以后不再从主节点同步数据了

从节点默认是只读默认的,确保主从节点数据的一致性,因为从节点可以感知并同步主节点的数据变化,而主节点不能感知到从节点的数据变化。


二、关于带宽消耗

redis默认主节点产生的命令无论大小都及时的发给从节点,这样主从节点的数据延迟就小,但是这样同时也会造成带宽消耗增加,对于网络情况较差的情况下可能不太适用,对于此种情况可以配置repl-disable-tcp-nodelay参数,使redis合并一些较小的数据包,有操作系统决定发送时间间隔,但是这样会加大数据的延迟。

三、主从结构

Redis支持三种主从结构,分别是:

1、一主对一从,常用于写请求量很大,并且需要持久化时,只在从节点开启AOF持久化,这样既保证了主节点的性能又保证了数据的安全性;但是当重启主节点时需要注意先断开从节点的复制关系,否则当主节点重启后由于没有持久化数据,所以主节点的数据为空,而此时从节点再同步主节点的数据就会丢失之前持久化的数据。

2、一主对多从,多用于读请求很高的情况,通过读写分离把读请求交给从节点来分担主节点压力;同时对于开发中的一些危险或耗时的操作也可以在从节点上执行;弊端:当从节点过多时,会导致主节点的一份数据要发给很多从节点,所以会导致主节点负载与带宽消耗较大。

3、树状主从结构,这种结构很好的解决了上面提到的从节点过多时主节点带宽消耗过大的问题,主节点把数据写给较少的从节点,然后从节点再同步给其自己的从节点。如下图:



四、复制流程

1、在从节点上配置主节点信息

2、redis通过每秒运行的定时任务发现新配置的主节点后,会尝试与主节点建立网络连接

3、通过步骤2建立的网络连接发送ping请求进行首次通信,主要目的是①确保网络畅通②检测主节点是否可以接受并处理命令

4、权限验证,如果主节点配置了requirepass,则从节点需要根据masterauth配置项进行密码验证,如果验证失败则复制终止,从节点重新发起复制流程

5、同步数据,当从节点第一次与主节点建立复制关系时,会对主节点进行全量复制,主节点会fork出子线程生成RDB文件,并通过步骤2建立的连接发送给从节点,从节点对数据进行同步

6、持续数据同步,主节点的写命令会持续发送给从节点进行同步。

五、数据同步

数据同步是通过psync命令完成的,分为全量复制和部分复制:

全量复制:主要用于首次复制,需要主节点把数据生成RBD文件一次性通过网络发给从节点,当文件很大时会对主从节点的网络造成很大开销。

部分复制:主要用于数据持续同步时,由于网络闪断等原因造成数据丢失,当从节点再次连上主节点时会根据从节点自身的复制偏移量从主节点的"复制积压缓冲区"中同步部分数据,如果“复制积压缓冲区“中存在丢失的数据,则主节点只需要补发丢失部分的数据即可,避免了全量复制过高的开销。

psync命令涉及到三个概念:

1、自身复制偏移量

2、复制积压缓冲区

3、主节点运行id

自身复制偏移量:用来标识当前从节点数据复制的位置偏移量,从接收到主节点的数据后会累加自身的复制偏移量;从节点每秒会上报自己的复制偏移量给主节点

复制积压缓冲区:一个固定大小的队列,默认为1MB,主节点的写操作命令一份直接发给slave一份放入到此处,当大小超过后会按先进先出原则淘汰数据,用于部分复制数据丢失时的补救;此缓冲区对于所有从节点是共享的,完全可以适当调大队列大小,从而避免全量复制。

主节点运行id:redis在启动后都会动态分配一个40位的16进制字符串作为运行id,用来唯一标识redis节点;每次重启后运行id都会改变,当运行id改变后从节点会进行全量复制(因为如果主节点重启后加载了RDB/AOF文件,此时再根据复制偏移量进行部分复制将变得不可靠),可以使用debug reload命令重新加载RDB文件并保持运行id不变,从而避免全量复制。


六、全量复制与部分复制

全量复制:在redis2.8版本之前通过sync命令触发,在2.8版本之后通过psync命令触发;接下来主要讲解psync命令,

全量复制流程如下:

1、slave向主节点发送psync ? -1命令,代表请求进行全量复制

2、master收到命令后响应给slave+FULLRESYNC{runid} {offset}

3、slave根据步骤二返回的结果解析出runid和偏移量offset后保存

4、master执行bgsave操作生成RDB文件保存到本地,此期间主线程同时响应客服端读写请求,并把写请求命令放到复制客户端缓冲区(详见注1)

5、master通过网络将步骤4得到的RDB文件传输给slave

6、slave接收完RDB文件后,master会再把复制客户端缓冲区的内容发给slave

7、当slave接收完所有数据后,slave清空自身的旧数据

8、slave先加载RDB文件后再加载master发送的复制客户端缓冲区中的内容

9、slave加载完数据后,如果开启了AOF,则立即执行bgrewriteof操作

注1:redis为客户端分有输入缓冲区和输出缓冲区;输入缓冲区用来存放客户端的命令,大小无法设置,最大为1G,当溢出时会中断客户端的连接;输出缓冲区用来缓冲存放redis服务执行命令的结果并发送给客户端,可以通过client-output-buffer-limit slave配置项设置缓冲区大小,详细配置用法可以百度;同时输入缓冲区和输入缓冲区都不受maxmemory 最大内存的限制,此点需注意!


部分复制:

全量复制必然会造成大量的带宽、硬盘以及cpu的消耗,除了首次复制采用全量复制在所难免外,其它时候应该避免全量复制,所以redis提供了部分复制功能。

通过命令psync {runid} {offset}实现。

当slave正从master复制数据时,如果出现网络闪断等导致复制命令丢失的情况,从节点会通过psync命令请求主节点重发丢失的数据,如果主节点复制积压缓冲区内存在这部分数据则直接发送给从节点,否则从节点将进行一次全量复制。

流程如下图:



主从节点心跳判断机制:

主从节点之间通过长连接建立连接,并彼此发送心跳命令

1、主节点会模拟从节点的客户端,每隔10s向从节点发送ping命令,用来检测从节点是否存活和连接状态,可以通过参数repl-ping-slave-period控制发送频率。

2、从节点会每隔1s会通过发送replconf ack {offset}命令向主节点上报当前自身复制偏移量,用来①向主节点上报自身复制偏移量,检测复制数据是否丢失,如果丢失则从主节点复制积压缓冲区中拉取丢失的数据。②实时检测主从节点网络状态。③实现min-slaves-to-write、min-slaves-max-lag功能。

在主节点通过info repalication命令可以看到lag信息,表示当前从节点与主节点最后一次通信延迟的秒数,0-1之间是正常的,如果lag时间大于repl-timeout参数的值时,则会判断从节点下线并断开与从节点的连接,当从节点回复后心跳检测会继续。

主节点异步发送写命令到从节点

主节点在执行完命令后会立即响应结果给客户端,对于写命令通过子线程异步向从节点发送;所以就会造成主从节点存在一定的数据延迟。


阅读更多
文章标签: redis主从复制
个人分类: 后端
上一篇redis持久化优化
下一篇kafka高吞吐量原理
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭