摸透 Redis 主从复制、哨兵、Cluster 三种模式

 

概述

Redis作为缓存的高效中间件,在我们日常的开发中被频繁的使用,今天就来说一说Redis的四种模式,分别是「单机版、主从复制、哨兵、以及集群模式」

可能,在一般公司的程序员使用单机版基本都能解决问题,在Redis的官网给出的数据是10W QPS,这对于应付一般的公司绰绰有余了,再不行就来个主从模式,实现读写分离,性能又大大提高。

但是,我们作为有抱负的程序员,仅限于单机版和主从模式的crud是不行的,至少也要了解「哨兵」「集群模式」的原理,这样面试的时候才能和面试官扯皮啊。

之前对于Redis方面也是写了比较多的文章,如:「Redis的基本数据类型和底层的实现原理、事务、持久化、分布式锁、订阅预发布」等,可以说是比较全面的教程了,这篇讲完基本就全了,我会把文章系统的整理成pdf,分享给大家。

先来个整理的Redis大纲,可能还有不完整的地方,若是有不完整的,可以在留言区补充,我后续会加进去。

单机

单机版的Redis就比较简单了,基本90%的程序员都是用过

优点

单机版的Redis也有很多优点,比如实现实现简单、维护简单、部署简单、维护成本非常低,不需要其它额外的开支。

缺点

但是,因为是单机版的Redis所以也存在很多的问题,比如最明显的单点故障问题,一个Redis挂了,所有的请求就会直接打在了DB上。

并且一个Redis抗并发数量也是有限的,同时要兼顾读写两种请求,只要访问量一上来,Redis就受不了了,另一方面单机版的Redis数据量存储也是有限的,数据量一大,再重启Redis的时候,就会非常的慢,所以局限性也是比较大的。

由于,单机版的Redis在并发量比较大的时候,并且需要较高性能和可靠性的时候,单机版基本就不适合了,于是就出现了「主从模式」

主从模式

原理

主从的原理还算是比较简单的,一主多从,「主数据库(master)可以读也可以写(read/write),从数据库仅读(only read)」

但是,主从模式一般实现「读写分离」「主数据库仅写(only write)」,减轻主数据库的压力,下面一张图搞懂主从模式的原理:

主从模式原理就是那么简单,那他执行的过程(工作机制)又是怎么样的呢?再来一张图:

当开启主从模式的时候,他的具体工作机制如下:

  1. 当slave启动后会向master发送SYNC命令,master节点收到从数据库的命令后通过bgsave保存快照(「RDB持久化」),并且期间的执行的些命令会被缓存起来。

  2. 然后master会将保存的快照发送给slave,并且继续缓存期间的写命令。

  3. slave收到主数据库发送过来的快照就会加载到自己的数据库中。

  4. 最后master讲缓存的命令同步给slave,slave收到命令后执行一遍,这样master与slave数据就保持一致了。

优点

之所以运用主从,是因为主从一定程度上解决了单机版并发量大,导致请求延迟或者redis宕机服务停止的问题。

从数据库分担主数据库的读压力,若是主数据库是只写模式,那么实现读写分离,主数据库就没有了读压力了。

另一方面解决了单机版单点故障的问题,若是主数据库挂了,那么从数据库可以随时顶上来,综上来说,主从模式一定程度上提高了系统的可用性和性能,是实现哨兵和集群的基础。

主从同步以异步方式进行同步,期间Redis仍然可以响应客户端提交的查询和更新的请求。

缺点

主从模式好是好,他也有自己的缺点,比如数据的一致性问题,假如主数据库写操作完成,那么他的数据会被复制到从数据库,若是还没有即使复制到从数据库,读请求又来了,此时读取的数据就不是最新的数据。

若是从主同步的过程网络出故障了,导致主从同步失败,也会出现问题数据一致性的问题。

主从模式不具备自动容错和恢复的功能,一旦主数据库,从节点晋升为主数据库的过程需要人为操作,维护的成本就会升高,并且主节点的写能力、存储能力都会受到限制。

实操搭建

安装Redis

$ yum -y install gcc $ yum -y install gcc-c++
$ wget http://download.redis.io/releases/redis-5.0.4.tar.gz 
$ tar -zvxf redis-5.0.4.tar.gz 
$ cd redis-5.0.4 
$ make

这里我们将redis.conf文件复制两份slave.conf和slave2.conf并修改配置

注意:不要用  bind 127.0.0.1,也不要这样配置:bind 127.0.0.1 10.234.1.10 而要用 bind 10.234.1.10 127.0.0.1

# 服务器端口号,主从分别修改为7001 7002 7003 
port 7001 
# 使得Redis可以跨网络访问 
bind 0.0.0.0 
# 配置reids的密码 
requirepass "111111" 
# 下面两个配置只需要配置从节点(slave) 
# 配置主服务器地址、端口号 
replicaof 127.0.0.1 7001 
# 主服务器密码 
masterauth "111111"

分别启动这三个Redis服务

$ ./src/redis-server redis.conf 
$ ./src/redis-server slave.conf 
$ ./src/redis-server slave2.conf

使用redis-cli工具连接redis服务查看主从节点是否搭建成功

$ ./src/redis-cli -h <主机名> -p <端口号> 
$ auth <password> 
$ info replication

看到类似如下所示信息则主从搭建成功

############主节点(master)信息#############
"# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.164,port=7002,state=online,offset=1015511,lag=0
slave1:ip=192.168.1.164,port=7003,state=online,offset=1015511,lag=0
master_replid:ffff866d17e11dcc9a9fd7bf3a487ad9e499fca9
master_replid2:1c8a6f05891dc72bbe4fefd9a54ff65eb46ce35d
master_repl_offset:1015511
second_repl_offset:424773
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:99239
repl_backlog_histlen:916273
"
############从节点(slave)信息#############
"# Replication
role:slave
master_host:192.168.1.164
master_port:7001
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:560709
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:ffff866d17e11dcc9a9fd7bf3a487ad9e499fca9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:560709
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:549628
repl_backlog_histlen:11082

 

哨兵模式

原理

哨兵模式是主从的升级版,因为主从的出现故障后,不会自动恢复,需要人为干预,这就很蛋疼啊。

在主从的基础上,实现哨兵模式就是为了监控主从的运行状况,对主从的健壮进行监控,就好像哨兵一样,只要有异常就发出警告,对异常状况进行处理。

 

所以,总的概括来说,哨兵模式有以下的优点(功能点):

  1. 「监控」:监控master和slave是否正常运行,以及哨兵之间也会相互监控

  2. 「自动故障恢复」:当master出现故障的时候,会自动选举一个slave作为master顶上去。

哨兵模式的监控配置信息,是通过配置数据库的sentinel monitor <master-name> <ip> <redis-port> <quorum> 来指定的,比如:

// mymaster 表示给master数据库定义了一个名字,后面的是master的ip和端口,1表示至少需要一个Sentinel进程同意才能将master判断为失效,如果不满足这个条件,则自动故障转移(failover)不会执行
sentinel monitor mymaster 127.0.0.1 6379 1

节点通信

当哨兵启动后,会与master建立一条连接,用于订阅master的_sentinel_:hello频道。该频道用于获取监控该master的其它哨兵的信息。哨兵定期向_sentinel_:hello频道发送自己的信息,以便其它的哨兵能够订阅获取自己的信息,发送的内容包含「哨兵的ip和端口、运行id、配置版本、master名字、master的ip端口还有master的配置版本」等信息。

哨兵还会与mastter建立一条获取master信息的连接,定时向master发送INFO命令。「当哨兵与master建立连接后,定期会向(10秒一次)master和slave发送INFO命令,若是master被标记为主观下线,频率就会变为1秒一次。」

以及,「定期的向master、slave和其它哨兵发送PING命令(每秒一次),以便检测对象是否存活」,若是对方接收到了PING命令,无故障情况下,会回复PONG命令。

所以,哨兵通过建立这两条连接、通过定期发送INFO、PING命令来实现哨兵与哨兵、哨兵与master之间的通信。

这里涉及到一些概念需要理解,INFO、PING、PONG等命令,后面还会有MEET、FAIL命令,以及主观下线,当然还会有客观下线,这里主要说一下这几个概念的理解:

  1. INFO:该命令可以获取主从数据库的最新信息,可以实现新结点的发现。

  2. PING:该命令被使用最频繁,该命令封装了自身节点和其它节点的状态数据。

  3. PONG:当节点收到MEET和PING,会回复PONG命令,也把自己的状态发送给对方。

  4. MEET:该命令在新结点加入集群的时候,会向老节点发送该命令,表示自己是个新人。

  5. FAIL:当节点下线,会向集群中广播该消息。

上线和下线

当哨兵与master相通之后就会定期一直保持联系,若是某一时刻哨兵发送的PING在指定时间内没有收到回复(sentinel down-after-milliseconds master-name milliseconds 配置),那么发送PING命令的哨兵就会认为该master「主观下线」Subjectively Down)。

因为有可能是哨兵与该master之间的网络问题造成的,而不是master本身的原因,所以哨兵同时会询问其它的哨兵是否也认为该master下线,若是认为该节点下线的哨兵达到一定的数量「前面的quorum字段配置」),就会认为该节点「客观下线」Objectively Down)。

若是没有足够数量的sentinel同意该master下线,则该master客观下线的标识会被移除;若是master重新向哨兵的PING命令回复了客观下线的标识也会被移除。

选举算法

当master被认为客观下线后,又是怎么进行故障恢复的呢?原来哨兵中首先选举出一个老大哨兵来进行故障恢复,选举老大哨兵的算法叫做「Raft算法」

  1. 发现master下线的哨兵(sentinelA)会向其它的哨兵发送命令进行拉票,要求选择自己为哨兵大佬。

  2. 若是目标哨兵没有选择其它的哨兵,就会选择该哨兵(sentinelA)为大佬。

  3. 若是选择sentinelA的哨兵超过半数(半数原则),该大佬非sentinelA莫属。

  4. 如果有多个哨兵同时竞选,并且可能存在票数一致的情况,就会等待下次的一个随机时间再次发起竞选请求,进行新的一轮投票,直到大佬被选出来。

选出大佬哨兵后,大佬哨兵就会对故障进行自动回复,从slave中选出一名slave作为主数据库,选举的规则如下所示:

  1. 所有的slave中slave-priority优先级最高的会被选中。

  2. 若是优先级相同,会选择偏移量最大的,因为偏移量记录着数据的复制的增量,越大表示数据越完整。

  3. 若是以上两者都相同,选择ID最小的。

通过以上的层层筛选最终实现故障恢复,当选的slave晋升为master,其它的slave会向新的master复制数据,若是down掉的master重新上线,会被当作slave角色运行。

优点

哨兵模式是主从模式的升级版,所以在系统层面提高了系统的可用性和性能、稳定性。当master宕机的时候,能够自动进行故障恢复,需不要人为的干预

哨兵与哨兵之间、哨兵与master之间能够进行及时的监控,心跳检测,及时发现系统的问题,这都是弥补了主从的缺点。

缺点

哨兵一主多从的模式同样也会遇到写的瓶颈,已经存储瓶颈,若是master宕机了,故障恢复的时间比较长,写的业务就会受到影响。

增加了哨兵也增加了系统的复杂度,需要同时维护哨兵模式。

实操搭建

新开一台服务器,并按上面的步骤下载安装Redis。

将sentinel.conf文件复制两份为sentinel2.conf、sentinel3.conf,并分别修改配置

# 三个配置文件分别配置不同的端口号
port <端口号>
# 设置为后台启动
daemonize yes
# 主节点的名称(可以自定义,与后面的配置保持一致即可)
# 主机地址
# 端口号
# 数量(2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作)
sentinel monitor mymaster 127.0.0.1 6379 2
# 多长时间没有响应认为主观下线(SDOWN)
sentinel down-after-milliseconds mymaster 60000
# 表示如果15秒后,mysater仍没活过来,则启动failover,从剩下从节点序曲新的主节点
sentinel failover-timeout mymaster 15000
# 指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长
sentinel parallel-syncs mymaster 1

启动三个sentinel

$ ./src/server-sentinel sentinel.conf 
$ ./src/server-sentinel sentinel2.conf 
$ ./src/server-sentinel sentinel3.conf

然后手动关闭主节点的redis服务,并查看两个slave信息是否有一个变成了master。

程序中使用

SpringBoot连接Redis主从集群配置

spring:
  redis:
    sentinel:
      master: mymaster
      nodes: 192.168.1.167:26379,192.168.1.167:26380,192.168.1.167:26381
    host: 192.168.1.164
    port: 7003
    database: 0
    password: <password>

 

Redis集群(Redis-Cluster)

Cluster模式

最后,Cluster是真正的集群模式了,哨兵解决和主从不能自动故障恢复的问题,但是同时也存在难以扩容以及单机存储、读写能力受限的问题,并且集群之前都是一台redis都是全量的数据,这样所有的redis都冗余一份,就会大大消耗内存空间。

集群模式实现了Redis数据的分布式存储,实现数据的分片,每个redis节点存储不同的内容,并且解决了在线的节点收缩(下线)和扩容(上线)问题

集群模式真正意义上实现了系统的高可用和高性能,但是集群同时进一步使系统变得越来越复杂,接下来我们来详细的了解集群的运作原理。

数据分区原理

集群的原理图还是很好理解的,在Redis集群中采用的是虚拟槽分区算法,会把redis集群分成16384 个槽(0 -16383)。

比如:下图所示三个master,会把0 -16383范围的槽可能分成三部分(0-5000)、(5001-11000)、(11001-16383)分别数据三个缓存节点的槽范围。

当客户端请求过来,会首先通过对key进行CRC16 校验并对 16384 取模(CRC16(key)%16383)计算出key所在的槽,然后再到对应的槽上进行取数据或者存数据,这样就实现了数据的访问更新。

之所以进行分槽存储,是将一整堆的数据进行分片,防止单台的redis数据量过大,影响性能的问题。

节点通信

节点之间实现了将数据进行分片存储,那么节点之间又是怎么通信的呢?这个和前面哨兵模式讲的命令基本一样。

首先新上线的节点,会通过 Gossip 协议向老成员发送Meet消息,表示自己是新加入的成员。

老成员收到Meet消息后,在没有故障的情况下会恢复PONG消息,表示欢迎新结点的加入,除了第一次发送Meet消息后,之后都会发送定期PING消息,实现节点之间的通信。

通信的过程中会为每一个通信的节点开通一条tcp通道,之后就是定时任务,不断的向其它节点发送PING消息,这样做的目的就是为了了解节点之间的元数据存储情况,以及健康状况,以便及时发现问题。

数据请求

上面说到了槽信息,在Redis的底层维护了unsigned char myslots[CLUSTER_SLOTS/8] 一个数组存放每个节点的槽信息。因为他是一个二进制数组,只有存储0和1值,如下图所示:

这样数组只表示自己是否存储对应的槽数据,若是1表示存在该数据,0表示不存在该数据,这样查询的效率就会非常的高,类似于布隆过滤器,二进制存储。

比如:集群节点1负责存储0-5000的槽数据,但是此时只有0、1、2存储有数据,其它的槽还没有存数据,所以0、1、2对应的值为1。

并且,每个redis底层还维护了一个clusterNode数组,大小也是16384,用于储存负责对应槽的节点的ip、端口等信息,这样每一个节点就维护了其它节点的元数据信息,便于及时的找到对应的节点。

当新结点加入或者节点收缩,通过PING命令通信,及时的更新自己clusterNode数组中的元数据信息,这样有请求过来也就能及时的找到对应的节点。

有两种其它的情况就是,若是请求过来发现,数据发生了迁移,比如新节点加入,会使旧的缓存节点数据迁移到新结点。

请求过来发现旧节点已经发生了数据迁移并且数据被迁移到新结点,由于每个节点都有clusterNode信息,通过该信息的ip和端口。此时旧节点就会向客户端发一个MOVED 的重定向请求,表示数据已经迁移到新结点上,你要访问这个新结点的ip和端口就能拿到数据,这样就能重新获取到数据。

倘若正在发生数据迁移呢?旧节点就会向客户端发送一个ASK 重定向请求,并返回给客户端迁移的目标节点的ip和端口,这样也能获取到数据。

扩容和收缩

扩容和收缩也就是节点的上线和下线,可能节点发生故障了,故障自动恢复的过程(节点收缩)。

节点的收缩和扩容时,会重新计算每一个节点负责的槽范围,并根据虚拟槽算法,将对应的数据更新到对应的节点。

还有前面的讲的新加入的节点会首先发送Meet消息,详细可以查看前面讲的内容,基本一样的模式。

以及发生故障后,哨兵老大节点的选举,master节点的重新选举,slave怎样晋升为master节点,可以查看前面哨兵模式选举过程。

优点

集群模式是一个无中心的架构模式,将数据进行分片,分布到对应的槽中,每个节点存储不同的数据内容,通过路由能够找到对应的节点负责存储的槽,能够实现高效率的查询。

并且集群模式增加了横向和纵向的扩展能力,实现节点加入和收缩,集群模式是哨兵的升级版,哨兵的优点集群都有。

缺点

缓存的最大问题就是带来数据一致性问题,在平衡数据一致性的问题时,兼顾性能与业务要求,大多数都是以最终一致性的方案进行解决,而不是强一致性

并且集群模式带来节点数量的剧增,一个集群模式最少要6台机,因为要满足半数原则的选举方式,所以也带来了架构的复杂性。

slave只充当冷备,并不能缓解master的读的压力

搭建步骤

Redis5.0之后的版本放弃了 Ruby 的集群方式,改为使用 C 语言编写的redis-cli的方式,使集群的构建方式复杂度大大降低。

下载安装Redis(见主从复制模式的搭建步骤)。

创建6个Redis的配置文件,如下所示:

/usr/local/redis-5.0.4/redis-cluster-conf/7001/redis.conf
/usr/local/redis-5.0.4/redis-cluster-conf/7002/redis.conf
/usr/local/redis-5.0.4/redis-cluster-conf/7003/redis.conf
/usr/local/redis-5.0.4/redis-cluster-conf/7004/redis.conf
/usr/local/redis-5.0.4/redis-cluster-conf/7005/redis.conf
/usr/local/redis-5.0.4/redis-cluster-conf/7006/redis.conf

配置文件内容:

port 7001  # 端口,每个配置文件不同7001-7006
cluster-enabled yes # 启用集群模式
cluster-config-file nodes.conf #节点配置文件
cluster-node-timeout 5000 # 超时时间
appendonly yes # 打开aof持久化
daemonize yes # 后台运行
protected-mode no # 非保护模式
pidfile  /var/run/redis_7001.pid # 根据端口修改

启动6个Redis节点。

./src/redis-server redis-cluster-conf/7001/redis.conf
./src/redis-server redis-cluster-conf/7002/redis.conf
./src/redis-server redis-cluster-conf/7003/redis.conf
./src/redis-server redis-cluster-conf/7004/redis.conf
./src/redis-server redis-cluster-conf/7005/redis.conf
./src/redis-server redis-cluster-conf/7006/redis.conf

此时启动的6个Redis服务是相互独立运行的,通过以下命令配置集群。

./src/redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006

配置完看到如下图所示信息表示集群搭建成功:

从图中可以看到启动了3个master节点,3个slave节点,16384个槽点平均分配到了3个master节点上。图中很长的一串字母数字的组合(07000b3a90......)为节点的ID。后面对节点的操作中会用到。

集群重新分片

如果对默认的平均分配不满意,我们可以对集群进行重新分片。执行如下命令,只需要指定集群中的其中一个节点地址即可,它会自动找到集群中的其他节点。(如果设置了密码则需要加上 -a <password>,没有密码则不需要,后面的命令我会省略这个,设置了密码的自己加上就好)。

./src/redis-cli -a <password> --cluster reshard 127.0.0.1:7001

输入你想重新分配的哈希槽数量

How many slots do you want to move (from 1 to 16384)?

输入你想接收这些哈希槽的节点ID

What is the receiving node ID?

输入想从哪个节点移动槽点,选择all表示所有其他节点,也可以依次输入节点ID,以done结束。

Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:

输入yes执行重新分片

Do you want to proceed with the proposed reshard plan (yes/no)?

自动故障转移

当运行中的master节点挂掉了,集群会在该master节点的slave节点中选出一个作为新的master节点。这里不做演示。

手动故障转移

有的时候在主节点没有任何问题的情况下强制手动故障转移也是很有必要的,比如想要升级主节点的Redis进程,我们可以通过故障转移将其转为slave再进行升级操作来避免对集群的可用性造成很大的影响。

Redis集群使用 cluster failover 命令来进行故障转移,不过要在被转移的主节点的从节点上执行该命令(使用redis-cli连接slave节点并执行 cluster failover命令进行转移)。

添加一个主节点

按之前的方式再复制一份配置文件,并修改配置

/usr/local/redis-5.0.4/redis-cluster-conf/7007/redis.conf

然后启动该Redis服务,执行以下命令将该节点添加到集群中去

./src/redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001

第一个参数为新增加的节点的IP和端口,第二个参数为任意一个已经存在的节点的IP和端口。

此时该新节点已经成为集群的一份子

127.0.0.1:7007> cluster nodes
90c78386c39c8258435b5b61f49a623b358ec8a6 127.0.0.1:7007@17007 myself,master - 0 1553239975877 10 connected
c4180e02149e2d853a80683433773ef4bceffc78 127.0.0.1:7001@17001 master - 0 1553240017595 11 connected 0-5544 10923-11004
b6584514edbf57331a65f367304f33ad1bd0903e 192.168.1.164:7005@17005 slave 3bdbc4ac0d5902dcf8a5ebbfb88db8fad224c066 0 1553240016992 2 connected
07000b3a905df0ab0c86361adcb2774a487ce650 192.168.1.164:7004@17004 slave c4180e02149e2d853a80683433773ef4bceffc78 0 1553240016000 11 connected
28fa7bbf6b2a46991c7a5fe8eec53db1a5f1e9f6 192.168.1.164:7003@17003 master - 0 1553240017595 3 connected 11005-16383
3bdbc4ac0d5902dcf8a5ebbfb88db8fad224c066 192.168.1.164:7002@17002 master - 0 1553240017000 2 connected 5545-10922
fd9cba359d94ba6c9beecc91fbd491f9cf7a39ca 192.168.1.164:7006@17006 slave 28fa7bbf6b2a46991c7a5fe8eec53db1a5f1e9f6 0 1553240016000 3 connected

但是该节点没有包含任何的哈希槽,所以没有数据会存到该主节点。我们可以通过上面的集群重新分片给该节点分配哈希槽,那么该节点就成为了一个真正的主节点了。

添加一个从节点

跟添加主节点一样添加一个节点7008,然后连接上该节点并执行如下命令

cluster replicate <nodeId>

这样就可以指定该节点成为哪个节点的从节点。

节点的移除

可以使用如下命令来移除节点

./src/redis-cli --cluster del-node 127.0.0.1:7001 <nodeId>

第一个参数是任意一个节点的地址,第二个参数是你想要移除的节点ID。如果是移除主节点,需要确保这个节点是空的,如果不是空的则需要将这个节点上的数据重新分配到其他节点上。

程序中使用

SpringBoot中连接Redis集群配置

spring:
  redis:
    cluster:
      nodes: 192.168.1.164:7001,192.168.1.164:7002,192.168.1.164:7003,192.168.1.164:7004,192.168.1.164:7005,192.168.1.164:7006
    database: 0
    password: <password>

Redis常见数据丢失情况分析及解决

情况分析

(1)异步复制导致的数据丢失

因为master->slave的数据同步是异步的,所以可能存在部分数据还没有同步到slave,master就宕机了,此时这部分数据就丢失了。

(2)脑裂导致的数据丢失

当master所在的机器突然脱离的正常的网络,与其他slave、sentinel失去了连接,但是master还在运行着。此时sentinel就会认为master宕机了,会开始选举把slave提升为新的master,这个时候集群中就会出现两个master,也就是所谓的脑裂

此时虽然产生了新的master节点,但是客户端可能还没来得及切换到新的master,会继续向旧的master写入数据。

当网络恢复正常时,旧的master会变成新的master的从节点,自己的数据会清空,重新从新的master上复制数据。

解决方案

Redis提供了这两个配置用来降低数据丢失的可能性

min-slaves-to-write 1 
min-slaves-max-lag 10

上面两行配置的意思是,要求至少有1个slave,数据复制和同步的延迟不能超过10秒,如果不符合这个条件,那么master将不会接收任何请求。

(1)减少异步复制的数据丢失

有了min-slaves-max-lag这个配置,就可以确保,一旦slave复制数据和ack延时太长,就认为master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低到可控范围内。

(2)减少脑裂的数据丢失

如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求

这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失。

Redis并不能保证数据的强一致性,看官方文档的说明

 

参考文档:

http://www.redis.cn/topics/cluster-tutorial.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值