redis专题:redis的主从、哨兵、集群架构的配置和部署详情、以及问题分析


1. 在linux下安装redis

下载地址:http://redis.io/download
安装步骤:
# 安装gcc
yum install gcc

# 把下载好的redis-5.0.3.tar.gz放在/usr/local文件夹下(可以使用Xftp传输)
wget http://download.redis.io/releases/redis-5.0.3.tar.gz

# 解压
tar xzf redis-5.0.3.tar.gz
cd redis-5.0.3

# 进入到解压好的redis-5.0.3目录下,进行编译与安装
make

# 修改配置
daemonize yes  #后台启动
protected-mode no  #关闭保护模式,开启的话,只有本机才可以访问redis
# 需要注释掉bind,如果开启只能通过自己服务器连接redis,多个redis之间无法连接,无法通信
#bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)
protected-mode no  #设置Redis可远程访问

# 启动服务
src/redis-server redis.conf

# 验证启动是否成功 
ps -ef | grep redis 

# 进入redis客户端 
src/redis-cli 

# 退出客户端
quit

# 退出redis服务: 
(1)pkill redis-server 
(2)kill 进程号                       
(3)src/redis-cli shutdown

如果使用make命令编译redis失败,出现
“没有名为‘xxx’的成员”
“警告:在有返回值的函数中,控制流程到达函数尾”等情况时,可能是gcc版本过低,具体请看此链接
解决make编译redis失败的方式


2. redis主从架构

redis主从架构可以配置一主一从、一主多从等结构,主要是从主节点读写数据,从节点多用于备份数据!
在这里插入图片描述

2.1 redis主从架构搭建步骤

1、复制一份redis.conf文件

2、将相关配置修改为如下值:
port 6380
pidfile /var/run/redis_6380.pid  # 把pid进程号写入pidfile配置的文件
logfile "6380.log"
dir /usr/local/redis-5.0.3/data/6380  # 指定数据存放目录
# 需要注释掉bind
# bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)

3、配置主从复制
replicaof 192.168.0.60 6379   # 从本机6379的redis实例复制数据,Redis 5.0之前使用slaveof
replica-read-only yes  # 配置从节点只读

4、启动从节点
redis-server redis.conf

5、连接从节点
redis-cli -p 6380

6、测试在6379实例上写数据,6380实例是否能及时同步新修改数据

2.2 redis主从架构数据同步原理

如果为reids配置了主从架构,那么从服务器启动时是怎么从主服务器中同步数据的呢?具体的流程图如下:
在这里插入图片描述

  • ①:从服务器slave先于主服务器master建立socket长连接
  • ②:从服务器slave向主服务器master发送一个PSYNC命令,请求复制数据。
  • ③:主服务器master接收到PSYNC命令后,会通过bgsave命令利用子线程生成最新的rdb快照文件,并发送给从服务器slave。持久化期间,master会继续接收客户端的请求,它会把这些可能修改数据集的请求缓存在内存repl buffer中
  • ④:slave清掉无用数据,并接受master传来的数据加载到内存中
  • ⑤:master再将之前持久化时缓存在内存中的命令发送给slave。
  • ⑥:slave接受master发过来的新命令并执行
  • ⑦:此时数据已同步完毕,当master再有新的写操作,会通过socket长连接持续的发给slave,保证主从数据一致性!

注意: 如果master收到了多个slave并发连接请求,它只会进行一次持久化,而不是一个连接一次,然后再把这一份持久化的数据发送给多个并发连接的slave。


2.3 如果在主从传输过程中,从节点挂了怎么办?

当salve因为网络等原因接收到一半数据时挂掉了,经过一段时间后,人为的重启了salve从节点,那么此时的数据传输是怎么处理呢?

       答:从redis2.8版本开始,redis改用可以支持部分数据复制的命令PSYNC去master同步数据,slave与master能够在网络连接断开重连后只进行部分数据复制(断点续传)。流程图如下:

在这里插入图片描述

  • ①:首先redis在运行时会默认开启一个缓存池,用于缓存最近的redis命令,可以在redis.config中配置
    # repl-backlog-size 1mb		redis命令缓存池,默认大小为1Mb
    
  • ②:当slave与master断开并重新建立连接时,slave会向master发送PSYNC命令,并通过offset偏移量定位到断开连接时传输数据的位置,从这个位置开始进行断点续传
  • ③:如果slave节点断开时间太久,导致偏移量太旧,已经在master中的命令缓存池中找不到对应的位置,那么就会进行一次全量数据的复制。无法使用断点续传了!


2.4 什么是主从复制风暴?

主从复制风暴:多个从节点同时复制主节点导致主节点压力过大
为了解决主从复制风暴问题,可以让部分从节点与从节点同步数据,架构如下设计:
在这里插入图片描述


3. redis哨兵高可用架构

        sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点的状态!

        哨兵架构下client端第一次请求redis服务时,会通过哨兵找出redis的主节点,后续就直接访问redis的主节点不会每次都通过sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis主节点通知给client端(这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)
在这里插入图片描述


3.1 redis哨兵架构搭建步骤

1、复制一份sentinel.conf文件
cp sentinel.conf sentinel-26379.conf

2、将相关配置修改为如下值:
port 26379
daemonize yes
pidfile "/var/run/redis-sentinel-26379.pid"
logfile "26379.log"
dir /usr/local/redis-5.0.3/data

# sentinel monitor <master-redis-name> <master-redis-ip> <master-redis-port> <quorum>
# quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效
# 推荐哨兵设为最少3个
# mymaster这个名字随便取,客户端访问时会用到
sentinel monitor mymaster 192.168.0.60 6379 2   

3、启动sentinel哨兵实例
src/redis-sentinel sentinel-26379.conf

4、查看sentinel的info信息
src/redis-cli -p 26379
127.0.0.1:26379>info
可以看到Sentinel的info里已经识别出了redis的主从

5、可以自己再配置两个sentinel,端口2638026381


注意:每个哨兵sentinel中的唯一标志myid一定不能一样,如果一样则只代表一个哨兵。删掉启动时会自动生成

创建完成后可以进入监听的master客户端,使用info命令查看哨兵、从服务器配置情况

Info:查看redis服务运行信息,分为 9 大块,每个块都有非常多的参数,这 9 块分别是:

Server 服务器运行的环境参数 
Clients 客户端相关信息 
Memory 服务器运行内存统计数据 
Persistence 持久化信息 
Stats 通用统计数据 
Replication 主从复制相关信息 
CPU CPU 使用情况 
Cluster 集群信息 
KeySpace 键值对统计数量信息

当哨兵启动完成,会往sentinel-xxx.conf配置文件的底部增添一些master的从节点信息,如下所示,如果有这些说明哨兵搭建成功!
在这里插入图片描述


3.2 哨兵的主要作用

        现象: 当master节点挂掉后,服务端控制台会打印 连接超时错误,当过一段时间后,又恢复正常,可以继续向redis中写入数据!

        原因: 原因就是哨兵会时刻监视着master节点,当master节点挂掉,此时服务端控制台会打印连接超时错误。但同时哨兵经过半数机制确认master挂掉,会选举出一个slave作为新的master(默认3分钟),选举的这顿时间内,控制台还是会打印错误,一旦选举成功,就会通知client并恢复正常连接,这也是出现以上现象的原因!!当原来挂掉的master节点重新恢复时,将自动称为新的master的丛节点,完成哨兵高可用架构!

注意: 当master节点挂掉,哨兵选举新节点的这个时间内,整个redis架构会挂掉,无法对外提供服务!


3.3 哨兵leader选举流程

        当一个master服务器被某sentinel视为下线状态后,哨兵会选举出一个新的master,大概流程如下:

  • ①:哨兵先与其他哨兵协商,选出一个哨兵leader。如果所有超过一半的sentinel选举某哨兵A作为leader,那这个哨兵A就是leader。如果只有一个哨兵,自己就是leader
  • ②:之后该哨兵leader从存活的slave中选举出新的master

为了高可用一般都推荐至少部署三个哨兵节点,且节点数为基数,这样做的原理和redis集群类似


4. redis集群高可用架构

        在redis3.0以前的版本要实现集群一般是借助哨兵sentinel来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master。这种方式足以应对一般的QPS,但在面对很高并发的场景时,也会存在以下几个缺点:

  • ①:主从切换瞬间会存在访问访问瞬断的情况,此时redis无法对外提供服务
  • ②:哨兵模式只有一个主节点对外提供服务,没法支持很高的并发(单台redis最高大概10w左右)
  • ③:单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率,引发主从复制风暴!

总之,在高并发场景下哨兵架构的配置略微复杂,并且性能和高可用性等各方面表现一般。为了应对这个问题,redis3.0以后引入了redis集群架构,redis集群架构如下:

在这里插入图片描述

        redis集群是一个由多个主从节点群 组成的分布式服务器群,它具有复制、高可用和数据分片存储特性。redis集群包含哨兵的功能,所以不需要配置哨兵也可以完成半数选举新节点的功能!

        redis集群在处理数据时是分片存储 且 没有中心节点,故可水平扩展,可根据实际场景(双11和平时)进行服务器动态扩容缩容,官方推荐不超过1000个节点。redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单!


4.1 redis高可用集群搭建

集群搭建步骤如下,可以单机搭建,也可多台服务器搭建

第一步:在第一台机器的/usr/local下创建文件夹redis-cluster,然后在其下面分别创建2个文件夾如下
(1)mkdir -p /usr/local/redis-cluster
(2)mkdir 8001 8004

第一步:把之前的redis.conf配置文件copy到8001下,修改如下内容:
(1)daemonize yes
(2)port 8001(分别对每个机器的端口号进行设置)
(3)pidfile /var/run/redis_8001.pid  # 把pid进程号写入pidfile配置的文件
(4)dir /usr/local/redis-cluster/8001/(指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据)
	//5、6、7步是针对集群的操作5)cluster-enabled yes(启动集群模式)
(6)cluster-config-file nodes-8001.conf(集群节点信息文件,相当于cluster nodes命令查看节点信息,这里800x最好和port对应上)
(7)cluster-node-timeout 10000

 (8)# bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)
 (9)protected-mode  no   (关闭保护模式)
 (10)appendonly yes		 (开启Aof持久化)
如果要设置密码需要增加如下配置:
 (11)requirepass zhuge     (设置redis访问密码)
 (12)masterauth zhuge      (设置集群节点间访问密码,跟上面一致)

第三步:把修改后的配置文件,copy到8004,修改第2346项里的端口号,可以用批量替换:
:%s/源字符串/目的字符串/g 

第四步:另外两台机器也需要做上面几步操作,第二台机器用80028005,第三台机器用80038006

第五步:分别启动6个redis实例,然后检查是否启动成功
(1/usr/local/redis-5.0.3/src/redis-server /usr/local/redis-cluster/800*/redis.conf
(2)ps -ef | grep redis 查看是否启动成功
    
第六步:用redis-cli创建整个redis集群(redis5以前的版本集群是依靠ruby脚本redis-trib.rb实现)
# 下面命令里的1代表为每个创建的主服务器节点创建一个从服务器节点
# 执行这条命令需要确认三台机器之间的redis实例要能相互访问,
# 可以先简单把所有机器防火墙关掉,如果不关闭防火墙则需要打开redis服务端口和集群节点gossip通信端口16379(默认是在redis端口号上加1W)
# 关闭防火墙
# systemctl stop firewalld # 临时关闭防火墙
# systemctl disable firewalld # 禁止开机启动
(1/usr/local/redis-5.0.3/src/redis-cli -a zhuge
 --cluster create --cluster-replicas 1 192.168.0.61:8001 192.168.0.62:8002 192.168.0.63:8003 192.168.0.61:8004 192.168.0.62:8005 192.168.0.63:8006 

第七步:验证集群:
(1)连接任意一个客户端即可:./redis-cli -c -h -p (-a访问服务端密码,-c表示集群模式,指定ip地址和端口号)
    如:/usr/local/redis-5.0.3/src/redis-cli -a zhuge -c -h 192.168.0.61 -p 800*2)进行验证: cluster info(查看集群信息)、cluster nodes(查看节点列表)
(3)进行数据操作验证
(4)关闭集群则需要逐个进行关闭,使用命令:
/usr/local/redis-5.0.3/src/redis-cli -a zhuge -c -h 192.168.0.60 -p 800* shutdown

 
问题一: 如何创建集群?

在这里采用一台机器部署redis集群的方式,分别启动8001、8002、8003、8004、8005、8006端口的redis后,结果如下:

在这里插入图片描述
此时要组成集群的6个redis节点已启动成功,但他们之间还没有任何关系,通过客户端命令可以为他们组建集群关系,下面的组建集群关系命令只在redis5.0以后有用,redis5.0之前的是依靠ruby脚本redis-trib.rb实现的!!

# --cluster create  		创建集群关系
# --cluster-replicas 1		每一个集群主节点配置一个从节点
redis-6.0.9/src/redis-cli  --cluster create  --cluster-replicas 1 192.168.100.100:8001 192.168.100.100:8002 192.168.100.100:8003 192.168.100.100:8004 192.168.100.100:8005 192.168.100.100:8006 

        输入命令后,会为每个集群节点分配槽位!那为什么会有槽位分配呢?

        因为redis集群的数据是分片(分槽位slot)来存储的,所以每个集群节点在建立集群关系时,会分到不同区间的槽位,一共16384个槽位供数据存储!

        在集群模式下,当操作redis客户端存储数据时,数据的key会与16384进行%运算,运算结果决定存储在哪个槽位上,这个槽位又被分配在redis集群中的某个master节点上,所以要存储的数据也就存储在这个master节点上!

分配槽位详情如下:
在这里插入图片描述
然后确定槽位分配,集群关系组建成功的标志如下:

在这里插入图片描述

连接任意一个客户端进行验证:

# -c 代表集群模式
 src/redis-cli -c -h 192.168.100.100 -p 8001  	

进入8001的客户端,在客户端中使用cluster info命令查看集群信息
在这里插入图片描述

在客户端中使用cluster nodes命令查看集群信息如下:
三主三从,每一台服务器对应一个唯一id,通过观察从服务器依赖的id,可以知道从服务器依赖于哪一台master!

在这里插入图片描述

问题二:集群关闭后,如何重新启动?

        如果要重启集群,千万不要使用上边的创建集群命令!!只需要把之前已经搭建好的6个集群节点使用 redis-server config 的方式逐一启动即可! 启动完成后,他们会自动建立集群关系!

因为我们之前在节点的配置文件中配置了节点信息存储目录,节点启动时会自动去该目录下找到并根据该配置建立集群关系

cluster-config-file nodes-8001.conf(集群节点信息文件,相当于cluster nodes命令查看节点信息,这里800x最好和port对应上)

8001的节点信息nodes-8001.conf配置如下,可以看到和上边的cluster nodes命令结果一样!
在这里插入图片描述
 
问题三:如果集群中的某个master节点挂掉,整个集群还可用吗?

redis集群默认一个master节点挂掉,整个集群不可用,但是可以修改配置文件使集群可用

注意:

# 为no表示当负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用
# 为yes则不可用
cluster-require-full-coverage = no

 
问题四: redis集群为什么至少需要三个master节点,并且推荐节点数为奇数?
        因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中一个挂了,是达不到选举新master的条件的。

        奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相比,大家如果都挂了一个master节点都能选举新master节点,如果都挂了两个master节点都没法选举新master节点了(因为选举需要大于2票,就剩余两个master,最大=2),所以奇数的master节点更多的是从节省机器资源角度出发说的。

 
问题五:redis集群支持批量操作命令吗?
        如果直接使用mset,mget这样的多个key的原生批量操作命令,会执行失败,因为redis集群只支持所有key落在同一槽位slot的情况,多个key可能落在不同的槽位slot中!

        如果有多个key一定要用mset命令在redis集群上操作,则可以在key的前面加上{XX},这样参数数据分片hash计算的只会是大括号里的值,这样能确保不同的key能落到同一slot里去,示例如下:

mset {user1}:1:name zhuge {user1}:1:age 18

假设name和age计算的hash slot值不一样,但是这条命令在集群下执行,redis只会用大括号里的 user1 做hash slot计算,所以算出来的slot值肯定相同,最后都能落在同一槽位slot中!


4.2 redis集群的槽位存储原理

        Redis Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。在Springboot项目中,当 Redis Cluster 的客户端(jedis、redistemplate等) 来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在本地。这样当客户端要查找某个 key 时,通过槽位定位算法可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况(比如集群数据迁移、集群扩容缩容等),还需要纠正机制来实现槽位信息的校验调整。

        
槽位定位算法

        redis集群默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。核心算法如下:HASH_SLOT = CRC16(key) mod 16384

        
跳转重定位

当时用redis客户端命令set向redis存储k-v值时

  • ①:如果当前key根据槽位定位算法算得槽位在当前master节点的槽位区间内,则把数据存储在当前master节点中
    在这里插入图片描述
  • ②:如果发生集群数据迁移、集群扩容等操作,本地缓存还未来得及修改槽位信息!那么当前key经过槽位定位算法算得槽位可能不在当前master节点的槽位区间内,这时它会向客户端发送一个特殊的跳转指令,这个指令携带了能匹配当前key的槽位值的节点地址,告诉客户端去这个节点操作数据。客户端收到指令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有 key 将使用新的槽位映射表。
    在这里插入图片描述


4.2 redis集群节点之间的通信机制

        redis集群中一个节点挂掉后,别的节点可以及时感知到,并选举出新的节点,这其中就依赖于节点之间的通信机制!维护集群的元数据通信方式大概有两种:集中式和gossip 。redis cluster节点间采取gossip协议进行通信! 两种通信方式介绍如下:

集中式:

  1. 优点:元数据的更新和读取,时效性非常好,一旦元数据出现变更立即就会更新到集中式的存储中,其他节点读取的时候立即就可以立即感知到
  2. 缺点:所有的元数据的更新压力全部集中在一个地方,可能导致元数据的存储压力

zookeeper就是借助集中式来哦存储数据信息!

gossip:

  1. 优点:元数据的更新比较分散,不是集中在一个地方,节点更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,具有最终一致性!但不会有元数据的集中存储,降低了存储压力!
  2. 缺点:元数据更新有延时可能导致集群的一些操作会有一些滞后。所以不推荐集群节点个数太多!

每个节点都有一个专门用于节点间gossip通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信的就是17001端口。
在这里插入图片描述
gossip协议包含多种消息,包括ping,pong,meet,fail等等。

  • meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通 信;
  • ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过 ping交换元数据(类似自己感知到的集群节点增加和移除,hash slot信息等);
  • pong: 对ping和meet消息的返回,包含自己的状态和其他信息,也可以用于信息广播和更新;
  • fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。

通信超时时间设置

        机房网络往往并不是风平浪静的,比如网络波动就是非常常见的一种现象,突然之间部分连接变得不可访问,然后很快又恢复正常。如果集群节点的通信因为网络波动而认为有节点挂掉,进而触发选举机制,那么网络波动结束后,旧的master节点恢复了连接,然而又选举出了一个新的master节点!两个master节点同时对外提供服务,就会出现脑裂问题。

        为了防止因网络波动产生脑裂,Redis Cluster 提供了一种选项cluster-node-timeout 设置连接超时时间,表示当某个节点持续 timeout 的时间失联时,才可以认定该节点出现故障,需要进行主从切换。如果没有这个选项,网络抖动会导致主从频繁切换 (数据的重新复制)。


4.3 redis集群选举原理

        当slave发现自己的master变为FAIL状态时,并不是马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在集群中传播完毕,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票。延迟之后slave便尝试成为新的master。

延迟计算公式:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms

说明:SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举(理论上)。

由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:

  • ①:slave发现自己的master变为FAIL
  • ②:将记录集群选举次数currentEpoch加1,并向其他节点广播,发送信息为自己拉票
  • ③:其他节点收到该信息,只有master响应,判断请求者的合法性,并返回FAILOVER_AUTH_ACK,对每一个slave的请求只发送一次ack
  • ④:尝试成为新的master的slave收集到其他master返回的FAILOVER_AUTH_ACK
  • ⑤:slave收到超过半数master的ack后变成新Master (这里解释了集群为什么至少需要三个主节点,如果只有两个,当其中一个挂了,只剩一个主节点是不能选举成功的)
  • ⑥:slave广播Pong消息通知其他集群节点自己已成为新的master!
  • ⑦:当旧的master复活后,会变成新的master的从节点

如果多个slave第一次竞选票数一样,则会把集群选举次数currentEpoch加1,再次执行上面的步骤进行选举!


4.4 redis的脑裂问题

redis的脑裂问题在哨兵模式和集群模式都可能存在:

哨兵模式的脑裂:

在这里插入图片描述

        如上图,1个master与3个slave组成的哨兵模式(哨兵独立部署于其它机器),刚开始时,2个应用服务器server1、server2都连接在master上,视为正常情况。

        如果masterslave及哨兵sentinel之间的网络发生故障,但是哨兵与slave之间通讯正常,这时3个slave其中1个经过哨兵投票后,提升为新master,如果恰好此时server1仍然连接的是旧的master,而server2连接到了新的master上。数据就不一致了,基于setNX指令的分布式锁,可能会拿到相同的锁;基于incr生成的全局唯一id,也可能出现重复。

集群模式的脑裂:

        上文说到为防止网络波动产生脑裂问题,可以配置cluster-node-timeout 设置连接超时时间来预防。但是当连接时间超出cluster-node-timeout设置的值,还是会选举出新的master节点,此时旧的master节点如果恢复连接,还是会因为存在多个master节点对外提供服务而产生脑裂!!

        生产环境下,由于redis master节点和redis salve节点处于不同的网络分区,当网络分区恢复(ping通)之前,有两个master节点对外提供服务,在提供服务期间:可能会存在数据不一致问题:

  • 基于setNX指令的分布式锁,可能会拿到相同的锁
  • 基于incr指令生成的全局唯一id,也可能出现重复

        当网络分区恢复之后,redis会把旧的master节点变为新的master节点的slave节点,并同步新的master节点的数据。但同时会带来一个新的问题,旧节点上的数据会被删除,如果它在作为master对外提供服务的时间内,处理了很多命令,那么被删除的话就会丢失一部分数据!具体过程如下图所示:

正常状态:
在这里插入图片描述
网络发生中断:如果此时master服务器所在区域网络通信出现异常,导致和两台slave机器无法正常通信,但是和客户端的连接是正常的。那么sentinel就会从两台slave机器中选举其中一个作为新的master来处理客户端请求。如图

在这里插入图片描述
网络恢复后: 旧master节点变为新master节点的从节点,旧master上的数据会被删除。在网络发生中断期间,旧master从客户端接收到的数据全部丢失!
在这里插入图片描述

脑裂问题的解决方案

可以在redis配置里加上参数(这种方法不可能百分百避免数据丢失):

# 写数据成功最少同步的slave数量
# 这个数量可以模仿大于半数机制配置,比如集群总共三个节点可以配置1,加上leader就是2,超过了半数
min-slaves-to-write 1  

# 主从数据同步超时时间,10秒。
min-slaves-max-lag 10

        根据以上配置可以将master通信异常期间的数据丢失控制在10秒以内,但同时在一定程度上会影响集群的可用性,比如slave要是少于1个,这个集群就算leader正常也不能提供服务了,需要具体场景权衡选择。


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值