目录

Redis的持久化存储

1.RDB持久化:

2.AOF持久化:

3.如何在 Redis 中同时使用 RDB 和 AOF:

总结:

Redis的主从集群

1. Redis 主从复制基本概念:

2.搭建主从集群:

(1)创建目录:

 (2)恢复原始配置:

(3)拷贝配置文件到每个实例目录:

(4)修改每个实例的端口、工作目录:

(5)修改每个实例的声明IP:

3.启动Redis实例:

4.开启主从关系:

5.主从数据同步原理:

(1) 全量同步:

流程简述:

(2)增量同步:

(3)优化:

Redis的哨兵集群

1.什么是哨兵集群?

2.哨兵如何得知节点状态? 

3.搭建哨兵集群:

 (1)搭建哨兵集群的大体轮廓:

(2)创建目录:

(3)启动哨兵集群:

4.如何使用RedisTemplate的哨兵集群?

(1)引入依赖:

(2)配置 Redis 哨兵:

(3)在启动类配置 Lettuce 客户端,指定读操作从 Slave 读取:

Redis的分片集群

1. 为什么要使用 Redis 分片集群?

2.配置分片集群:

(1)准备实例和配置:

(2)启动分片集群:

(3)测试分片集群:

3.哈希槽(Hash Slot):

4.集群伸缩(Cluster Scaling):

5.集群故障转移(Failover):

模拟:

总结:


本篇内容详细介绍Redis分布式集群的三种模式,内容来源黑马程序员Redis入门到实战课程资料,如果有收获,希望给这篇博客点个赞作为支持,谢谢!!!


什么是 Redis 分布式集群?


Redis 分布式集群(Redis Cluster) 是 Redis 提供的一个分布式系统,用于处理大规模数据。它将数据分散到多个节点中(分片),并且每个节点只存储数据的部分副本。这种设计使得 Redis 集群能够扩展性强,能够应对更多的请求和更多的数据存储需求。

在 Redis 集群中:

  • 数据通过 分片(Sharding)存储到多个节点上。
  • 每个节点可能会有 主从复制,以提高可用性和容错性。
  • 通过 哈希槽(Hash Slots)将数据分配到不同的节点。
  • 通过 集群管理,自动进行故障转移和重新分配分片。

单节点 Redis 和 Redis 集群的对比


特性 单节点 Redis Redis 集群
存储方式 单个实例,所有数据都保存在一个节点中 数据通过分片分布在多个节点上
扩展性 扩展性差,单节点性能有限 可以横向扩展,添加更多节点以扩展容量和吞吐量
高可用性 单点故障,系统崩溃时服务不可用 主从复制和自动故障转移,提高高可用性
性能 当数据量增大时性能会下降 通过分片机制提升性能,处理更多请求
数据冗余 无数据冗余,数据丢失风险大 主从复制提供数据冗余,提高容错能力
复杂度 配置简单,容易理解 配置复杂,涉及分片、故障转移等

Redis的持久化存储


Redis 持久化是指将 Redis 中的数据从内存保存到磁盘上,以防止服务器重启或宕机时数据丢失。Redis 提供了两种持久化方式:RDB(Redis DataBase)AOF(Append-Only File)。这两种方式可以单独使用,也可以同时使用,根据应用场景的不同,选择合适的持久化方案可以在性能与数据持久性之间做出权衡。

1.RDB持久化:

RDB 持久化方式通过创建数据集的快照,将 Redis 中的数据保存到一个二进制文件中,文件扩展名通常是 .rdb。RDB 会在指定的时间间隔内(或满足某些条件时)将 Redis 数据快照写入磁盘。

工作原理: 

  • Redis 会根据一定的时间间隔或数据变化条件(例如写入一定次数的命令)来保存数据的快照。
  • 每次保存时,Redis 会将整个内存中的数据快照保存到硬盘,生成一个 RDB 文件。该文件包含 Redis 数据库的完整数据。
  • RDB 是通过 fork 操作创建子进程来保存快照的,父进程继续响应客户端请求,子进程则负责将数据保存到磁盘。

配置RDB:

在 Redis 的配置文件 redis.conf 中,可以设置触发 RDB 快照的条件。例如:

save 900 1      # 在 900 秒(15 分钟)内,如果至少 1 个键发生变化,则保存快照
save 300 10     # 在 300 秒(5 分钟)内,如果至少 10 个键发生变化,则保存快照
save 60 10000   # 在 60 秒内,如果至少 10000 个键发生变化,则保存快照

RDB的其他配置也可以在redis.conf文件中设置:

优点

  • 性能好:RDB 是通过 fork 创建子进程来进行持久化操作,主进程不会阻塞客户端请求,因此性能较好。
  • 数据恢复快:RDB 文件是一个二进制文件,恢复时可以快速加载数据,适合用于恢复大量数据。
  • 适合备份:RDB 适合用于定期备份整个数据库的快照。

缺点

  • 持久化时数据丢失的风险较大:由于 RDB 是基于时间间隔的快照方式,如果 Redis 崩溃或重启,最后一次快照和当前内存中的数据可能有差异,导致有数据丢失。
  • 内存占用较大:每次保存快照时,Redis 会在内存中复制整个数据集,因此内存占用较大。

2.AOF持久化:

AOF 持久化方式是通过将 Redis 执行的写命令以追加的方式写入一个日志文件中。每次 Redis 执行写命令时,AOF 会将该命令记录到日志文件中。AOF 是基于命令的持久化方式,可以保证每个写操作都会被记录,因此比 RDB 更具可靠性。

工作原理:

  • 每次 Redis 执行写操作时,都会将写命令追加到 AOF 文件中。
  • AOF 文件中的内容是 Redis 的所有写命令,当 Redis 重启时,Redis 会按 AOF 文件中的命令顺序重新执行,恢复数据。
  • AOF 写操作有不同的策略,可以选择不同的同步策略(不同的刷写频率)。

配置 AOF:

AOF默认是关闭的,在 Redis 配置文件 redis.conf 中,可以设置 AOF 的行为。例如:

appendonly yes           # 启用 AOF 持久化
appendfilename "appendonly.aof" # AOF文件的名称

AOF的命令记录频率也可以通过redis.conf文件来配置:

Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf文件中配置:

3.如何在 Redis 中同时使用 RDB 和 AOF:

Redis 支持同时启用 RDB 和 AOF 持久化方式,这样可以兼顾性能和数据可靠性。Redis 会先使用 RDB 快照进行持久化,如果发生故障,还可以通过 AOF 恢复数据,确保数据丢失最小化。

redis.conf 中,我们可以同时启用这两种持久化方式:

save 900 1      # 900 秒内至少 1 个键发生变化,则保存 RDB 快照
save 300 10     # 300 秒内至少 10 个键发生变化,则保存 RDB 快照
save 60 10000   # 60 秒内至少 10000 个键发生变化,则保存 RDB 快照

appendonly yes           # 启用 AOF 持久化
appendfsync everysec     # 每秒同步一次 AOF 文件

总结:

RDB 持久化:基于快照的持久化方式,性能较好,但可能丢失最后一次快照后的数据。

AOF 持久化:基于命令追加的持久化方式,提供较高的数据可靠性,但性能开销较大,且文件可能较大。

同时使用 RDB 和 AOF:可以平衡性能和数据可靠性,适用于对数据持久性要求较高的场景。 


持久化配置


no-appendfsync-on-rewrite=yes 是 Redis 配置文件(redis.conf)中的一个选项,用于控制 Redis 在 AOF 重写(Append-Only File Rewrite) 过程中是否调用 fsync 一个系统调用,用于将文件数据从内存缓冲区强制写入磁盘,确保数据持久化将数据强制刷入磁盘。

 


 接下来给大家讲述三种集群处理方式:

方案 适用场景 读写分离 自动Failover 水平扩展 复杂度
主从复制(Master-Slave) 适用于读多写少的系统 ✅ 是 ❌ 否 ❌ 否
哨兵集群(Sentinel) 小规模系统,读写分离 ✅ 是 ✅ 是 ❌ 否 ⭐⭐
分片集群(Cluster) 大数据量,高并发系统 ✅ 是 ✅ 是 ✅ 是 ⭐⭐⭐

📌 推荐使用:

  • 小型应用(< 10GB 数据)主从 + 哨兵
  • 中型应用(10GB~100GB 数据)Redis Cluster
  • 大型应用(> 100GB 数据)Redis Cluster + 分片

Redis的主从集群


Redis 主从集群(Replication)是一种 数据复制 机制,通过这种机制,Redis 能够在一个或多个 从节点 上复制 主节点 的数据。这种机制能够实现高可用性、负载均衡和容错能力,帮助 Redis 构建高可用的分布式架构。

1. Redis 主从复制基本概念:

Redis 主从复制指的是一个 Redis 实例(称为 主节点)将其数据复制到一个或多个 Redis 实例(称为 从节点)。从节点仅从主节点复制数据,不处理写请求。主节点将所有的写操作(如 SETDEL 等)同步到从节点,从节点则响应读取请求。 

2.搭建主从集群:

上面图片共包含三个节点,一个主节点,两个从节点。

这里我们会在同一台虚拟机中开启3个redis实例,模拟主从集群,信息如下:

IP PORT 角色
192.168.150.101 7001 master
192.168.150.101 7002 slave
192.168.150.101 7003 slave

要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。

(1)创建目录:

我们创建三个文件夹,名字分别叫7001、7002、7003:

# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 7001 7002 7003

 (2)恢复原始配置:

修改redis-6.2.4/redis.conf文件,将其中的持久化模式改为默认的RDB模式,AOF保持关闭状态。

# 开启RDB
# save ""
save 3600 1
save 300 100
save 60 10000

# 关闭AOF
appendonly no

(3)拷贝配置文件到每个实例目录:

然后将redis-6.2.4/redis.conf文件拷贝到三个目录中(在/tmp目录执行下列命令):

# 方式一:逐个拷贝
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003

# 方式二:管道组合命令,一键拷贝
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf

(4)修改每个实例的端口、工作目录:

修改每个文件夹内的配置文件,将端口分别修改为7001、7002、7003,将rdb文件保存位置都修改为自己所在目录(在/tmp目录执行下列命令):

sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf

(5)修改每个实例的声明IP:

虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定ip信息,格式如下:

# redis实例的声明 IP
replica-announce-ip 192.168.150.101

每个目录都要改,我们一键完成修改(在/tmp目录执行下列命令):

# 逐一执行
sed -i '1a replica-announce-ip 192.168.150.101' 7001/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7002/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7003/redis.conf

# 或者一键修改
printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.150.101' {}/redis.conf

3.启动Redis实例:

为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:

# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf

如果要一键停止,可以运行下面命令:

printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown

4.开启主从关系:

现在三个实例还没有任何关系,要配置主从可以使用replicaof 或者slaveof(5.0以前)命令。

有临时和永久两种模式:

  • 修改配置文件(永久生效)

    • 在redis.conf中添加一行配置:slaveof <masterip> <masterport>

  • 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
slaveof <masterip> <masterport>

这里我们为了演示方便,使用方式二。

通过redis-cli命令连接7002,执行下面命令:

# 连接 7002
redis-cli -p 7002
# 执行slaveof
slaveof 192.168.150.101 7001

 通过redis-cli命令连接7003,执行下面命令:

# 连接 7003
redis-cli -p 7003
# 执行slaveof
slaveof 192.168.150.101 7001

然后连接 7001节点,查看集群状态:

# 连接 7001
redis-cli -p 7001
# 查看状态
info replication

随后就可以实现主从集群了,可以发现,只有在7001这个master节点上可以执行写操作,7002和7003这两个slave节点只能执行读操作。

5.主从数据同步原理:

(1) 全量同步:

但是master如何判断slave节点是不是第一次来做数据同步的?

偏移量offset是无法判断是否是第一次来的,比如这个从节点已经在别的主节点进行拷贝,那么偏移量无法判断是否是当前主节点拷贝。所以我们只能通过replid来判断。

流程简述:

slave节点请求增量同步,随后master节点判断replid是否一致,如果不一致则拒绝增量同步,如果一致,那么master将完整内存数据生成RDB,发送RDB到slave,随后slave清空本地数据并加载master的RDB,建立成功后,master将RDB期间的命令记录在repl_backlog,并持续将log中的命令发送给slave。

(2)增量同步:

什么情况会进行增量同步?

在slave重启中,master会持续的接受数据,所以slave的数据肯定会落后,这个时候做的同步就是增量同步。

slave重启过程中,master将RDB期间的命令记录在repl_backlog,repl_backlog是一个数组结构(如上图两侧的圆形),只要我们master存储的命令没有占满整个数组,就可以即使的进行增量同步。

但是一但出现占满整个数组的情况,由于repl_backlog的存储大小有上限,写满后会覆盖最早的数据,如果slave断开时间太久导致尚未备份的数据被覆盖,则无法基于log进行增量同步,那么这个时候就只能进行全量同步

(3)优化:


Redis的哨兵集群


在上面,我们如果slave宕机可以使用全量同步以及增量同步的方法解决数据不一致问题,但是如果master宕机了,这种情况下用户是无法进行写操作的,那怎么办呢?

我们可以监控集群中的节点状态,当我们发现master宕机时,立即选一个slave当做master,若原来的master回复正常,让其当做slave就可以完美的解决了。这个时候就需要我们用到哨兵机制

1.什么是哨兵集群?

Redis 哨兵(Sentinel)是一套分布式系统,由多个哨兵进程组成,用于监控 Redis 主从架构中的各个节点。其主要特点包括:

  • 监控:实时检查 Redis 主节点和从节点的运行状态。
  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新消息推送给Redis客户端。
  • 自动故障恢复:当主节点宕机或无法访问时,哨兵集群会协商并自动将其中一个从节点升级为新的主节点,保证服务的连续性。
  • 服务发现:应用程序可以通过哨兵获取当前可用的主节点地址,实现自动切换连接。

2.哨兵如何得知节点状态? 

Sentinal是基于心跳机制来监测服务状态,每隔1秒向集群的每隔实例发送ping命令:

  • 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel的实例数量的一半。

如何选择新的slave作为master呢?

在每个从节点的配置中,都可以通过 slave-priority 参数来设置其在故障转移过程中的优先级。

  • 如果一个从节点的 slave-priority 被设置为 0,则它永远不会被选举为主节点。
  • 当多个从节点的复制偏移量相差不大时,Sentinel 会参考各节点的 slave-priority,数值较高(或说被配置为更高优先级)的节点更有可能被选中。
  • 这样做的目的在于:通过人工调整某些节点的优先级,管理员可以预先指定某些节点不参与或参与故障转移,从而达到负载均衡或其他业务需求。

如何实现故障转移? 

假设7001作为主节点并且宕机,那么使用7002作为新的主节点,随后等待7001宕机结束后变更为从节点:

3.搭建哨兵集群:

 (1)搭建哨兵集群的大体轮廓:

这里我们搭建一个三节点形成的Sentinel集群,来监管之前的Redis主从集群。如图:

三个sentinel实例信息如下:

节点 IP PORT
s1 192.168.150.101 27001
s2 192.168.150.101 27002
s3 192.168.150.101 27003

(2)创建目录:

要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。

我们创建三个文件夹,名字分别叫s1、s2、s3:

# 进入/tmp目录
cd /tmp
# 创建目录
mkdir s1 s2 s3

然后我们在s1目录创建一个sentinel.conf文件,添加下面的内容:

port 27001
sentinel announce-ip 192.168.150.101
sentinel monitor mymaster 192.168.150.101 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/tmp/s1"

内容解读:

  • port 27001:是当前sentinel实例的端口

  • sentinel monitor mymaster 192.168.150.101 7001 2:指定主节点信息

    • mymaster:主节点名称,自定义,任意写

    • 192.168.150.101 7001:主节点的ip和端口

    • 2:选举master时的quorum值

然后将s1/sentinel.conf文件拷贝到s2、s3两个目录中(在/tmp目录执行下列命令):

# 方式一:逐个拷贝
cp s1/sentinel.conf s2
cp s1/sentinel.conf s3
# 方式二:管道组合命令,一键拷贝
echo s2 s3 | xargs -t -n 1 cp s1/sentinel.conf

随后修改s2、s3两个文件夹内的配置文件,将端口分别修改为27002、27003:

sed -i -e 's/27001/27002/g' -e 's/s1/s2/g' s2/sentinel.conf
sed -i -e 's/27001/27003/g' -e 's/s1/s3/g' s3/sentinel.conf

(3)启动哨兵集群:

为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:

# 第1个
redis-sentinel s1/sentinel.conf
# 第2个
redis-sentinel s2/sentinel.conf
# 第3个
redis-sentinel s3/sentinel.conf

4.如何使用RedisTemplate的哨兵集群?

(1)引入依赖:

pom.xml 文件中添加 Spring Boot Redis 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

(2)配置 Redis 哨兵:

application.ymlapplication.properties 中配置 Redis 哨兵信息:

spring:
  redis:
    password: your_password # 如果没有密码,可以省略
    database: 0
    sentinel:
      master: mymaster  # 这里是 Sentinel 监控的主节点名称,必须与 Sentinel 配置文件一致
      nodes:
        - 192.168.150.101:27001
        - 192.168.150.102:27001
        - 192.168.150.103:27001
    timeout: 5000  # 连接超时时间(毫秒)

注意:这里配置的地址并不是集群地址,而是sentinel地址。

因为在哨兵模式下,我们的主从节点地址会变更,所以不能将地址写死,所以redis客户端不需要知道集群地址而只需要知道sentinel的地址,随后通过sentinel进行集群的地址发现。

但是如何实现读写分离呢?如何实现让所有的写操作找master,读操作找slave?

实现 读写分离 主要依赖 Lettuce 的 ReadFrom 策略,让 GET 读操作从 Slave 读取,而 SET 写操作仍然走 Master

spring:
  redis:
    sentinel:
      master: mymaster  # 配置 Sentinel 监控的 Master 名称
      nodes: 192.168.150.101:27001,192.168.150.102:27002,192.168.150.103:27003  # 哨兵地址
    database: 0
    password: yourpassword
    lettuce:
      pool:
        max-active: 10
        max-idle: 5
        min-idle: 2
      shutdown-timeout: 100ms
  logging:
    level:
      io.lettuce.core: debug  # 开启 Lettuce 日志,方便调试
    pattern:
      dateformat: MM-dd HH:mm:ss:SSS
  • mymaster 是 Redis 哨兵管理的主节点名称,需与 sentinel.conf 配置一致。
  • nodes 配置了多个 Sentinel 地址,Lettuce 会自动连接主节点和从节点。
  • lettuce.pool 配置连接池参数,优化 Redis 连接管理。

(3)在启动类配置 Lettuce 客户端,指定读操作从 Slave 读取:

实现 读写分离 主要依赖 Lettuce 的 ReadFrom 策略,让 GET 读操作从 Slave 读取,而 SET 写操作仍然走 Master

import io.lettuce.core.ReadFrom;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;

@SpringBootApplication
public class RedisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisDemoApplication.class, args);
    }

    // 配置 Lettuce 客户端,指定读操作从 Slave 读取
    public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer() {
        return builder -> builder.readFrom(ReadFrom.REPLICA_PREFERRED);
    }

}


Redis的分片集群


1. 为什么要使用 Redis 分片集群?

Redis 的 主从集群(Master-Slave)+ 哨兵(Sentinel) 方案在一些场景下可能无法满足高可用和高性能的需求,主要有以下几个问题:

方案 优点 缺点
主从集群 读写分离,提高读性能 写入仍然受限于单个 Master,存储能力受 Master 内存限制
哨兵集群 自动故障转移,提高可用性 无法进行数据分片,一个实例仍然受内存/性能限制
分片集群(Cluster) 数据水平扩展,无单点瓶颈 运维更复杂,需要客户端支持

 对于读写操作的情景下,我们不能让集群占用内存太高,如果太高会导致大量的RDB持久化以及全量同步时导致大量的io则性能下降,但是如果内存太低,当需要存储海量的数据时同样也解决不了问题。

所以下面我们需要解决两个问题:

  1. 海量数据存储问题
  2. 高并发写的问题

如下图:

2.配置分片集群:

分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:

这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:

IP PORT 角色
192.168.150.101 7001 master
192.168.150.101 7002 master
192.168.150.101 7003 master
192.168.150.101 8001 slave
192.168.150.101 8002 slave
192.168.150.101 8003 slave

(1)准备实例和配置:

删除之前的7001、7002、7003这几个目录,重新创建出7001、7002、7003、8001、8002、8003目录:

# 进入/tmp目录
cd /tmp
# 删除旧的,避免配置干扰
rm -rf 7001 7002 7003
# 创建目录
mkdir 7001 7002 7003 8001 8002 8003

在/tmp下准备一个新的redis.conf文件,内容如下:

port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /tmp/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /tmp/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.150.101
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /tmp/6379/run.log

将这个文件拷贝到每个目录下:

# 进入/tmp目录
cd /tmp
# 执行拷贝
echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf

修改每个目录下的redis.conf,将其中的6379修改为与所在目录一致:         

# 进入/tmp目录
cd /tmp
# 修改配置文件
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf

(2)启动分片集群:

因为已经配置了后台启动模式,所以可以直接启动服务:

# 进入/tmp目录
cd /tmp
# 一键启动所有服务
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf

通过ps查看状态:

ps -ef | grep redis

如果要关闭所有进程,可以执行命令:

ps -ef | grep redis | awk '{print $2}' | xargs kill

或者(推荐这种方式):

printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown

虽然六个集群启动成功,但是这六个集群都是独立集群,他们之间没有任何关系,所以接下来我们需要管理集群:

我们使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:

redis-cli --cluster create --cluster-replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003

命令说明:

  • redis-cli --cluster或者./redis-trib.rb:代表集群操作命令

  • create:代表是创建集群

  • --replicas 1或者--cluster-replicas 1 :指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1) 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master。

(前三个是主节点,后三个是从节点)

运行后出现下面的log:

这里输入yes集群就可以开始创建,随后我们通过命令可以查看集群状态

redis-cli -p 7001 cluster nodes

(3)测试分片集群:

在使用分片集群时,我们需要使用 redis-cli 命令(注意:必须带有-c,在进行集群操作时,我们需要给redis-cli加上-c参数才可以 ):

#连接
redis-cli -c -p 7001
# 存储数据
set num 123
# 读取数据
get num
# 再次存储
set a 1

在 Redis Cluster(分片集群)中,核心概念包括 哈希槽(Slot)、集群伸缩(Cluster Scaling)、故障转移(Failover)。下面我们详细介绍这些概念以及如何使用。


3.哈希槽(Hash Slot)

Redis Cluster 使用哈希槽(Hash Slot)实现数据分片,即 将 Key 分配到不同的 Redis 节点,以达到 数据分布均衡 的目的。数据key不是与节点绑定,而是与插槽绑定,redis会根据key的有效部分计算插槽值。

有效部分分为两种情况:

  1. key中包含{},且{}中至少包含一个字符,则{}中的部分是有效部分。
  2. key中不包含{},则整个key都是有效部分。

例如:

 其中【15495】的15495就是插槽值,所以这个key就是在7003节点。

哈希槽的工作方式:

  1. Redis 预先定义了 16384 个哈希槽(编号 0 ~ 16383)。
  2. 每个 Key 经过 哈希函数 CRC16(key) % 16384 计算出一个槽编号。
  3. 每个 Redis 节点(Master)负责一部分槽,比如:
    • Master1 负责槽 0 - 5460
    • Master2 负责槽 5461 - 10922
    • Master3 负责槽 10923 - 16383
  4. 客户端连接时会询问集群,然后直接访问对应的 Master,避免中心代理的性能瓶颈。

4.集群伸缩(Cluster Scaling):

在 Redis 集群运行过程中,可能需要:

  • 增加节点(add-node):当数据量过大,当前 Master 存储不足。
  • 减少节点(缩容):减少服务器数量,降低成本。

我们先创建一个端口号为7004的集群,随后使用下面命令联系7004:

redis-cli --cluster add-node 192.168.150.101:7004 192.168.1.1:7001
  • 192.168.1.100:7004新加入的节点
  • 192.168.1.1:7001集群中的任意一个已存在的节点

 随后为了让7004集群有意义,我们往7004上分配插槽:

例如我们num插槽值为2764,将num分配到新增节点7004上 ->

首先需要给num重新分配插槽值(reshard):

redis-cli --cluster reshard 192.168.150.101:7001

在这里系统会提示输入 要迁移的槽数量、源节点 ID,然后完成数据迁移。 

随后会让我们输入移动插槽数量:

在后面输入3000就可以将0~3000的所有插槽移动,之后会出现移动到哪里:

这里我们需要输入7004的ID值,可以在上面寻找,划出来的就是7004的ID如下图:

随后我们将这个ID粘贴到后面即可。

下面就需要让我们输入从哪里作为数据源进行拷贝的ID值,这里我们输入7001的ID值即可:

随后输入done结束:

最后输入yes就可以开始移动。 

5.集群故障转移(Failover):

Redis Cluster 具备 自动故障转移(Failover) 能力。当某个 Master 宕机 时:

  1. 集群会检测 Master 是否下线(Gossip 协议)
  2. 超过半数 Master 认为它下线,则 Slave 自动晋升为 Master
  3. 集群更新拓扑信息,所有客户端重新连接新 Master

情景假设: 假设 Master1 负责槽 0-5460,但它崩溃了。其从节点 Slave1 被选举为新的 Master1Slave1 接管槽 0-5460,客户端无感知地继续访问。

模拟:

关闭某个 Master:

redis-cli -p 7001 shutdown

查看集群状态:

redis-cli --cluster info 192.168.1.2:7003

集群会自动选举新的 Master,无需人工干预。

什么时候需要人工进行手动故障转移?

如果一台机器老旧或者需要维护,我们就需要手动故障转移, 其流程如下图:

 一般使用默认的缺省模式,如果我们想让宕机的7001重启并重新夺回主节点的地位

redis-server 7001/redis.conf
redis-cli -p 7001
CLUSTER FAILOVER

6.使用redis客户端操作分片集群:

首先进行配置:

logging:
  level:
    io.lettuce.core: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
spring:
  redis:
    cluster:
      nodes:
        - 192.168.1.1:7001
        - 192.168.1.2:7002
        - 192.168.1.2:7003
        - 192.168.1.2:8001
        - 192.168.1.2:8002
        - 192.168.1.2:8003

总结:

功能 作用
哈希槽(Slot) 通过 16384 个哈希槽分片存储数据
集群扩容 添加新节点,自动迁移数据,提高存储能力
集群缩容 迁移数据后删除节点,减少服务器占用
故障转移(Failover) 监测 Master 宕机,自动选举新的 Master,保障高可用
Spring Boot 通过 Lettuce + Redis Cluster 连接集群,实现高性能数据存取

Redis Cluster 适用于高并发、高可用的分布式缓存架构,在 电商、社交、推荐系统 等场景广泛应用! 🚀

Logo

更多推荐