Redis_主从复制模式

229 阅读23分钟

Redis 实例宕机了怎么实现高可用呢

既然一台宕机了无法提供高可用,那就是用多台服务器,只要有一台服务器可以对外提供服务,则就满足我们的需求。

高可用有两个含义:

  • 一是数据尽量少丢失,
  • 二是服务尽量少中断。

AOF 和 RDB 保证了前者,而对于后者,Redis 的做法就是增加副本冗余量,将一份数据同时保存在多个实例上。即使有一个实例出现了故障,需要过一段时间才能恢复,其他实例也可以对外提供服务,不会影响业务使用。

多台Redis提供了那些特性

  • 通过副本机制可以保证数据不会丢失,保证了数据的可靠性
  • 多台服务器对外提供服务,若N-1台服务器宕机,该服务还是可以对外提供服务。保证了服务的高可用,
  • 一台服务器存在性能瓶颈,而且容量有限,通过集群可以增加服务的吞吐量。

在生产环境,因为对高可用和可靠性的要求,则需要引入Redis的集群方案。

Redis支持三种集群方案

  • 主从复制模式
  • Sentinel(哨兵)模式
  • Cluster模式

redis.conf 配置文件中的各个参数的解释

# redis进程是否以守护进程的方式运行,yes为是,no为否(不以守护进程的方式运行会占用一个终端)。 
daemonize no 
# 指定redis进程的PID文件存放位置 
pidfile /var/run/redis.pid 
# redis进程的端口号 
port 6379 
#是否开启保护模式,默认开启。要是配置里没有指定bind和密码。开启该参数后,redis只会本地进行访问,拒绝外部访问。要是开启了密码和bind,可以开启。否则最好关闭设置为no。 
protected-mode yes 
# 绑定的主机地址 
bind 127.0.0.1 
# 客户端闲置多长时间后关闭连接,默认此参数为0即关闭此功能 
timeout 300 
# redis日志级别,可用的级别有debug.verbose.notice.warning 
loglevel verbose 
# log文件输出位置,如果进程以守护进程的方式运行,此处又将输出文件设置为stdout的话,就会将日志信息输出到/dev/null里面去了 
logfile stdout 
# 设置数据库的数量,默认为0可以使用select <dbid>命令在连接上指定数据库id 
databases 16 
# 指定在多少时间内刷新次数达到多少的时候会将数据同步到数据文件 
save <seconds> <changes> 
# 指定存储至本地数据库时是否压缩文件,默认为yes即启用存储 
rdbcompression yes 
# 指定本地数据库文件名 
dbfilename dump.db 
# 指定本地数据问就按存放位置 
dir ./ 
# 指定当本机为slave服务时,设置master服务的IP地址及端口,在redis启动的时候他会自动跟master进行数据同步 
replicaof <masterip> <masterport> 
# 当master设置了密码保护时,slave服务连接master的密码 
masterauth <master-password> 
# 设置redis连接密码,如果配置了连接密码,客户端在连接redis是需要通过AUTH<password>命令提供密码,默认关闭 
requirepass footbared 
# 设置同一时间最大客户连接数,默认无限制。redis可以同时连接的客户端数为redis程序可以打开的最大文件描述符,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回 max number of clients reached 错误信息 
maxclients 128 
# 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key。当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区 
maxmemory<bytes> 
# 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no。 
appendonly no 
# 指定跟新日志文件名默认为appendonly.aof 
appendfilename appendonly.aof 
# 指定更新日志的条件,有三个可选参数 - no:表示等操作系统进行数据缓存同步到磁盘(快),always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全), everysec:表示每秒同步一次(折衷,默认值); 
appendfsync everysec 

主从复制

主从复制:主从复制是高可用redis的基础,主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。

哨兵和集群都是在主从复制基础上实现高可用的。

缺点:故障恢复无法自动化,写操作无法负载均衡,存储能力受到单机的限制。

1.原理

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

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

为什么要采用读写分离的方式呢

你可以设想一下,如果在上图中,不管是主库还是从库,都能接收客户端的写操作,那么,一个直接的问题就是:如果客户端对同一个数据(例如 k1)前后修改了三次,每一次的修改请求都发送到不同的实例上,在不同的实例上执行,那么,这个数据在这三个实例上的副本就不一致了(分别是 v1、v2 和 v3)。在读取这个数据的时候,就可能读取到旧的值。

如果我们非要保持这个数据在三个实例上一致,就要涉及到加锁、实例间协商是否完成修改等一系列操作,但这会带来巨额的开销,当然是不太能接受的。

而主从库模式一旦采用了读写分离,所有数据的修改只会在主库上进行,不用协调三个实例。主库有了最新的数据后,会同步给从库,这样,主从库的数据就是一致的。

从原理上来说,Redis的主从复制主要包括了全量复制、增量复制和长连接同步三种情况。

  • 全量复制传输RDB文件,发生在第一次主从库全量复制;
  • 增量复制传输主从断连期间的命令,发生在主从库间网络断开重连同步。
  • 长连接同步则是把主节点正常收到的请求传输给从节点,发生在主从正常运行期间的同步;

这三种情况看似简单,但是在实现的时候,我们通常都需要考虑主从连接建立、主从握手和验证、复制情况判断和数据传输等多种不同状态下的逻辑处理。

2 主从复制搭建

在一台机器上简单操作

创建一个新的Iterm,启动redis server 端口指定:6379

xuyatao@evan171206  ~/devConf/tool/redis-7.0.4  redis-server --port 6379

创建一个新的Iterm,启动redis server 端口指定:6380

xuyatao@evan171206  ~/devConf/tool/redis-7.0.4  redis-server --port 6380

创建一个新的Iterm,创建redis client 端口指定:6379

 xuyatao@evan171206  ~/devConf/tool/redis-7.0.4  redis-cli -h 127.0.0.1 -p 6379

创建一个新的Iterm,创建redis client 端口指定:6380

 xuyatao@evan171206  ~/devConf/tool/redis-7.0.4  redis-cli -h 127.0.0.1 -p 6380

现在有两个实例

  • 实例1:127.0.0.1 6379
  • 实例2:127.0.0.1 6380

运行中设置从服务器

若将实例2当做主库,实例1 当做从库

在 Redis 运行过程中,我们可以使用 replicaof host port 命令,把自己设置为目标 IP 的从服务器,执行命令如下:

127.0.0.1:6379> replicaof 127.0.0.1 6380
OK

如果主服务设置了密码,需要在从服务器输入主服务器的密码,使用 config set masterauth 主服务密码 命令的方式,例如:

127.0.0.1:6377> config set masterauth pwd654321
OK

  1. 执行流程

在执行完 replicaof 命令之后,从服务器的数据会被清空,主服务会把它的数据副本同步给从服务器。

  1. 测试同步功能

主从服务器设置完同步之后,我们来测试一下主从数据同步,首先我们先在主服务器上执行保存数据操作,再去从服务器查询。

主服务器执行命令:

127.0.0.1:6380> set lang redis
OK

从服务执行查询:

127.0.0.1:6379> get lang
"redis"

可以看出数据已经被正常同步过来了。

启动时设置从服务器

我们可以使用命令 redis-server --port 6380 --replicaof 127.0.0.1 6379 将自己设置成目标服务器的从服务器。

查询服务器的角色

我们使用 role 命令,来查询当前服务器的主从角色信息。

主服务查看

在主服务器上执行 role 结果如下:

127.0.0.1:6380> role
1) "master"
2) (integer) 505
3) 1) 1) "127.0.0.1"
      2) "6379"
      3) "505"
127.0.0.1:6380>

master 表示主服务器,底下是从服务器的 IP、端口和连接时间。

从服务器查看

在从服务器执行 role 命令,执行结果如下:

127.0.0.1:6379> role
1) "slave"
2) "127.0.0.1"
3) (integer) 6380
4) "connected"
5) (integer) 505
127.0.0.1:6379>

slave 表示从服务器,底下主服务器的 IP、端口和连接时间。

3 主从复制的四大阶段

首先,我们可以根据主从复制时的关键事件,把整个复制过程分成四个阶段,分别是初始化、建立连接、主从握手、复制类型判断与执行。下面,我们就来依次了解下每个阶段的主要工作。

1.初始化阶段

当我们把一个Redis实例A设置为另一个实例B的从库时,实例A会完成初始化操作,主要是获得了主库的IP和端口号。

初始化过程,可以用三种方式来设置。

  • 方式一:在实例A上执行replicaof masterip masterport的主从复制命令,指明实例B的IP(masterip)和端口号(masterport)。
  • 方式二:在实例A的配置文件中设置replicaof masterip masterport,实例A可以通过解析文件获得主库IP和端口号。
  • 方式三:在实例A启动时,设置启动参数–replicaof [masterip] [masterport]。实例A解析启动参数,就能获得主库的IP和端口号。

比如现在有

  • 实例 1(192.168.1.108)
  • 实例 2(192.168.109.2)
  • 实例 3 (192.168.110.3)

在实例 2 和实例 3 上分别执行以下命令,实例 2 和 实例 3 就成为了实例 1 的从库,实例 1 成为 Master。

replicaof 192.168.1.108 6379

2.建立连接阶段

接下来,一旦实例2/3获得了主库IP和端口号,该实例就会尝试和主库建立TCP网络连接,并且会在建立好的网络连接上,监听是否有主库发送的命令。

3.主从握手阶段

当实例2/3和主库建立好连接之后,实例2/3就开始和主库进行握手。简单来说,握手过程就是主从库间相互发送PING-PONG消息,同时从库根据配置信息向主库进行验证。最后,从库把自己的IP、端口号,以及对无盘复制和PSYNC 2协议的支持情况发给主库。

4.复制类型判断与执行阶段

等到主从库之间的握手完成后,从库就会给主库发送PSYNC命令。紧接着,主库会根据从库发送的命令参数作出相应的三种回复,分别是执行全量复制、执行增量复制、发生错误。最后,从库在收到上述回复后,就会根据回复的复制类型,开始执行具体的复制操作。

4 第一次主从库全量复制

4.1.1 准备阶段

从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。

psync 命令包含了主库的 runID 和复制进度 offset 两个参数。

  • runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。
  • offset,此时设为 -1,表示第一次复制。
pysnc ? -1

主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到响应后,会记录下这两个参数。

4.1.2 主库同步数据给从库

主库对从库的PSYNC命令返回FULLRESYN{runID}{offset}。FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库

主库将所有数据同步给从库。从库收到数据后,在本地完成数据加载。这个过程依赖于内存快照生成的 RDB 文件。

具体来说,主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库。从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。这是因为从库在通过 replicaof 命令开始和主库同步前,可能保存了其他数据。为了避免之前数据的影响,从库需要先把当前数据库清空。

在主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求。否则,Redis 的服务就被中断了。但是,这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中。为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。

replication buffer 是什么

replication buffer:记录 RDB 文件生成后的所有写操作。

一个在 master 端上创建的缓冲区,存放的数据是下面三个时间内所有的 master 数据写操作。

  1. master 执行 bgsave 产生 RDB 的期间的写操作;
  2. master 发送 RDB 到 slave 网络传输期间的写操作;
  3. slave load RDB 文件把数据恢复到内存的期间的写操作。

Redis 和客户端通信也好,和从库通信也好,Redis 都分配一个内存 buffer 进行数据交互,客户端就是一个 client,从库也是一个 client,我们每个 client 连上 Redis 后,Redis 都会分配一个专有 client buffer,所有数据交互都是通过这个 buffer 进行的。

Master 先把数据写到这个 buffer 中,然后再通过网络发送出去,这样就完成了数据交互。

不管是主从在增量同步还是全量同步时,master 会为其分配一个 buffer ,只不过这个 buffer 专门用来传播写命令到从库,保证主从数据一致,我们通常把它叫做 replication buffer。

replication buffer 太小会引发的问题:

replication buffer 由 client-output-buffer-limit slave 设置,当这个值太小会导致主从复制连接断开。

  1. 当 master-slave 复制连接断开,master 会释放连接相关的数据。replication buffer 中的数据也就丢失了,此时主从之间重新开始复制过程。
  2. 还有个更严重的问题,主从复制连接断开,导致主从上出现重新执行 bgsave 和 rdb 重传操作无限循环。

当主节点数据量较大,或者主从节点之间网络延迟较大时,可能导致该缓冲区的大小超过了限制,此时主节点会断开与从节点之间的连接;

这种情况可能引起

全量复制 -> replication buffer 溢出导致连接中断 -> 重连 -> 全量复制 -> replication buffer 缓冲区溢出导致连接中断……

的循环。

具体详情:[top redis headaches for devops – replication buffer]

因而推荐把 replication buffer 的 hard/soft limit 设置成 512M。

config set client-output-buffer-limit "slave 536870912 536870912 0"

4.1.3 发送新写命令到从库

主库会把新收到的写命令,再发送给从库。具体的操作是,当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了。

4.2 主从复制对主库的影响

在一次全量复制中,对于主库来说,需要完成两个耗时的操作:生成 RDB 文件和传输 RDB 文件。

如果从库数量很多,而且都要和主库进行全量复制的话,就会导致主库忙于 fork 子进程生成 RDB 文件,进行数据全量同步。fork 这个操作会阻塞主线程处理正常请求,从而导致主库响应应用程序的请求速度变慢。此外,传输 RDB 文件也会占用主库的网络带宽,同样会给主库的资源使用带来压力。那么,有没有好的解决方法可以分担主库压力呢?那就是“主 - 从 - 从”模式。比如把实例2当做实例3的主库。来减轻主库的压力。

4.3 代码实现

以下代码就展示了slaveTryPartialResynchronization函数的基本分支,你可以看到从库会根据主库的回复消息,将slaveTryPartialResynchronization函数的返回值置为不同结果,分别对应了全量复制、增量复制,或是不支持PSYNC

int slaveTryPartialResynchronization(int fd, int read_reply) {
		 …
		 //发送PSYNC命令
		 if (!read_reply) {
					//从库第一次和主库同步时,设置offset为-1
					server.master_initial_offset = -1;
	 …
	//调用sendSynchronousCommand发送PSYNC命令
	reply =
	sendSynchronousCommand(SYNC_CMD_WRITE,fd,"PSYNC",psync_replid,psync_offset,NULL);
		…
		//发送命令后,等待主库响应
		return PSYNC_WAIT_REPLY;
		 }
	
	 //读取主库的响应
	 reply = sendSynchronousCommand(SYNC_CMD_READ,fd,NULL);
	
	//主库返回FULLRESYNC,全量复制
	 if (!strncmp(reply,"+FULLRESYNC",11)) {
	 	…
	 	return PSYNC_FULLRESYNC;
		 }
	
	 //主库返回CONTINUE,执行增量复制
	 if (!strncmp(reply,"+ CONTINUE",11)) {
	…
	return PSYNC_CONTINUE;
		 }
	
	 //主库返回错误信息
	 if (strncmp(reply,"-ERR",4)) {
				 …
	 }
	 return PSYNC_NOT_SUPPORTED;
}

因为slaveTryPartialResynchronization是在syncWithMaster函数中调用的,当该函数返回PSYNC命令不同的结果时,syncWithMaster函数就会根据结果值执行不同处理。

5 增量复制

在 Redis 2.8 之前,如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。

从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。全量复制是同步所有数据,而增量复制只会把主从库网络断连期间主库收到的命令,同步给从库。

增量复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。

5.1 repl_backlog_buffer

增量复制时,主从库之间具体是怎么保持同步的呢?这里的奥妙就在于 repl_backlog_buffer 这个缓冲区

不管在什么时候 master 都会将写指令操作记录在 repl_backlog_buffer 中,因为内存有限, repl_backlog_buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。

刚开始的时候,主库和从库的写读位置在一起,这算是它们的起始位置。随着主库不断接收新的写操作,它在缓冲区中的写位置会逐步偏离起始位置,我们通常用偏移量来衡量这个偏移距离的大小,对主库来说,对应的偏移量就是 master_repl_offset。主库接收的新写操作越多,这个值就会越大。

同样,从库在复制完写操作命令后,它在缓冲区中的读位置也开始逐步偏移刚才的起始位置,此时,从库已复制的偏移量 slave_repl_offset 也在不断增加。正常情况下,这两个偏移量基本相等。

  • master 使用 master_repl_offset记录自己写到的位置偏移量,
  • slave 则使用 slave_repl_offset记录已经读取到的偏移量。
  • master 收到写操作,偏移量则会增加。从库持续执行同步的写指令后,在 repl_backlog_buffer 的已复制的偏移量 slave_repl_offset 也在不断增加。
  • 正常情况下,这两个偏移量基本相等。
  • 在网络断连阶段,主库可能会收到新的写操作命令,所以 master_repl_offset会大于 slave_repl_offset。

当主从断开重连后,slave 会先发送 psync 命令给 master,同时将自己的 runID,slave_repl_offset发送给 master。master 会判断自己的 master_repl_offset 和 slave_repl_offset 之间的差距。然后master只会把 master_repl_offset 和 slave_repl_offset 之间的命令操作同步给从库就行。

增量复制执行流程如下图:

因为 repl_backlog_buffer 是一个环形缓冲区,所以在缓冲区写满后,主库会继续写入,此时,就会覆盖掉之前写入的操作。如果从库的读取速度比较慢,就有可能导致从库还未读取的操作被主库新写的操作覆盖了,这会导致主从库间的数据不一致。

我们要想办法避免这个情况,一旦被覆盖就会执行全量复制。我们可以调整 repl_backlog_size 这个参数用于控制缓冲区大小。计算公式:

repl_backlog_buffer = second * write_size_per_second
  1. second:从服务器断开重连主服务器所需的平均时间;
  2. write_size_per_second:master 平均每秒产生的命令数据量大小(写命令和数据大小总和);

例如,如果主服务器平均每秒产生 1 MB 的写数据,而从服务器断线之后平均要 5 秒才能重新连接上主服务器,那么复制积压缓冲区的大小就不能低于 5 MB。

为了安全起见,可以将复制积压缓冲区的大小设为2 * second * write_size_per_second,这样可以保证绝大部分断线情况都能用部分重同步来处理。

replication buffer 和 repl_backlog
  1. replication buffer 对应于每个 slave,通过 config set client-output-buffer-limit slave设置。
  2. repl_backlog_buffer是一个环形缓冲区,整个 master 进程中只会存在一个,所有的 slave 公用。repl_backlog 的大小通过 repl-backlog-size 参数设置,默认大小是 1M,其大小可以根据每秒产生的命令、(master 执行 rdb bgsave) +( master 发送 rdb 到 slave) + (slave load rdb 文件)时间之和来估算积压缓冲区的大小,repl-backlog-size 值不小于这两者的乘积。

总的来说,replication buffer 是主从库在进行全量复制时,主库上用于和从库连接的客户端的 buffer,而 repl_backlog_buffer 是为了支持从库增量复制,主库上用于持续保存写操作的一块专用 buffer。

repl_backlog_buffer是一块专用 buffer,在 Redis 服务器启动后,开始一直接收写操作命令,这是所有从库共享的。主库和从库会各自记录自己的复制进度,所以,不同的从库在进行恢复时,会把自己的复制进度(slave_repl_offset)发给主库,主库就可以和它进行增量同步。

6 长连接同步

当主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,使用长连接的目的就是避免频繁建立连接导致的开销。

在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING 和 REPLCONF ACK。

主->从:PING

每隔指定的时间,主节点会向从节点发送 PING 命令,这个 PING 命令的作用,主要是为了让从节点进行超时判断。

从->主:REPLCONF ACK

在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:

REPLCONF ACK <replication_offset>

其中 replication_offset 是从服务器当前的复制偏移量。发送 REPLCONF ACK 命令对于主从服务器有三个作用:

  1. 检测主从服务器的网络连接状态。
  2. 辅助实现 min-slaves 选项。
  3. 检测命令丢失, 从节点发送了自身的 slave_replication_offset,主节点会用自己的 master_replication_offset 对比,如果从节点数据缺失,主节点会从 repl_backlog_buffer缓冲区中找到并推送缺失的数据。注意,offset 和 repl_backlog_buffer 缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。

7 如何确定执行全量同步还是部分同步?

在 Redis 2.8 及以后,从节点可以发送 psync 命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制

  1. 从节点根据当前状态,发送 psync命令给 master:

    • 如果从节点从未执行过 replicaof ,则从节点发送 psync ? -1,向主节点发送全量复制请求;
    • 如果从节点之前执行过 replicaof 则发送 psync , runID 是上次复制保存的主节点 runID,offset 是上次复制截至时从节点保存的复制偏移量。
  2. 主节点根据接受到的psync命令和当前服务器状态,决定执行全量复制还是部分复制:

    • runID 与从节点发送的 runID 相同,且从节点发送的 slave_repl_offset之后的数据在 repl_backlog_buffer缓冲区中都存在,则回复 CONTINUE,表示将进行部分复制,从节点等待主节点发送其缺少的数据即可;
    • runID 与从节点发送的 runID 不同,或者从节点发送的 slave_repl_offset 之后的数据已不在主节点的 repl_backlog_buffer缓冲区中 (在队列中被挤出了),则回复从节点 FULLRESYNC ,表示要进行全量复制,其中 runID 表示主节点当前的 runID,offset 表示主节点当前的 offset,从节点保存这两个值,以备使用。

一个从库如果和主库断连时间过长,造成它在主库 repl_backlog_buffer的 slave_repl_offset 位置上的数据已经被覆盖掉了,此时从库和主库间将进行全量复制。

8 主从同步的优缺点

优点:

  1. master能自动将数据同步到slave,可以进行读写分离,分担master的读压力
  2. master、slave之间的同步是以非阻塞的方式进行的,同步期间,客户端仍然可以提交查询或更新请求
  3. 故障恢复:当主节点宕机,其他节点依然可以提供服务;
  4. 负载均衡:Master 节点提供写服务,Slave 节点提供读服务,分担压力;
  5. 高可用基石:是哨兵和 cluster 实施的基础,是高可用的基石。

缺点:

  1. 不具备自动容错与恢复功能,master或slave的宕机都可能导致客户端请求失败,需要等待机器重启或手动切换客户端IP才能恢复。主库挂了,无法执行「写操作」,无法自动选择一个 Slave 切换为 Master,也就是无法故障自动切换。
  2. master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不一致的问题
  3. 难以支持在线扩容,Redis的容量受限于单机配置