目录
(3)在启动类配置 Lettuce 客户端,指定读操作从 Slave 读取:
本篇内容详细介绍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 实例(称为 从节点)。从节点仅从主节点复制数据,不处理写请求。主节点将所有的写操作(如 SET
、DEL
等)同步到从节点,从节点则响应读取请求。
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.yml
或 application.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则性能下降,但是如果内存太低,当需要存储海量的数据时同样也解决不了问题。
所以下面我们需要解决两个问题:
- 海量数据存储问题
- 高并发写的问题
如下图:
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的有效部分计算插槽值。
有效部分分为两种情况:
- key中包含{},且{}中至少包含一个字符,则{}中的部分是有效部分。
- key中不包含{},则整个key都是有效部分。
例如:
其中【15495】的15495就是插槽值,所以这个key就是在7003节点。
哈希槽的工作方式:
- Redis 预先定义了 16384 个哈希槽(编号
0
~16383
)。- 每个 Key 经过 哈希函数
CRC16(key) % 16384
计算出一个槽编号。- 每个 Redis 节点(Master)负责一部分槽,比如:
Master1
负责槽0 - 5460
Master2
负责槽5461 - 10922
Master3
负责槽10923 - 16383
- 客户端连接时会询问集群,然后直接访问对应的 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 宕机 时:
- 集群会检测 Master 是否下线(Gossip 协议)。
- 超过半数 Master 认为它下线,则 Slave 自动晋升为 Master。
- 集群更新拓扑信息,所有客户端重新连接新 Master。
情景假设: 假设
Master1
负责槽0-5460
,但它崩溃了。其从节点Slave1
被选举为新的Master1
。Slave1
接管槽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 适用于高并发、高可用的分布式缓存架构,在 电商、社交、推荐系统 等场景广泛应用! 🚀