Redis持久化、主从复制、集群

Redis持久化

        Redis是内存数据库,宕机后内存中的数据会消失,Redis重启后为了快速恢复数据,要提供持久化机制。

        Redis提供了两种主要的持久化机制:RDB持久化AOF持久化。此外,还可以采用混合持久化(RDB + AOF)的方式,将这两种持久化方式结合在一起。

RDB持久化

        RDB(Redis DataBase)持久化是redis默认的存储方式,是一种基于快照的持久化方式。它把当前时刻全量数据持久化到磁盘上,最终生成一个RBD文件。

RDB持久化配置

        在redis.conf文件中,配置

# 在900s内至少有一次写操作时,会自动触发bgsave持久化
save 900 1
# 300s内至少有1次写操作
save 300 10
# 60s内至少有10000次写操作
save 60 10000

        触发持久化后,会自动生成dump.rdb文件,其内容如下:

RDB持久化触发方式

        RDB持久化可以通过以下几种方式触发:

  • 手动触发:使用savebgsave命令进行持久化。save是同步命令,会阻塞当前 Redis 服务器响应其他命令,直到 RDB 快照生成完成为止。bgsave是异步命令,主进程会forks一个子进程,进行异步持久化,持久化过程中主进程仍然可以处理其他请求。
  • 自动触发:在配置中配置了 save 相关配置信息,如上面配置文件中的 save m n, 表示 m 秒内数据集存在 n 次修改时,会自动触发 bgsave。
  • 自动触发:Redis在关闭服务时会自动触发save操作,进行一次RDB持久化。
  • 自动触发:当从节点连接到主节点时,主节点自动执行 bgsave 生成 RDB 文件并发送给从节点。

        可以看出,save命令触发的持久化比较少,大多数情况下使用的都是bgsave命令。下面是bgsave命令的流程图:

  • 执行 bgsave 命令,Redis 主进程判断当前是否存在正在执行的 RDB/AOF子进程,如果存在, bgsave 命令直接返回不在往下执行。
  • 父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞,fork 完成后父进程将不在阻塞可以接受其他命令。
  • 子进程创建新的 RDB 文件,基于父进程当前内存数据生成临时快照文件,完成后用新的 RDB 文件替换原有的 RDB 文件,并且给父进程发送 RDB 快照生成完毕通知。

RDB持久化的优缺点

        RDB持久化优点:

  • 高性能:由于采用子进程进行磁盘操作,主进程无需进行磁盘IO,保证了Redis的高性能。
  • 快速恢复:RDB文件包含了某一时刻的完整数据快照,可以快速恢复数据。
  • 更小的存储空间:RDB文件经过压缩,占用较小的磁盘空间。

        RDB持久化缺点:

  • 数据丢失:由于RDB持久化是基于时间间隔的,可能存在一定程度的数据丢失。
  • 子进程占用内存:在生成RDB文件过程中,子进程会占用和主进程相同的内存空间,可能导致内存不足的问题。

AOF持久化

        AOF(Append Only File)持久化是一种基于日志的持久化方式。Redis将所有的写操作命令追加到一个AOF文件中。当Redis重新启动时,可以通过重放AOF文件中的命令来恢复数据。

AOF持久化配置

        Redis 默认并没有开启 AOF 持久化方式,需要我们自行开启,启用AOF持久化:在配置文件中设置appendonly yes。启用AOF持久化后,会生成持久化文件appendonly.aof,里面保存序列化后的redis命令。

# 开启aof持久化
appendonly yes

# aof文件名
appendfilename "appendonly.aof"

        AOF文件同步策略:在配置文件中设置**appendfsync**选项。可选值包括:

always:每次写操作都同步到磁盘,保证最高的数据安全性,但性能较差。

everysec:每秒同步一次磁盘,提供较好的数据安全性和性能平衡。

no:由操作系统决定何时同步磁盘,性能最好,但数据安全性较差。

# 持久化策略,always表示每次写入都进行持久化
appendfsync always

        AOF重写策略:在redis.conf文件中进行配置,控制AOF重写的触发条件

# 指定在执行BGSAVE或BGREWRITEAOF命令时是否禁用AOF文件同步。默认为yes,表示禁用同步。
no-appendfsync-on-rewrite yes

# 定AOF文件大小增长到原始大小的百分比时进行重写。
# 默认为100,表示AOF文件大小增长到原始大小的两倍时进行重写。
auto-aof-rewrite-percentage 100

# 指定进行AOF重写的最小AOF文件大小。默认为64mb。
auto-aof-rewrite-min-size 64

AOF持久化过程

        下面时是AOF 持久化流程图:

        持久化文件appendonly.aof的部分内容如下:

*2
$6
SELECT
$2
10
*4
$4
ZADD
$24
aesd.mkc.media.heartbeat
$17
1.687770021851E12
$38
"f9c0a148-f80a-4f80-8f9d-07bf603be46d"

1、 为什么要将命令写入到 aof_buf 缓存区而不是直接写入到 aof 文件?

        我们知道 Redis 是单线程响应,如果每次写入 AOF 命令都直接追加到磁盘上的 AOF 文件中,这样频繁的 IO 开销,Redis 的性能就完成取决于你的机器硬件了,为了提升 Redis 的响应效率就添加了一层 aof_buf 缓存层, 利用的是操作系统的 cache 技术,这样就提升了 Redis 的性能,虽然这样性能是解决了,但是同时也引入了一个问题,aof_buf 缓存区数据如何同步到 AOF 文件呢?由谁同步呢?这就是我们接下来要聊的一个操作:「fsync 操作」

2、aof_buf 缓存区数据如何同步到 aof 文件中?

        aof_buf 缓存区数据写入到 aof 文件是由linux 系统去完成的,由于 Linux 系统调度机制周期比较长,如果系统故障宕机了,意味着一个周期内的数据将全部丢失,所以 Linux 提供了一个 fsync 命令,fsync 是针对单个文件操作(比如这里的 AOF 文件),做强制硬盘同步,fsync 将阻塞直到写入硬盘完成后返回,保证了数据持久化,正是由于有这个命令,所以 redis 提供了配置项让我们自行决定何时进行磁盘同步,redis 在 redis.conf 中提供了appendfsync 配置项,有如下三个选项:

# appendfsync always
appendfsync everysec
# appendfsync no

解释:
always:每次有写入命令都进行缓存区与磁盘数据同步,这样保证不会有数据丢失。但是会导致 redis 的吞吐量大大下降,不推荐使用这种方式。

everysec:这是 redis 默认的同步机制,虽然每秒同步一次数据,看上去时间也很快的,但是它对 redis 的吞吐量没有任何影响,每秒同步一次的话意味着最坏的情况下我们只会丢失 1 秒的数据, 推荐使用这种同步机制,兼顾性能和数据安全

no:不做任何处理,缓存区与 aof 文件同步交给系统去调度,操作系统同步调度的周期不固定,最长会有 30 秒的间隔,这样出故障了就会丢失比较多的数据。

AOF重写(Rewrite)

        由于AOF 文件都是追加的,随着服务器的运行 AOF 文件会越来越大,会在 Redis 重启时加载过大的 AOF 文件需要过多的时间,降低Redis效率。因此,引入了AOF重写机制来解决AOF文件过大的问题。

        AOF rewrite 开启的前提是开启 AOF。

        Redis AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程,重写之后的 AOF 文件会比旧的 AOF 文件占更小的体积,这是由以下几个原因导致的:

  • 进程内已经超时的数据不再写入文件
  • 旧的 AOF 文件含有无效命令,如 del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保 留最终数据的写入命令
  • 多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢 出,对于 list、set、hash、zset 等类型操作,以 64 个元素为界拆分为多条。
AOF重写触发方式
  • 手动触发:调用bgrewriteaof命令,异步执行一个 AOF重写操作。
10.19.132.41:0>BGREWRITEAOF
"Background append only file rewriting started"
  • 自动触发:修改redis.conf中的如下配置
#代表当前 AOF文件空间和上一次重写后 AOF 文件空间的比值,默认是 100%,也就是一样大的时候
auto-aof-rewrite-percentage 100

#表示运行 AOF 重写时 AOF 文件最小体积,也就是说AOF 文件最小为 64MB 才有可能触发重写
auto-aof-rewrite-min-size 64mb
AOF 文件重写过程

        AOF 文件重写在重写期间建立了一个 aof_rewrite_buf 缓存区来保存重写期间主进程响应的命令,等新的 AOF 文件重写完成后,将这部分文件同步到新的 AOF 文件中,最后用新的 AOF 文件替换掉旧的 AOF 文件。需要注意的是在重写期间,旧的 AOF 文件依然会进行磁盘同步,这样做的目的是防止重写失败导致数据丢失。

AOF持久化优缺点

AOF持久化具有以下优点:

  1. 更高的数据安全性:根据同步策略的选择,AOF持久化可以保证较高的数据安全性。
  2. 更好的容错性:即使AOF文件存在部分损坏,仍可以恢复大部分数据。

AOF持久化的缺点包括:

  1. 较大的存储空间:与RDB持久化相比,AOF文件通常较大,占用较多磁盘空间。
  2. 数据加载速度较慢:由于需要重放AOF文件中的命令,数据恢复速度相对较慢。

混合持久化

        从上面知道,rdb 文件小且加载快但可能会导致一定时间内的数据丢失,AOF文件大且加载慢但数据更安全。混合持久化是吸取RDB和 AOF 两者优点的一种持久化方案。

        修改redis.conf配置文件,开启混合持久化:

aof-use-rdb-preamble yes

混合持久化原理

        Redis首先使用RDB持久化将内存中的数据快照存储到磁盘上,然后再使用AOF持久化将所有新的写操作追加到AOF文件中。

        在开启混合持久化的情况下,触发AOF 重写时会把 Redis 的 RDB快照写入到 appendonly.aof 文件的开头,之后的所有写命令以AOF的格式追加到appendonly.aof文件的末尾。混合持久化的数据存储结构如下图所示:

混合持久化触发

        在混合持久化开启的情况下,执行BGREWRITEAOF命令,手动触发AOF重写,得到 appendonly.aof 的文件内容如下图所示:

        可以看出 appendonly.aof 文件存储的内容是以 REDIS 开头的 RDB 格式的内容,文件结尾是AOF格式的内容。

混合持久化数据恢复流程

        混合持久化的数据恢复流程图如下图所示:

  • 判断是否开启 AOF 持久化,开启继续执行后续流程,未开启执行加载 RDB 文件的流程;
  • 判断 appendonly.aof 文件是否存在,文件存在则执行后续流程;
  • 判断 AOF 文件开头是 RDB 的格式, 先加载 RDB 内容再加载剩余的 AOF 内容;
  • 判断 AOF 文件开头不是 RDB 的格式,直接以 AOF 格式加载整个文件。

上图也说明,Redis恢复数据时,优先加载AOF文件。

混合持久化的优缺点

混合持久化优点:

  • 混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险。

混合持久化缺点:

  • AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;
  • 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了。

Redis主从复制

主从复制概述

        主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave)。数据的复制是单向的,只能由主节点到从节点。默认情况下,每台Redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。主从之间采用异步复制的方式。下图是主从复制的架构:

主从复制的作用

  • 数据备份:主节点将数据同步到从节点上,实现了数据备份
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复
  • 负载均衡:在主从复制的架构下,可以实现读写分离,即:由主节点提供写服务,从节点提供读服务。这样可以减轻单个服务器的压力,提高服务器的并发量。

主从复制的最终一致性

        当主节点和从节点不一致时,从节点会努力追赶主节点,最终从节点的状态会和主节点的状态将保持一致。

主从复制的分类

        Redis的主从复制分为全量复制增量复制。下面分别介绍这2中复制方式。

开启主从复制

        主从复制的开启,完全是在从节点发起的;不需要我们在主节点做任何事情。

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

  • 在从服务器的配置文件中加入:slaveof masterip masterport
  • 启动命令redis-server后加入 --replicaof masterip masterport。如:redis-server --replicaof 127.0.0.1 7001
  • 直接在客户端执行命令:slaveof masterip masterport。这会让该Redis实例成为从节点。

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

全量复制

        全量复制发生在slave节点初次连接或无法进行部分复制的情况。

        对于初次连接的从节点,全量复制前,需要先和主节点建立连接:

全量复制过程

        从节点进行全量复制的过程如下图所示:

  • 从节点通过配置文件中的replicaof {masterip} {port} 获得主节点ipport,然后向主节点发送psync {run_id} {offset} 指令,其中run_id表示主节点唯一标识,offset为复制偏移量,因为当前从节点与主节点尚未连接,且尚未开始复制,所以run_id?offset-1

  • 主节点收到psync {run_id} {offset} 指令后,会响应从节点并发送fullresync {run_id} {offset} 指令,从节点会将主节点的run_idoffset保存下来;
  • 主节点收到psync {run_id} {offset} 指令后,会执行bgsave异步的生成RDB文件,然后主节点将RDB文件发送给从节点,从节点接收到RDB文件后,会清空内存数据,然后加载RDB文件的数据到内存中;
  • 由于主节点生成RDB文件时是异步生成的,此时主节点是非阻塞的,可以继续处理业务,所以在生成RDB文件期间发送RDB文件期间从节点加载RDB文件期间主节点执行的写指令均会存放到缓冲区replication_buffer中,所以当从节点加载完RDB文件后,主节点会将replication_buffer中的内容发送给从节点,从节点会执行replication_buffer中的指令,从而达到和主节点一致的状态。

        特别说明:在全量同步期间,主节点是非阻塞的,同时从节点很大程度上是非阻塞的,从节点的非阻塞表现在可以通过配置让从节点在全量同步期间使用旧内存数据来处理查询指令,但是从节点在删除旧内存数据并加载RDB文件数据到内存中这段时间里,从节点是阻塞的(4.0版本前,删除旧数据和加载RDB文件都会阻塞从节点,4.0版本开始,删除旧数据可以通过配置变成不阻塞从节点,但是加载RDB文件还是会阻塞从节点)。

        最后说明一个异常情况,那就是replication_buffer是有大小限制的,如果replication_buffer大小超过了限制,主节点会断开与从节点的同步连接,此时replication_buffer的数据会被清空,然后会重新开始全量同步,所以replication_buffer大小需要设置一个合理值。

增量复制

        由于全量复制非常耗费资源,效率太低,对于slave节点正常工作时需要进行同步或slave节点断开重连时需要进行同步的场景,可以使用增量复制,这种方式效率很高。

        通常情况下,Master每执行一个写命令就会向Slave发送相同的写命令,然后Slave接收并执行。

增量复制的过程

        首先,需要明白三个概念:runid、offset、repl backlog buffer。

服务器 RUN ID

        无论主库还是从库都有自己的 RUN ID,RUN ID在启动时自动产生,RUN ID 由40个随机的十六进 制字符组成。

        当从库对主库初次复制时,主库将自身的 RUN ID 传送给从库,从库会将 RUN ID 保存;

        当从库断线重连主库时,从库将向主库发送之前保存的 RUN ID;

  • 从库 RUN ID 和主库 RUN ID 一致,说明从库断线前复制的就是当前的主库;主库尝试执行 增量同步操作;
  • 若不一致,说明从库断线前复制的主库并不时当前的主库,则主库将对从库执行全量同步操 作;
复制积压缓冲区(repl backlog buffer)

      复制积压缓冲区也叫环形缓冲区,主节点在任何时候执行的写指令都会记录在这里。它本质上是一个环形的固定长度先进先出队列。所以,如果环形缓冲区中记录的从节点断开连接期间的写指令已经被后续的写指令覆盖,那么此时不能执行增量同步,而是需要执行全量同步。

复制偏移量 offset

        主从节点都会维护一个复制偏移量:

  • 主库向从库发送N个字节的数据时,将自己的复制偏移量上加N;
  • 从库接收到主库发送的N个字节数据时,将自己的复制偏移量加上N;

通过比较主从偏移量得知主从之间数据是否一致;偏移量相同则数据一致;偏移量不同则数据不一 致;

增量同步过程

使用增量复制还是全量复制

Redis 哨兵模式

哨兵模式介绍

        考虑这种情况:万一我们的master 突然宕机了,不能提供写服务了,只能依靠slave实现读的功能,这种情况是很糟糕的。为了解决这种情况,提出的哨兵模式。

        哨兵(sentinel)是Redis的高可用性(High Availability)的解决方案:

  • 由一个或多个sentinel实例组成sentinel集群可以监视一个或多个主服务器和多个从服务器。

  • 当主服务器进入下线状态时,sentinel可以将该主服务器下的某一从服务器升级为主服务器继续提供服务,从而保证redis的高可用性

哨兵模式搭建

        每个哨兵实例都是一个单独的进程。

安装

sudo apt-get install redis-sentinel

配置

        假如创建3个哨兵,需要修改每个哨兵的配置文件sentinel.conf:

cp sentinel.conf sentinel‐26379.conf
cp sentinel.conf sentinel‐26380.conf
cp sentinel.conf sentinel‐26381.conf

         再修改每个sentinel.conf文件的内容:

#哨兵sentinel实例运行的端口默认26379
port 26379

#将`daemonize`由`no`改为`yes`
daemonize yes

#哨兵sentinel监控的redis主节点的 ip port
#master-name可以自己命名的主节点名字只能由字母A-z、数字0-9、这三个字符".-_"组成。#quorum当这些quorum个数sentinel哨兵认为master主节点失联那么这时客观上认为主节点失联了
#sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor master 127.0.0.1 6379 2

#当在Redis实例中开启了requirepass foobared授权密码这样所有连接Redis实例的客户端都要提供密码
#设置哨兵sentinel连接主从的密码注意必须为主从设置一样的验证密码
#sentinel auth-pass <master-name> <password>

sentinel auth-pass master MySUPER--secret-0123passw0rd

#指定多少毫秒之后主节点没有应答哨兵sentinel此时哨兵主观上认为主节点下线默认30秒,改成3秒
#sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds master 3000

#这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为1来保证每次只有一个slave处于不能处理命令请求的状态。
#sentinel parallel-syncs <master-name> <numslaves>

sentinel parallel-syncs master 1

#故障转移的超时时间failover-timeout可以用在以下这些方面:
#1.同一个sentinel对同一个master两次failover之间的间隔时间。
#2.当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了#默认三分钟
#sentinel failover-timeout <master-name> <milliseconds>
sentinelf ailover-timeout master1 80000

启动哨兵示例

在redis-sentinel1目录下 ./redis-sentinel sentinel.conf
在redis-sentinel2目录下 ./redis-sentinel sentinel.conf
在redis-sentinel3目录下 ./redis-sentinel sentinel.conf

        查看启动后的哨兵进程状态:

哨兵执行流程

        下图是哨兵实例运行的流程:

启动并初始化sentinel        

        Sentinel是一个特殊的Redis服务器不会进行持久化,Sentinel实例启动后每个Sentinel会创建2个连向主服务器的网络连接:

  • 命令连接:用于向主服务器发送命令,并接收响应

  • 订阅连接:用于订阅主服务器的—sentinel—:hello频道

获取主redis信息

        Sentinel默认每10s一次,向被监控的主节点发送info命令,获取主节点和其下属从节点的信息。

获取从Redis信息

        当Sentinel发现主节点有新的从节点出现时,Sentinel还会向从节点建立命令连接和订阅连接。

        在命令连接建立之后,Sentinel还是默认10s一次,向从节点发送info命令,并记录从节点的信息。

哨兵以订阅的方式向主从节点发送消息

        默认情况下,Sentinel每2s一次,向所有被监视的主从节点所订阅的—sentinel—:hello频道上发送消息,消息中会携带Sentinel自身的信息和主服务器的信息。

检测主观下线

        sentinel 会以每秒一次的频率向所有节点(其他sentinel、主节点、以及从节点)发送 ping 命令,然后通过接收返回判断该节点是否下线;如果在配置指定的down-after-milliseconds 时间内无回复,则sentinel会认为该节点主观下线;

检测客观下线

        当一个 sentinel 节点将一个主节点判断为主观下线之后,为了确认这个主节点是否真的下线,它 会向其他sentinel 节点进行询问,如果收到一定数量的已下线回复,sentinel 会将主节点判定为客观下线。

哨兵选举

        当一个主节点被判定为客观下线后,监视这个主节点的所有Sentinel会通过选举算法(raft),开始leader sentinel选举,需要要一半以上的 sentinel 支持,选出一个Leader Sentinel,去对这个下线的主节点执行failover(故障转移)操作。

故障转移

        当选举出Leader Sentinel后,Leader Sentinel会对下线的主服务器执行故障转移操作:

  • 从从节点中选举一个从节点作为新的主节点
  • 通知其他从节点复制连接新的主节点
  • 若故障主节点重新连接,将作为新的主节点的从节点

总结

        与主从相比,哨兵仅解决了手动切换主从节点问题,至于其他的问题,基本上仍然存在。

Redis Cluster

        Redis Cluster 即 Redis 集群,是 Redis 官方在 3.0 版本推出的一套分布式存储方案。完全去中心化,由多个节点组成,所有节点彼此互联。Redis 客户端可以直接连接任何一节点获取集群中的键值对,不需要中间代理,如果该节点不存在用户所指定的键值,其内部会自动把客户端重定向到键值所在的节点。

为什么要实现Redis Cluster

        在海量数据的场景下,单实例Redis存储能力根本无法满足业务需求,因此需要对数据进行分布式存储,将不同的数据存储在不同的master节点上,提高并发性能。

Redis Cluster特点

  • 多主多从,去中心化:从节点作为备用,复制主节点,不做读写操作,不提供服务
  • 不支持处理多个key:因为数据分散在多个节点,在数据量大高并发的情况下会影响性能;
  • 支持动态扩容缩容节点:这是我认为算是Rerdis Cluster最大的优点之一;
  • 节点之间相互通信,相互选举,不再依赖sentinel:准确来说是主节点之间相互“监督”,保证及时故障转移

Redis Cluster基本架构

Cluster节点

        Redis 集群是一个网状结构,每个节点都通过 TCP 连接跟其他每个节点连接。在一个有 N 个节点的集群中,每个节点都有 N-1 个流出的 TCP 连接,和 N-1 个流入的连接,这些 TCP 连接会永久保持。

        Redis集群可以看成多个主从架构组合起来的,每一个主从架构可以看成一个节点(其中,只有master节点具有处理请求的能力,slave节点主要是用于节点的高可用,即:每个master节点都可以挂载多个slave节点,当master节点挂掉时,集群会提升它的某个slave节点作为新的master节点。)

分配槽

        Redis cluster 将所有数据划分为 16384(2^14)个槽位,把这些槽平均配给节点进行管理,每个节点只能对自己负责的槽进行读写操作。由于每个节点之间都彼此通信,每个节点都知道另外节点负责管理的槽范围。

客户端访问cluster节点

        每个节点利用通信共享Redis Cluster中槽和集群中对应节点的关系。

  1. 客户端向Redis Cluster的任意节点发送命令,接收命令的节点会对数据key按照CRC16规则进行hash运算与16383取余,计算出数据所在的槽和Redis节点。
  2. 如果数据所在的槽位于当前节点,则去槽中执行命令,并把命令执行结果返回给客户端
  3. 如果数据所在的槽不在当前节点,则向客户端返回moved重定向异常
  4. 客户端接收到节点返回的结果,如果是moved异常,则从moved异常中获取目标节点的信息
  5. 客户端向目标节点发送命令,获取命令执行结果

        例如,计算hello这个key所在的槽:

ask重定向

        当集群进行扩容或缩容时,需要对槽及槽中数据进行迁移:

      当客户端向某个节点发送命令,节点向客户端返回moved异常,告诉客户端数据对应的槽的节点信息。如果此时正在进行集群扩展或者收缩操作,当客户端向正确的节点发送命令时,槽及槽中数据已经被迁移到别的节点了,就会返回ask,这就是ask重定向机制。

  1. 客户端向目标节点发送命令,目标节点中的槽已经迁移支别的节点上了,此时目标节点会返回ask转向给客户端
  2. 客户端向新的节点发送Asking命令给新的节点,然后再次向新节点发送命令
  3. 新节点执行命令,把命令执行结果返回给客户端

moved异常与ask异常的比较

  • 两者都是客户端重定向
  • moved异常:槽已经确定迁移,即槽已经不在当前节点
  • ask异常:槽还在迁移中

数据迁移

官方迁移工具:redis-trib.rb和import
只能从单机迁移到集群
不支持在线迁移:source需要停写
不支持断点续传
单线程迁移:影响深度

在线迁移:

唯品会:redis-migrate-tool
豌豆荚:redis-port

故障发现

        cluster 集群中节点分为主节点和从节点,其中主节点用于处理槽,而从节点则用于复制该主节 点,并在主节点下线时,代替主节点继续处理命令请求.

        集群中每个节点都会定期地向集群中的其他节点发送 ping 消息,如果接收 ping 消息的节点没有 在规定时间内回复 pong 消息,那么这个没有回复 pong 消息的节点会被标记为 PFAIL(probable fail); 集群中各个节点会通过互相发送消息的方式来交换集群中各个节点的状态信息;如果在一个集群 中,半数以上负责处理槽的主节点都将某个主节点 A 报告为疑似下线,那么这个主节点A将被标记 为下线(FAIL);标记主节点 A 为下线状态的主节点会广播这条消息,其他节点(包括A节点的从 节点)也会将A节点标识为 FAIL;

故障转移

        当从节点发现自己的主节点进入FAIL状态,从节点将开始对下线主节点进行故障转移:

  • 从数据最新的从节点中选举为主节点
  • 该从节点会执行 replica no one 命令,称为新的主节点
  • 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己
  • 新的主节点向集群广播一条 pong 消息,这条 pong 消息可以让集群中的其他节点立即知道
  • 这个节点已经由从节点变成主节点,并且这个主节点已经接管了之前下线的主节点
  • 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移结束

redis-cluster相关的集群命令

  • cluster info :打印集群的信息
  • cluster nodes :列出集群当前已知的所有节点( node),以及这些节点的相关信息。
  • cluster meet <ip> <port> :将 ip 和 port 所指定的节点添加到集群当中。
  • cluster forget <node_id> :从集群中移除 node_id 指定的节点。
  • cluster replicate <master_node_id> :将当前从节点设置为 node_id 指定的master节点的slave节点。只能针对slave节点操作。
  • cluster saveconfig :将节点的配置文件保存到硬盘里面。
  • cluster addslots <slot> [slot ...] :将一个或多个槽( slot)指派( assign)给当前节点。
  • cluster delslots <slot> [slot ...] :移除一个或多个槽对当前节点的指派。
  • cluster flushslots :移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
  • cluster setslot <slot> node <node_id> :将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给
  • cluster setslot <slot> migrating <node_id> :将本节点的槽 slot 迁移到 node_id 指定的节点中。
  • cluster setslot <slot> importing <node_id> :从 node_id 指定的节点中导入槽 slot 到本节点。
  • cluster setslot <slot> stable :取消对槽 slot 的导入( import)或者迁移( migrate)。
  • cluster keyslot <key> :计算键 key 应该被放置在哪个槽上。
  • cluster countkeysinslot <slot> :返回槽 slot 目前包含的键值对数量。
  • cluster getkeysinslot <slot> <count> :返回 count 个 slot 槽中的键 。

参考文献:

Redis 的持久化方式及其原理,看这一篇就够了 - 知乎 (zhihu.com)

详解Redis的主从同步原理 - 掘金 (juejin.cn)

全网最详细Redis教程之主从复制 - 掘金 (juejin.cn)

一文彻底吃透Redis Cluster集群,干货满满,速来 - 知乎 (zhihu.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值