Redis主从复制高可用集群详解-创新互联

一、Redis单点故障 1、单机故障问题 

1. 单机故障

让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名与空间、虚拟空间、营销软件、网站建设、琼中黎族网站维护、网站推广。

如果发生机器故障,例如磁盘损坏,主板损坏等,未能在短时间内修复好,客户端将无法连接redis。

当然如果仅仅是redis节点挂掉了,可以进行问题排查然后重启,姑且不考虑这段时间对外服务的可用性,那还是可以接受的。而发生机器故障,基本是无济于事。除非把redis迁移到另一台机器上,并且还要考虑数据同步的问题。

2. 容量瓶颈

假如一台机器是16G内存,redis使用了12G内存,而其他应用还需要使用内存,假设我们总共需要60G内存要如何去做呢,是否有必要购买64G内存的机器呢?

3. QPS瓶颈

redis官方数据显示可以达到10w的QPS,如果业务需要100w的QPS怎么去做呢?

关于容量瓶颈和QPS瓶颈是redis分布式需要解决的问题,而机器故障就是高可用的问题了。

2、单机故障解决方法

在分布式系统中为了解决单点问题,通常会把数据复制多个副本部署到其他机器(主从模式),满足故障恢复和负载均衡的需求。

  • 主(Master)和从(Slave)分别部署在不同的服务器上,当主节点服务器写入数据时,同时也会将数据同步到从节点服务器。
  • 通常情况下,主节点负责写入数据,从节点负责读出数据

redis也是如此,它为我们提供了复制功能,实现了相同数据的多个redis副本(复制功能是高可用redis的基础,哨兵和集群都是在复制的基础上实现高可用的)。

但是这样会有如下问题,多个副本之间的数据如何保持一致呢?数据读写操作可以发送给所有实例呢?

实际上,Redis 提供了主从库模式,以保证数据副本的一致,主从库之间采用的是读写分离的方式。

  • 读操作:主库、从库都可以接收;
  • 写操作:首先到主库执行,然后,主库将写操作同步给从库。

即:

说明: 

  • redis主机会一直将自己的数据复制给redis从机,从而实现主从同步;
  • 在这个过程中,只有master主机可以执行写命令,其他slave从机只能执行读命令;
  • 这种读写分离模式可以大大减轻redis主机的数据读取压力,从而提高了redis的效率,并同时提供了多个数据备份;
  • 主从模式是搭建Redis Cluster 集群最简单的一种方式;
二、CAP原理 1、CAP原理简介

在了解 Redis 的主从复制之前,让我们先来理解一下现代分布式系统的理论基石——CAP 原理。

CAP 原理是分布式存储的理论基石:

  • C:Consistent,一致性
  • A:Availability,可用性
  • P:Partition tolerance,分区容忍性

分布式系统的节点往往都是分布在不同的机器上进行网络隔离开的,这意味着必然会有网络断开的风险,这个网络断开的场景的专业词汇叫做”网络分区“。

在网络分区发生时,两个分布式节点无法进行通信,我们对一个节点进行的修改操作将无法同步到另外一个节点,所以数据的”一致性“将无法满足,因为两个分布式节点的数据不再保持一致。除非我们牺牲”可用性“,也就是暂停分布式节点服务,在网络分区发生时,不再提供修改数据的功能,直到网络状况完全恢复正常再继续对外提供服务。

一句话概括 CAP 原理就是——网络分区发生时,一致性和可用性两难全。

2、Redis主从同步最终一致性

Redis 的主从数据是 异步 复制的,所以分布式的 Redis 系统并不满足一致性要求。当客户端在 Redis 的主节点修改了数据后,立即返回,即使在主从网络断开的情况下,主节点依旧可以正常对外提供服务,所以 Redis 满足可用性。

而 Redis 其实是保证 ”最终一致性“,从节点会努力追赶主节点,最终从节点的状态会和主节点的状态保持一致。如果网络断开了,主从节点的数据将会出现大量不一致,一旦网络恢复,从节点会采用多种策略努力追赶上落后的数据,继续尽力保持和主节点一致。

三、主从复制类型 1、主备与主从

1. 主备

请求都只能打到Master主节点上,备机只是等主机挂了后来自动升级为客户端继续提供服务。也就是说他不会为主节点分摊请求压力。

2. 主从

读请求会均摊到主节点和从节点上,而不是等主机挂了才提供服务。写请求在master上进行,然后同步到slaver。读请求会分摊,比如10w个请求,一主双从的话,可能M上3w个,两个S上处理6w个,他会为主节点分摊压力。所以可以解决单点故障问题。

2、主从复制三种类型

1. 同步阻塞

这种方式讲究强一致性,必须等所有Slave都写入成功后我才会给客户端响应,否则一直阻塞。也是CAP中的C。

原理图:

  • 优点:数据强一致性(但是会破坏可用性,也就是CAP的A)。
  • 缺点:效率低,同步阻塞。

2. 异步非阻塞

Redis采取的这种方式。没有采取下面同步阻塞mq的方式可能也是因为效率吧,因为Redis就是要高效。客户端发完请求到Redis Master后,立马给客户端返回,我不管你Slaver是否同步完成。保留CAP的A,舍弃C。

原理图:

  • 优点:效率高,异步非阻塞。
  • 缺点:会丢失数据,满足了CAP的A,舍弃了CAP的C。

3. 同步阻塞MQ

大数据hive采取的就是这种方式,他会保证最终一致性。相对于第二种方式好处在于能保证数据的最终一致性,坏处在于没第二种方式高效,但第二种存在丢数据的风险。

  • 优点:效率相对较高、能保证数据最终一致性。
  • 缺点:没发现啥缺点。非要说缺点那就是有可能取到不一致的数据,因为不是强一致性。为什么Redis不采取这个?因为Redis要高效率,不想融入太多组件(MQ)进来。
四、Redis主从复制实现原理 1、Redis主从复制简介

主从复制其实就是实现高可用(虽然是人工操作),避免单点故障问题。挂掉一个节点,我其他节点可以接着提供服务,但是明显缺点发现是Slave挂掉还好,Master挂掉可就难受了,Slave太多的话那就够运维折腾的了,这时候就有了哨兵。 同时,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况,主从复制也能够分担读压力。

主从复制原理图:

其实就跟MySQL一个道理,mysql是靠binlog,而Redis靠的是rdb文件和aof文件。

2、主从复制实现原理

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

设置主节点的地址和端口-》建立套接字链接-》发送PING命令-》权限验证-》同步-》命令传播

接下来分别叙述每个步骤,整个流程图如下:

假设在本地机开启两个Redis节点,分别监听:

  • 127.0.0.1 6379(主)
  • 127.0.0.1 6380(从) 

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 命令分别查看从服务器的主从信息:

而6379服务器已经成为主服务器角色: 

3. 发送PING命令

从节点成为了主节点的客户端之后,发送 ping 命令进行首次请求,目的是:检查socket连接是否可用,以及主节点当前是否能够处理请求。

从节点发送 ping 命令后,可能出现3种情况:

  1. 返回 PONG:说明socket连接正常,且主节点当前可以处理请求,复制过程继续。
  2. 超时:一定时间后从节点仍未收到主节点的回复,说明socket连接不可用,则从节点断开socket连接,并重连。
  3. 返回pong以外的结果:如果主节点返回其他结果,如正在处理超市运行的脚本,说明主节点当前无法处理命令,则从节点端口socket连接,并重连。

4. 身份验证

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

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

5. 同步

同步就是将从节点的数据库状态更新成主节点当前的数据库状态。具体执行的方式是:从节点向主节点发送psync命令(Redis2.8以前是sync命令),开始同步。

数据同步阶段是主从复制最核心的阶段,根据主从节点当前状态的不同,可以分为 全量复制 和 部分复制。

6. 命令传播

经过上面同步操作,此时主从的数据库状态其实已经一致了,但这种一致的状态并不是一成不变的。

在完成同步之后,也许主服务器马上就接受到了新的写命令,执行完该命令后,主从的数据库状态又不一致。

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

另外命令传播我们需要关注两个点:延迟与不一致 和 心跳机制。

  • 延迟与不一致

需要注意的是,命令传播是异步的过程,即主节点发送写命令后并不会等待从节点的回复;因此实际上主从节点之间很难保持实时的一致性,延迟在所难免。数据不一致的程度,与主从节点之间的网路状况、主节点写命令执行频率、以及主节点中repl-disable-tcp-nodelay 配置等有关。

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

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

概括来说就是:前者关注性能,后者关注一致性。

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

命令传播阶段,从服务器会利用心跳检测机制定时的向主服务发送消息。

3、Redis主从复制结构

Redis的主从结构可以采用一主一从、一主多从或者树状主从结构,Redis主从复制可以根据是否是全量分为全量同步和增量同步。

一主一从:

  • 一主一从是最简单的复制拓扑结构,用于主节点出现宕机时从节点提供故障转移支持
  • 当应用写命令并发量较高而且需要持久化时,可以只在从节点开启AOF,这样即保证了数据安全性同时也避免了持久化对主节点的性能干扰
  • 但需要注意的是, 当主节点关闭持久化功能时,如果主节点脱机要避免自动重启操作。 因为主节点之前没有开启持久化功能自动重启后数据集为空, 这时从节点如果继续复制主节点会导致从节点数据也被清空的情况, 丧失了持久化的意义。 安全的做法是在从节点上执行slaveof no one断开与主节点的复制关系, 再重启主节点从而避免这一问题。

一主多从:

  • 一主多从结构(又称为星形拓扑结构) 使得应用端可以利用多个从节点实现读写分离(见图) 。 对于读占比较大的场景, 可以把读命令发送到从节点来分担主节点压力。
  • 同时在日常开发中如果需要执行一些比较耗时的读命令, 如: keys、 sort等, 可以在其中一台从节点上执行, 防止慢查询对主节点造成阻塞从而影响线上服务的稳定性。
  • 对于写并发量较高的场景, 多个从节点会导致主节点写命令的多次发送从而过度消耗网络带宽, 同时也加重了主节点的负载影响服务稳定性。

树状主从结构:

  • 树状主从结构(又称为树状拓扑结构) 使得从节点不但可以复制主节点数据, 同时可以作为其他从节点的主节点继续向下层复制
  • 通过引入复制中间层, 可以有效降低主节点负载和需要传送给从节点的数据量。
  • 如图所示, 数据写入节点A后会同步到B和C节点, B节点再把数据同步到D和E节点, 数据实现了一层一层的向下复制。
  • 当主节点需要挂载多个从节点时为了避免对主节点的性能干扰, 可以采用树状主从结构降低主节点压力。

在Redis2.8以前,从接待你向主节点发送sync命令请求同步数据,此时的同步方式是全量复制;在Redis2.8及以后,从节点可以发送psync命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制。

全量复制:用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作。

部分复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效,需要注意的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行地写命令,则无法进行部分复制,仍使用全量复制。

1. 全量同步

Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。

具体步骤如下: 

  • 从服务器连接主服务器,发送SYNC命令; 
  • 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令; 
  • 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令; 
  • 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照; 
  • 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令; 
  • 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;

完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来自用户的读请求。

2. 增量同步

由于全量复制在主节点数据量较大时效率太低,因此Redis2.8开始提供部分复制,用于处理网络中断时的数据同步。

部分复制的实现,依赖于三个重量的概念:复制偏移量、复制积压缓冲区、服务器运行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)复制积压缓冲区(replication-backlog-buffer)

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

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

为了提高网络中断时部分复制执行的概率,可以根据需要增大复制积压缓冲区的大小(通过配置repl-backlog-size);例如如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(某些特定协议格式)所占据的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。

从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制:

  • 如果offset偏移量之后的数据,仍然都在复制积压缓冲区例,则执行部分复制;
  • 如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制。

3)服务器运行ID(runid)

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

如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);

如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制。

4、psync命令的执行

在了解了复制偏移量、复制积压缓冲区、节点运行id之后,这里psync命令的参数和返回值,从而说明psync命令执行过程中,主从节点是如何确定使用全量复制还是部分复制的。

psync命令流程图如下:

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,进行完整的数据全量复制。

Redis通过psnyc命令进行全量复制的过程如下:

  1. 从节点判断无法进行部分复制,向主节点发送全量复制的请求;或从节点发送部分复制的请求,但主节点判断无法进行部分复制;
  2. 主节点收到全量复制的命令后,执行bgsave,在后台生成RDB文件,并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令;
  3. 主节点的bgsave执行完成后,将RDB文件发送给从节点;从节点首先清除自己的旧数据,然后载入接收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态;
  4. 主节点将前述复制缓冲区中的所有写命令发送给从节点,从节点执行这些写命令,将数据库状态更新至主节点的最新状态;
  5. 如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态;

通过全量复制的过程可以看出,全量复制是非常重型的操作:

  1. 主节点通过bgsave命令fork子进程进行RDB持久化,该过程是非常消耗CPU、内存(页表复制)、磁盘IO的;
  2. 主节点通过网络将RDB文件发送给从节点,对主从节点的带宽都会带来很大的消耗;
  3. 从节点清空老数据、载入新RDB文件的过程是阻塞的,无法响应客户端的命令;如果从节点bgrewriteaof,也会带来额外的消耗;

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

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

检查主从服务器的网络连接状态,主节点信息中可以看到所属的从节点的连接信息:

state 表示从节点状态、offset表示复制偏移量、lag表示延迟值(几秒之前有过心跳检测机制)

辅助实现min-slaves选项,Redis.conf 配置文件中有下方两个参数:

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

如果将两个参数注释取消,那么如果从服务器的数量少于3个,或者三个从服务器的延迟(lag)大于等于10秒时,主服务器都会拒绝执行写命令。

检测命令丢失时,在从服务器的连接信息中可以看到复制偏移量,如果此时主服务器的复制偏移量与从服务器的复制偏移量不一致时,主服务器会补发缺失的数据。

5、无磁盘复制

通常来讲,一个完全重新同步需要在磁盘上创建一个RDB文件,然后加载这个文件以便为从服务器发送数据。如果使用比较低速的磁盘,这种操作会给主服务器带来较大的压力。Redis从2.8.18版本开始尝试支持无磁盘的复制。使用这种设置时,子进程直接将RDB通过网络发送给从服务器,不使用磁盘作为中间存储,避免了IO性能差问题。

可以使用repl-diskless-sync 配置参数来启动无磁盘复制。使用repl-diskless-sync-delay参数来配置传输开始的延迟时间,以便等待更多的从服务器连接上来。

开启无磁盘复制:

repl-diskless-sync yes
6、主从复制架构中出现宕机情况

如果在主从复制架构中出现宕机的情况,需要分情况看:

1. 从Redis宕机

这个相对而言比较简单,在Redis中从库重新启动后会自动加入到主从架构中,自动完成同步数据,这是因为在Redis2.8版本后就新增了增量复制功能,主从断线后恢复是通过增量复制实现的。所以这种情况无需担心。

2. 主Redis宕机

这个情况相对而言就会复杂一些,需要以下2步才能完成:

第一步,在从数据库中执行SLAVEOF NO ONE命令,断开主从关系并且提升为主库继续服务;

第二步,将主库修复重新启动后,执行SLAVEOF命令,将其设置为其他库的从库,这时数据就能更新回来;

这两个步骤要通过手动完成恢复,过程其实是比较麻烦的并且容易出错,有没有好办法解决呢?有的,Redis提供的哨兵(sentinel)功能就可以实现主Redis宕机的自动切换。

7、Redis主从复制总结

1. Redis主从复制策略

主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

2. 主从复制的特点

主从复制的特点:

  1. 采用异步复制;
  2. 一个主redis可以含有多个从redis;
  3. 每个从redis可以接收来自其他从redis服务器的连接;
  4. 主从复制对于主redis服务器来说是非阻塞的,这意味着当从服务器在进行主从复制同步过程中,主redis仍然可以处理外界的访问请求;
  5. 主从复制对于从redis服务器来说也是非阻塞的,这意味着,即使从redis在进行主从复制过程中也可以接受外界的查询请求,只不过这时候从redis返回的是以前老的数据,如果你不想这样,那么在启动redis时,可以在配置文件中进行设置,让redis在复制同步过程中对来自外界的查询请求都返回错误给客户端;(虽然说主从复制过程中,对于从redis是非阻塞的,但是当从redis从主redis同步过来最新的数据后,还需要将新数据加载到内存中,在加载到内存的过程中是阻塞的,在这段时间内的请求将会被阻);
  6. 主从复制提高了redis服务的扩展性,避免单个redis服务器的读写访问压力过大的问题,同时也可以给为数据备份及冗余提供一种解决方案;
  7. 为了避免主redis服务器写磁盘压力带来的开销,可以配置让主redis不在将数据持久化到磁盘,而是通过连接让一个配置的从redis服务器及时的将相关数据持久化到磁盘,不过这样会存在一个问题,就是主redis服务器一旦重启,因为主redis服务器数据为空,这时候通过主从同步可能导致从redis服务器上的数据也被清空;所以要避免主redis自动重启。
8、主从模式不足

主从模式并不完美,它也存在许多不足之处,下面做了简单地总结:

  • redis主从模式不具备自动容错和恢复功能,如果主节点宕机,redis集群将无法工作,此时需要人为干预,将从节点提升为主节点
  • 如果主机宕机前有一部分数据未能及时同步到从机,及时切换主机后也会造成数据不一致的问题,从而降低了系统的可用性
  • 因为只有一个主节点,所以其写入能力和存储能力都受到一定的限制
  • 在进行数据全量同步时,如果同步的数据量较大可能会造成卡顿的现象

虽然主从模式存在上述不足,但他仍然是实现分布式集群的基础。Sentinel哨兵模式同样是依赖于主从模式实现。

五、Redis主从复制实战 1、主从复制配置文件

redis.config配置文件相关配置:

  • slaveof:复制选项,slave复制对应的master的ip和端口。
  • masterauth:如果master设置了requirepass,那么slave要连上master,需要有master的密码才行。masterauth就是用来配置master的密码,这样可以在连上master后进行认证。
  • slave-serve-stale-data yes:当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续响应客户端的请求;2) 如果slave-serve-stale-data设置为no,除去INFO和SLAVOF命令之外的任何请求都会返回一个错误”SYNC with master in progress”。
  • slave-read-only yes:作为从服务器,默认情况下是只读的(yes),可以修改成NO,用于写(不建议)。
  • repl-diskless-sync no:是否使用socket方式复制数据。目前redis复制提供两种方式,disk和socket。如果新的slave连上来或者重连的slave无法增量同步,就会执行全量同步,master会生成rdb文件。有2种方式:1)disk方式是master创建一个新的进程把rdb文件保存到磁盘,再把磁盘上的rdb文件传递给slave;2)socket是master创建一个新的进程,直接将RDB通过网络发送给slave,不使用磁盘作为中间存储。disk方式的时候,rdb是作为一个文件保存在磁盘上,因此多个slave都能共享这个rdb文件。socket方式的复制(无盘复制)是基于顺序的串行复制(master会等待一个repl-diskless-sync-delay的秒数,如果没slave来注册话,就直接传,后来的slave得排队等待。已注册的就可以一起传)。在磁盘速度缓慢,网速快的情况下推荐用socket方式。
  • repl-diskless-sync-delay 5:无磁盘复制的延迟时间,不要设置为0。因为一旦复制开始,master节点不会再接收新slave的复制请求,直到这个rdb传输完毕。所以最好等待一段时间,等更多的slave注册上到master后一起传输,提供同步性能。
  • repl-ping-slave-period 10:slave根据指定的时间间隔向服务器发送ping请求。时间间隔可以通过 repl_ping_slave_period 来设置,默认10秒。
  • repl-timeout 60:复制连接超时时间。master和slave都有超时时间的设置。master检测到slave上次发送的时间超过repl-timeout,即认为slave离线,清除该slave信息。slave检测到上次和master交互的时间超过repl-timeout,则认为master离线。需要注意的是repl-timeout需要设置一个比repl-ping-slave-period更大的值,不然会经常检测到超时。
  • repl-backlog-size 5mb:复制缓冲区大小,这是一个环形复制缓冲区,用来保存最新复制的命令。这样在slave离线的时候,不需要完全复制master的数据,如果可以执行部分同步,只需要把缓冲区的部分数据复制给slave,就能恢复正常复制状态。缓冲区的大小越大,slave离线的时间可以更长,复制缓冲区只有在有slave连接的时候才分配内存。没有slave的一段时间,内存会被释放出来,默认1m。
  • repl-backlog-ttl 3600:master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。单位为秒。

配置主从:

# 相当于我们上面客户端执行的REPLICAOF命令,配置到配置文件每次重启就不用手动再执行命令了。
replicaof# master的密码
masterauth

主从传输数据这期间,从节点是否允许对外提供服务:

# 默认是ye,允许
slave-serve-stale-data yes

看下面的log(这是我们建立主从关系的时候产生的log)。

意思是说在和Master建立连接,获取完Master数据之间,也就是从库进行flush操作之前,是否允许对外继续提供请求(就是Slave完成配置之前的那些flush之前的老数据是否还允许被访问)。

是否开启Slave从节点也支持写命令:

# 默认只读,yes代表只读
slave-read-only yes

先落磁盘再传输还是直接网络传输:

# 默认是先落盘,再进行网络传输
repl-diskless-sync no

因为默认是Master先生成rdb文件到磁盘,这时候产生一次磁盘IO,然后将磁盘上rdb文件以网络的方式传递给Slave,这时候又产生一次IO,如果rdb几个GB的话那还不如直接走网络传输,就不走磁盘io了。 改为yes的话直接Master通过网络的方式发送rdb给Slave。默认是no,从日志也可以看出先落盘了

原理图:

全量还是增量:

repl-backlog-size 1mb

可以发现比主从复制原理图中多了个队列和偏移量。

这个队列代表repl-backlog-size参数设置的值大小,是决定全量复制还是增量复制的关键参数。

RDB每次同步到slave的时候,slave都会记录一个offset偏移量,然后每次同步数据的时候都会看队列里的数据偏移量是否符合slave上次同步的数据大小,若符合则增量,否则全量。

举例:

如果设置的1MB,你挂了3s钟,假设1s钟就写了1MB,那么3s钟的队列肯定放不下,这时候就触发全量,所以这个需要看业务调整大小。

再比如master是100MB数据,slave也是1MB数据,然后slave挂了。恢复的时候发现master已经有110MB了,但是队列大小只有1MB,把队列里的数据拿来显然不行,所以会触发全量,这只是举例,其实不会那么傻的判断总大小,而是通过偏移量来的。 

2、仅开启RDB

仅仅开启RDB持久化,关闭AOF。

首先启动三个redis,端口分别是6379、6380、6381。我们这里设定6379为Master,其余两个为Slaver。

1. 如何设置Slaver

可以看到Redis5.x后开始用REPLICAOF命令代替5.x版本之前的SLAVEOF命令。

2. 设置Slaver

# 设置6380是6379的从节点
127.0.0.1:6380>REPLICAOF localhost 6379
OK

设置完成后去看6379和6380的log

6379的log:

6380的log:

3. ​​​​在Master执行写命令

127.0.0.1:6379>set k1 123
OK
127.0.0.1:6379>get k1
"123"

4. 在Slave(6380)上查看是否同步过来了

127.0.0.1:6380>keys *
1) "k1"
127.0.0.1:6380>get k1
"123"

5. Slave是禁止执行写命令的

127.0.0.1:6380>set k2 123
(error) READONLY You can't write against a read only replica.

6. 设置6382也作为6379的Slave

设置从节点之前先在6382内set一个值,为了确定设置完后会进行flush操作。

127.0.0.1:6381>set k2 222
OK
127.0.0.1:6381>get k2
"222"

然后设置Slave:

127.0.0.1:6381>REPLICAOF 127.0.0.1 6379
OK
127.0.0.1:6381>keys *
1) "k1"

将Master的数据同步过来了。

如果设置Slave后进行了flush操作(上面的log也体现出来了),我们之前的k2没了。

若6381宕机了,这时候他再启动的时候是会同步Master的数据的,增量同步的。不需要手动进行同步。

但前提是需要作为Master的Slave,有如下三种方式:

  • 客户端执行REPLICAOF;
  • 启动Redis的时候添加 --REPLICAOF 127.0.0.1 6379,比如 service redis_6381 start --REPLICAOF 127.0.0.1 6379;
  • 修改配置文件;

8. Master挂了怎么办

从节点会一直报错:

导致的问题:Slave无法提供写请求,只能读了。影响了业务使用。

解决方案:让其中一个Slave升级为Master,然后其他Slave作为这个新升级为Master的从。 

# 升级为Master的方法:在客户端执行,比如我们升级6380为Master
127.0.0.1:6380>REPLICAOF no one
OK
# 这时候再看6380就不会再刷错了,但是6381还在刷,
# 因为6381是已经挂掉的6379的Slave,我们需要让6381作为6380的Slave,
# 我们再操作这步骤之前,对6380set一个key,然后看6381的数据会重新复制6380的数据
# 显示业务中几乎不会存在此情况,因为从节点升级就是升级,所有主从的数据都一致,不会随意改
# 这里只是演示效果而已。
127.0.0.1:6380>set kkk 3333
OK
# 6381作为6380的Slave
127.0.0.1:6381>REPLICAOF 127.0.0.1 6380
OK
127.0.0.1:6381>keys *
1) "kkk"
2) "k1"
127.0.0.1:6381>get kkk
"3333"
3、RDB+AOF混合模式

1. 仅开启AOF

和上面一样。只是会按照aof文件进行主从复制数据。

2. 混合模式(RDB+AOF)

流程和仅开启RDB一样,只是主从复制的时候会优先按照aof来同步数据,因为aof文件丢失数据最少,更可靠。redis会判断aof文件是否存在,若开启了aof且文件存在,则以aof复制,若没开启aof则走rdb方式。

4、Redis主从复制实战

1. 使用命令实现

1)方法一

使用命令在服务端搭建主从模式,其语法格式如下:

redis-server --port--slaveof

执行以下命令:

#开启开启一个port为6300的从机,它依赖的主机port=6379
>redis-server --port 6300 --slaveof 127.0.0.1 6379

接下来开启客户端,并执行查询命令,如下所示: 

>redis-cli -p 6300
127.0.0.1:6300>get name
"jack"
127.0.0.1:6300>get website
"www.biancheng.net"
#不能执行写命令
127.0.0.1:6300>set myname BangDe
(error) READONLY You can't write against a read only slave.
127.0.0.1:6300>keys *
1) "myset:__rand_int__"
2) "ID"
3) "title"
4) "course2"

从上述命令可以看出,port =6300 的主机,完全备份了主机的数据,它可以执行查询命令,但不能执行写入命令

从机服务端提示如下:

[18160] 20 Jan 17:40:34.101 # Server initialized #服务初始化
[18160] 20 Jan 17:40:34.108 * Ready to accept connections #准备连接
[18160] 20 Jan 17:40:34.108 * Connecting to MASTER 127.0.0.1:6379 #连接到主服务器
[18160] 20 Jan 17:40:34.109 * MASTER<->REPLICA sync started #启动副本同步
[18160] 20 Jan 17:40:34.110 * Non blocking connect for SYNC fired the event.#自动触发SYNC命令,请求同步数据
[18160] 20 Jan 17:40:34.110 * Master replied to PING, replication can continue...
[18160] 20 Jan 17:40:34.112 * Partial resynchronization not possible (no cached master)
[18160] 20 Jan 17:40:34.431 * Full resync from master: 6eb220706f73107990c2b886dbc2c12a8d0d9d05:0
[18160] 20 Jan 17:40:34.857 * MASTER<->REPLICA sync: receiving 6916 bytes from master #从主机接受了数据,并将其存在于磁盘
[18160] 20 Jan 17:40:34.874 * MASTER<->REPLICA sync: Flushing old data #清空原有数据
[18160] 20 Jan 17:40:34.874 * MASTER<->REPLICA sync: Loading DB in memory #将磁盘中数据载入内存
[18160] 20 Jan 17:40:34.879 * MASTER<->REPLICA sync: Finished with success #同步数据完成

可以看出主从模式下,数据的同步是自动完成的,这个数据同步的过程,又称为全量复制。

2)方法二

启动一个服务端,并指定端口号。

#指定端口号为63001,不要关闭
redis-server --port 63001

打开一个客户端,连接服务器,如下所示:

# 连接port=63001的服务器
>redis-cli -p 63001
// 现在处于主机模式下,所以运行读写数据
127.0.0.1:63001>keys *
1) "name"
127.0.0.1:63001>get name
"aaaa"
127.0.0.1:63001>set name "bbbb"
OK
127.0.0.1:63001>get name
"bbbb"
127.0.0.1:63001># 将当前服务器设置为从服务器,从属于6379
127.0.0.1:63001>SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:63001>keys *   
1) "master_6379"    # 现在它的数据和主服务器的数据一样了
#写入命令执行失败
127.0.0.1:63001>SET mywebsite www.biancheng.net
(error) READONLY You can't write against a read only replica.
#再次切换为主机模式,执行下面命令
127.0.0.1:63001>SLAVEOF no one
OK
127.0.0.1:63001>SLAVEOF no one
OK
127.0.0.1:63001>keys *
1) "master_6379"       # 数据还是和之前主服务器的一样
127.0.0.1:63001>SET mywebsite www.biancheng.net  # 但是现在可以写入命令了
OK
127.0.0.1:63001>keys *
1) "mywebsite"
2) "master_6379"

2. 修改配置文件实现

每个 Redis 服务器都有一个与其对应的配置文件,通过修改该配置文件也可以实现主从模式。

新建 redis_6302.conf 文件,并添加以下配置信息:

slaveof 127.0.0.1 6379 #指定主机的ip与port
port 6302 #指定从机的端口

启动 Redis 服务器,执行以下命令:

$ redis-server redis_6302.conf

客户端连接服务器,并进行简单测试。

执行以下命令:

$ redis-cli -p 6302
127.0.0.1:6300>HSET user:username biangcheng
#写入失败
(error) READONLY You can't write against a read only slave.

通过命令搭建主从模式,简单又快捷,所以不建议使用修改配置文件的方法。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


分享文章:Redis主从复制高可用集群详解-创新互联
链接地址:http://myzitong.com/article/ddgego.html