彻底搞懂Redis主从复制原理及实战

迎接关注民众号:「码农富哥」,致力于分享后端手艺 (高并发架构,漫衍式集群系统,新闻行列中间件,网络,微服务,Linux, TCP/IP, HTTP, MySQL, Redis), Python 等 原创干货 和 面试指南!

主从复制概述

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);

数据的复制是单向的,只能由主节点到从节点。

默认情形下,每台Redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

现在许多中小企业都没有使用到 Redis 的集群,然则至少都做了主从。有了主从,当 master 挂掉的时刻,运维让从库过来接受,服务就可以继续,否则 master 需要经由数据恢复和重启的历程,这就可能会拖很长的时间,影响线上营业的连续服务。

Redis主从复制服务器架构图如下:

彻底搞懂Redis主从复制原理及实战

主从复制的作用

主从复制的作用主要包罗:

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 故障恢复:当主节点泛起问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  • 负载平衡:在主从复制的基础上,配合读写星散,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用毗邻主节点,读Redis数据时应用毗邻从节点),分管服务器负载;尤其是在写少读多的场景下,通过多个从节点分管读负载,可以大大提高Redis服务器的并发量。
  • 高可用基石:主从复制照样哨兵和集群能够实行的基础,因此说主从复制是Redis高可用的基础。

CAP 原理

在领会 Redis 的主从复制之前,让我们先来明白一下现代漫衍式系统的理论基石——CAP 原理。

CAP 原理就好比漫衍式领域的牛顿定律,它是漫衍式存储的理论基石。自打 CAP 的论文揭晓之后,漫衍式存储中间件犹如雨后春笋般一个一个涌现出来。明白这个原理实在很简朴,本节我们首先对这个原理举行一些简朴的解说。

  • C – Consistent ,一致性
  • A – Availability ,可用性
  • P – Partition tolerance ,分区容忍性
    漫衍式系统的节点往往都是漫衍在差别的机械上举行网络隔脱离的,这意味着一定会有网络断开的风险,这个网络断开的场景的专业词汇叫着「网络分区」。

在网络分区发生时,两个漫衍式节点之间无法举行通讯,我们对一个节点举行的修改操作将无法同步到另外一个节点,以是数据的「一致性」将无法知足,由于两个漫衍式节点的数据不再保持一致。除非我们牺牲「可用性」,也就是暂停漫衍式节点服务,在网络分区发生时,不再提供修改数据的功效,直到网络状态完全恢复正常再继续对外提供服务。

一句话归纳综合 CAP 原理就是——网络分区发生时,一致性和可用性两难全

Redis 主从同步最终一致性

Redis 的主从数据是异步同步的,以是漫衍式的 Redis 系统并不知足「一致性」要求。当客户端在 Redis 的主节点修改了数据后,立刻返回,纵然在主从网络断开的情形下,主节点依旧可以正常对外提供修改服务,以是 Redis 知足「可用性」。

Redis 保证「最终一致性」,从节点会起劲追赶主节点,最终从节点的状态会和主节点的状态将保持一致。若是网络断开了,主从节点的数据将会泛起大量不一致,一旦网络恢复,从节点会接纳多种计谋起劲追赶上落伍的数据,继续全力保持和主节点一致。

主从复制的实现原理

总的来说主从复制功效的详细步骤可以分为7个步骤:

  1. 设置主节点的地址和端口
  2. 确立套接字毗邻
  3. 发送PING下令
  4. 权限验证
  5. 同步
  6. 下令流传

接下来划分叙述每个步骤,整个流程图如下:
彻底搞懂Redis主从复制原理及实战
为了测试,我在本地机开启两个Redis节点,划分监听:
127.0.0.1 6379(主)
127.0.0.1 6380(从)
彻底搞懂Redis主从复制原理及实战

1. 设置主服务器的地址和端口

第一步首先是在从服务器设置需要同步的主服务器信息,包罗机械IP, 端口。
主从复制的开启,完全是在从节点提议的;不需要我们在主节点做任何事情。

从节点开启主从复制,有3种方式:

(1)设置文件

在从服务器的设置文件中加入:slaveof masterip masterport

(2)启动下令

redis-server启动下令后加入 –slaveof masterip masterport

(3)客户端下令

Redis服务器启动后,直接通过客户端执行下令:slaveof masterip masterport,则该Redis实例成为从节点。

上述3种方式是等效的,下面以客户端下令的方式为例,看一下当执行了slaveof后,Redis主节点和从节点的转变。

完成上面的设置后, 从服务器会将主服务器的ip地址和端口号保留到服务器状态的属性内里。可以Redis使用info Replication 下令划分查看从服务器和主服务器的主从信息

2. 确立套接字毗邻

在slaveof下令执行之后,从服务器会凭据设置的ip和端口,向主服务器简历socket毗邻。
在6380从服务器内里执行完slave of 127.0.0.1 6379 后意味着,从服务器向主服务器提议socket毗邻
在执行info Replication 下令,可以看到6380服务器的角色是slave了
彻底搞懂Redis主从复制原理及实战
而6379 服务器已经成为主服务器角色:
彻底搞懂Redis主从复制原理及实战

3. 发送PING下令

从节点成为主节点的客户端之后,发送ping下令举行首次请求,目的是:检查socket毗邻是否可用,以及主节点当前是否能够处置请求。

从节点发送ping下令后,可能泛起3种情形:

(1)返回pong:说明socket毗邻正常,且主节点当前可以处置请求,复制历程继续。

(2)超时:一准时间后从节点仍未收到主节点的回复,说明socket毗邻不可用,则从节点断开socket毗邻,并重连。

(3)返回pong以外的效果:若是主节点返回其他效果,如正在处置超时运行的剧本,说明主节点当前无法处置下令,则从节点断开socket毗邻,并重连。

主从发送PING下令流程图如下:
彻底搞懂Redis主从复制原理及实战

4. 身份验证

若是从节点中设置了masterauth选项,则从节点需要向主节点举行身份验证;没有设置该选项,则不需要验证。从节点举行身份验证是通过向主节点发送auth下令举行的,auth下令的参数即为设置文件中的masterauth的值。

若是主节点设置密码的状态,与从节点masterauth的状态一致(一致是指都存在,且密码相同,或者都不存在),则身份验证通过,复制历程继续;若是不一致,则从节点断开socket毗邻,并重连。

主从身份验证流程图如下:
彻底搞懂Redis主从复制原理及实战

5. 同步

同步就是将从节点的数据库状态更新成主节点当前的数据库状态。详细执行的方式是:从节点向主节点发送psync下令(Redis2.8以前是sync下令),最先同步。
数据同步阶段是主从复制最焦点的阶段,凭据主从节点当前状态的差别,可以分为全量复制部门复制
下面会有详细先容全量复制和部门复制内容,这里暂不详述

6. 下令流传

经由上面同步操作,此时主从的数据库状态实在已经一致了,但这种一致的状态的并不是一成不变的。
在完成同步之后,也许主服务器马上就接受到了新的写下令,执行完该下令后,主从的数据库状态又不一致。

数据同步阶段完成后,主从节点进入下令流传阶段;在这个阶段主节点将自己执行的写下令发送给从节点,从节点吸收下令并执行,从而保证主从节点数据的一致性。

另外下令转播我们需要关注两个点: 延迟与不一致心跳机制 我们下面先容一下

延迟与不一致
需要注重的是,下令流传是异步的历程,即主节点发送写下令后并不会守候从节点的回复;因此实际上主从节点之间很难保持实时的一致性,延迟在所难免。数据不一致的水平,与主从节点之间的网络状态、主节点写下令的执行频率、以及主节点中的repl-disable-tcp-nodelay设置等有关。

repl-disable-tcp-nodelay 设置如下:

  • 如果设置成yes,则redis会合并小的TCP包从而节约带宽,但会增添同步延迟(40ms),造成master与slave数据不一致
  • 如果设置成no,则redis master会立刻发送同步数据,没有延迟

归纳综合来说就是:前者关注性能,后者关注一致性

详细发送频率与Linux内核的设置有关,默认设置为40ms。当设置为no时,TCP会立马将主节点的数据发送给从节点,带宽增添但延迟变小。

一般来说,只有当应用对Redis数据不一致的容忍度较高,且主从节点之间网络状态欠好时,才会设置为yes;多数情形使用默认值no

Redis是若何保证主从服务器一致处于毗邻状态以及下令是否丢失?
答:下令流传阶段,从服务器会行使心跳检测机制准时的向主服务发送新闻。
心跳机制我们下面再详细说。

全量复制和部门复制

在Redis2.8以前,从节点向主节点发送sync下令请求同步数据,此时的同步方式是全量复制;在Redis2.8及以后,从节点可以发送psync下令请求同步数据,此时凭据主从节点当前状态的差别,同步方式可能是全量复制或部门复制。后文先容以Redis2.8及以后版本为例。

  1. 全量复制:用于首次复制或其他无法举行部门复制的情形,将主节点中的所有数据都发送给从节点,是一个异常重型的操作。
  2. 部门复制:用于网络中止等情形后的复制,只将中止时代主节点执行的写下令发送给从节点,与全量复制相比加倍高效。需要注重的是,若是网络中止时间过长,导致主节点没有能够完整地保留中止时代执行的写下令,则无法举行部门复制,仍使用全量复制。

全量复制

Redis通过psync下令举行全量复制的历程如下:

(1)从节点判断无法举行部门复制,向主节点发送全量复制的请求;或从节点发送部门复制的请求,但主节点判断无法举行部门复制;详细判断历程需要在讲述了部门复制原理后再先容。

(2)主节点收到全量复制的下令后,执行bgsave,在后台天生RDB文件,并使用一个缓冲区(称为复制缓冲区)纪录从现在最先执行的所有写下令

使用 nuget server 的 API 来实现搜索安装 nuget 包

(3)主节点的bgsave执行完成后,将RDB文件发送给从节点;从节点首先消灭自己的旧数据,然后载入吸收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态

(4)主节点将前述复制缓冲区中的所有写下令发送给从节点,从节点执行这些写下令,将数据库状态更新至主节点的最新状态

(5)若是从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态
彻底搞懂Redis主从复制原理及实战
通过全量复制的历程可以看出,全量复制是异常重型的操作:

(1)主节点通过bgsave下令fork子历程举行RDB持久化,该历程是异常消耗CPU、内存(页表复制)、硬盘IO的;关于bgsave的性能问题,可以参考我另外一篇文章: 深入剖析Redis高可用系列:持久化 AOF和RDB

(2)主节点通过网络将RDB文件发送给从节点,对主从节点的带宽都市带来很大的消耗

(3)从节点清空老数据、载入新RDB文件的历程是壅闭的,无法响应客户端的下令;若是从节点执行bgrewriteaof,也会带来分外的消耗

部门复制

由于全量复制在主节点数据量较大时效率太低,因此Redis2.8最先提供部门复制,用于处置网络中止时的数据同步。

部门复制的实现,依赖于三个主要的观点:

  1. 复制偏移量
  2. 复制积压缓冲区
  3. 服务器运行ID(runid)
    下面我们划分解说一下这三个观点:

1. 复制偏移量:

执行复制的双方,主从节点,划分会维护一个复制偏移量offset:
主节点每次向从节点同步了N字节数据后,将修改自己的复制偏移量offset+N
从节点每次从主节点同步了N字节数据后,将修改自己的复制偏移量offset+N

offset用于判断主从节点的数据库状态是否一致:
若是二者offset相同,则一致;
若是offset差别,则不一致,此时可以凭据两个offset找出从节点缺少的那部门数据。

例如,若是主节点的offset是1000,而从节点的offset是500,那么部门复制就需要将offset为501-1000的数据传递给从节点。而offset为501-1000的数据存储的位置,就是下面要先容的复制积压缓冲区。

2. 复制积压缓冲区:

主节点内部维护了一个牢固长度的、先进先出(FIFO)行列 作为复制积压缓冲区,其默认巨细为1MB
在主节点举行下令流传时,不仅会将写下令同步到从节点,还会将写下令写入复制积压缓冲区。

由于复制积压缓冲区定长且是先进先出,以是它保留的是主节点最近执行的写下令;时间较早的写下令会被挤出缓冲区。因此,当主从节点offset的差距过大跨越缓冲区长度时,将无法执行部门复制,只能执行全量复制。

为了提高网络中止时部门复制执行的概率,可以凭据需要增大复制积压缓冲区的巨细(通过设置repl-backlog-size);例如若是网络中止的平均时间是60s,而主节点平均每秒发生的写下令(特定协议花样)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情形都可以使用部门复制。

从节点将offset发送给主节点后,主节点凭据offset和缓冲区巨细决议能否执行部门复制:

  • 若是offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部门复制
  • 若是offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制

复制积压缓冲区示意图:
彻底搞懂Redis主从复制原理及实战

3. 服务器运行ID(runid):

每个Redis节点,都有其运行ID,运行ID由节点在启动时自动天生,主节点会将自己的运行ID发送给从节点,从节点会将主节点的运行ID存起来。
从节点Redis断开重连的时刻,就是凭据运行ID来判断同步的进度:

  • 若是从节点保留的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续实验使用部门复制(到底能不能部门复制还要看offset和复制积压缓冲区的情形);
  • 若是从节点保留的runid与主节点现在的runid差别,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能举行全量复制。

psync 下令的执行

在领会了复制偏移量、复制积压缓冲区、节点运行id之后,本节将先容psync下令的参数和返回值,从而说明psync下令执行历程中,主从节点是若何确定使用全量复制照样部门复制的。
psync下令流程图如下:
彻底搞懂Redis主从复制原理及实战
psync下令的大要流程如下:

  • 若是从节点之前没有复制过任何主节点,或者之前执行过slaveof no one下令,从节点就会向主节点发送psync下令,请求主节点举行数据的全量同步
  • 若是前面从节点已经同步过部门数据,此时从节点就会发送psync {runid} {offset}下令给主节点,其中runid是上一次主节点的运行ID,offset是当前从节点的复制偏移量

主节点收到psync下令后,会泛起以下三种可能:

  • 主节点返回 fullresync {runid} {offset}回复,示意主节点要求与从节点举行数据的完整全量复制,其中runid示意主节点的运行ID,offset示意当前主节点的复制偏移量
  • 若是主服务器返回 +continue,示意主节点与从节点会举行部门数据的同步操作,将从服务器缺失的数据复制过来即可
  • 若是主服务器返回 -err,示意主服务器的Redis版本低于2.8,无法识别psync下令,此时从服务器会向主服务器发送sync下令,举行完整的数据全量复制

心跳检测机制

心跳检测机制的作用有三个:

  1. 检查主从服务器的网络毗邻状态
  2. 辅助实现min-slaves选项
  3. 检测下令丢失

检查主从服务器的网络毗邻状态

主节点信息中可以看到所属的从节点的毗邻信息:

  • state 示意从节点状态
  • offset 示意复制偏移量
  • lag 示意延迟值(几秒之前有过心跳检测机制)
  • 彻底搞懂Redis主从复制原理及实战

辅助实现min-slaves选项

Redis.conf设置文件中有下方两个参数

# 未到达下面两个条件时,写操作就不会被执行
# 最少包罗的从服务器
# min-slaves-to-write 3
# 延迟值
# min-slaves-max-lag 10

若是将两个参数的注释作废,那么若是从服务器的数目少于3个,或者三个从服务器的延迟(lag)大于即是10秒时,主服务器都市拒绝执行写下令。

检测下令丢失

在从服务器的毗邻信息中可以看到复制偏移量,若是此时主服务器的复制偏移量与从服务器的复制偏移量不一致时,主服务器会补发缺失的数据。

实践中的问题

1.读写星散及其中的问题

在主从复制基础上实现的读写星散,可以实现Redis的读负载平衡:由主节点提供写服务,由一个或多个从节点提供读服务(多个从节点既可以提高数据冗余水平,也可以最大化读负载能力);在读负载较大的应用场景下,可以大大提高Redis服务器的并发量。下面先容在使用Redis读写星散时,需要注重的问题。

1. 延迟与不一致问题
前面已经讲到,由于主从复制的下令流传是异步的,延迟与数据的不一致不可制止。若是应用对数据不一致的接受水平水平较低,可能的优化措施包罗:优化主从节点之间的网络环境(如在同机房部署);监控主从节点延迟(通过offset)判断,若是从节点延迟过大,通知应用不再通过该从节点读取数据;使用集群同时扩展写负载和读负载等。

在下令流传阶段以外的其他情形下,从节点的数据不一致可能加倍严重,例如毗邻在数据同步阶段,或从节点失去与主节点的毗邻时等。从节点的slave-serve-stale-data参数便与此有关:它控制这种情形下从节点的显示;若是为yes(默认值),则从节点仍能够响应客户端的下令,若是为no,则从节点只能响应info、slaveof等少数下令。该参数的设置与应用对数据一致性的要求有关;若是对数据一致性要求很高,则应设置为no。

2. 数据过时问题
在单机版Redis中,存在两种删除计谋:

惰性删除:服务器不会自动删除数据,只有当客户端查询某个数据时,服务器判断该数据是否过时,若是过时则删除。
定期删除:服务器执行准时义务删除过时数据,然则思量到内存和CPU的折中(删除会释放内存,然则频仍的删除操尴尬刁难CPU不友好),该删除的频率和执行时间都受到了限制。
在主从复制场景下,为了主从节点的数据一致性,从节点不会自动删除数据,而是由主节点控制从节点中过时数据的删除。由于主节点的惰性删除和定期删除计谋,都不能保证主节点实时对过时数据执行删除操作,因此,当客户端通过Redis从节点读取数据时,很容易读取到已经由期的数据。

Redis 3.2中,从节点在读取数据时,增添了对数据是否过时的判断:若是该数据已过时,则不返回给客户端;将Redis升级到3.2可以解决数据过时问题。

3. 故障切换问题
在没有使用哨兵的读写星散场景下,应用针对读和写划分毗邻差别的Redis节点;当主节点或从节点泛起问题而发生更改时,需要实时修改应用程序读写Redis数据的毗邻;毗邻的切换可以手动举行,或者自己写监控程序举行切换,但前者响应慢、容易失足,后者实现庞大,成本都不算低。

4. 总结
在使用读写星散之前,可以思量其他方式增添Redis的读负载能力:如只管优化主节点(削减慢查询、削减持久化等其他情形带来的壅闭等)提高负载能力;使用Redis集群同时提高读负载能力和写负载能力等。若是使用读写星散,可以使用哨兵,使主从节点的故障切换尽可能自动化,并削减对应用程序的侵入。

2. 复制超时问题

主从节点复制超时是导致复制中止的最主要的缘故原由之一,本小节单独说明超时问题,下一小节说明其他会导致复制中止的问题。

超时判断意义

在复制毗邻确立历程中及之后,主从节点都有机制判断毗邻是否超时,其意义在于:

  1. 若是主节点判断毗邻超时,其会释放相应从节点的毗邻,从而释放种种资源,否则无效的从节点仍会占用主节点的种种资源(输出缓冲区、带宽、毗邻等);此外毗邻超时的判断可以让主节点更准确的知道当前有用从节点的个数,有助于保证数据平安(配合前面讲到的min-slaves-to-write等参数)。

  2. 若是从节点判断毗邻超时,则可以实时重新确立毗邻,制止与主节点数据历久的不一致。

判断机制

主从复制超时判断的焦点,在于repl-timeout参数,该参数划定了超时时间的阈值(默认60s),对于主节点和从节点同时有用;主从节点触发超时的条件划分如下:

  1. 主节点:每秒1次挪用复制准时函数replicationCron(),在其中判断当前时间距离上次收到各个从节点REPLCONF ACK的时间,是否跨越了repl-timeout值,若是跨越了则释放相应从节点的毗邻。

  2. 从节点:从节点对超时的判断同样是在复制准时函数中判断,基本逻辑是:

    • 若是当前处于毗邻确立阶段,且距离上次收到主节点的信息的时间已跨越repl-timeout,则释放与主节点的毗邻;
    • 若是当前处于数据同步阶段,且收到主节点的RDB文件的时间超时,则住手数据同步,释放毗邻;
    • 若是当前处于下令流传阶段,且距离上次收到主节点的PING下令或数据的时间已跨越repl-timeout值,则释放与主节点的毗邻。

需要注重的坑

下面先容与复制阶段毗邻超时有关的一些实际问题:

  1. 数据同步阶段:在主从节点举行全量复制bgsave时,主节点需要首先fork子历程将当前数据保留到RDB文件中,然后再将RDB文件通过网络传输到从节点。若是RDB文件过大,主节点在fork子历程+保留RDB文件时耗时过多,可能会导致从节点长时间收不到数据而触发超时;此时从节点会重连主节点,然后再次全量复制,再次超时,再次重连……这是个悲痛的循环。为了制止这种情形的发生,除了注重Redis单机数据量不要过大,另一方面就是适当增大repl-timeout值,详细的巨细可以凭据bgsave耗时来调整。

  2. 下令流传阶段:如前所述,在该阶段主节点会向从节点发送PING下令,频率由repl-ping-slave-period控制;该参数应显著小于repl-timeout值(后者至少是前者的几倍)。否则,若是两个参数相等或靠近,网络发抖导致个体PING下令丢失,此时恰巧主节点也没有向从节点发送数据,则从节点很容易判断超时。

  3. 慢查询导致的壅闭:若是主节点或从节点执行了一些慢查询(如keys *或者对大数据的hgetall等),导致服务器壅闭;壅闭时代无法响应复制毗邻中对方节点的请求,可能导致复制超时。

总结

Redis 高可用系列的第二弹:主从复制的焦点内容已经解说完毕了,希望人人阅读完会有一点收获,另外若是人人以为看完文章有辅助的话,可以点赞,珍藏微微示意一下支持,好让我能有动力继续写手艺文章。

另外:我开了民众号【码农富哥】(id: coder2025),专注于写后端,服务端的原创干文,连续更新手法文章,人人有兴趣也可以关注一下!

迎接关注民众号:「码农富哥」,致力于分享后端手艺 (高并发架构,漫衍式集群系统,新闻行列中间件,网络,微服务,Linux, TCP/IP, HTTP, MySQL, Redis), Python 等 原创干货 和 面试指南!

彻底搞懂Redis主从复制原理及实战

原创文章,作者:28qn新闻网,如若转载,请注明出处:https://www.28qn.com/archives/18979.html