别人都在用 Redis Cluster 高可用了,你还在手动重启 Redis?😅

背景

在我之前的一家公司,曾负责一个中等体量的项目。虽然业务量不大,但为了确保系统具备良好的扩展性和可用性,我们整体采用了集群架构。其中数据库MySQL 使用了云数据库,而Redis 则选择了自主搭建。

选择云 MySQL 是因为它自带自动备份、高可用、主从同步等功能,省去了很多维护成本。遇到性能瓶颈也能快速扩展实例,对我们这种缺乏专职 DBA 的小团队来说非常合适。

而 Redis 之所以自主搭建,主要是出于成本考虑。云 Redis 多按内存或 QPS 计费,费用偏高。而项目中的 Redis 多用于缓存,部署和维护都比较简单,偶尔丢失数据也在可接受范围内。综合考虑后,我们决定自主搭建一个 Redis Cluster,以实现分布式缓存与高可用能力。

为什么要搭建 Redis Cluster?

我们选择 Redis Cluster,主要是为了兼顾 高可用性横向扩展能力。虽然系统体量不大,但 Redis 是项目核心的缓存服务,一旦挂掉会直接影响用户体验,因此我们希望具备容灾能力和后续扩展空间。

Redis Cluster 支持数据自动分片、主从复制,主节点宕机时可自动切换到对应的从节点,保障服务不中断。相比单机或哨兵模式,Cluster 架构更适合分布式部署,稳定性也更强。而三台服务器部署三主三从,在控制成本的同时,也能满足基本的高可用需求,部署复杂度也不高。

如果对 "为什么 Redis Cluster 至少需要三个主节点" 感到困惑,建议先看看其他有关 Redis Cluster 的架构原理文章,了解它的分片机制、选主流程、故障投票机制等。这里就不展开详细解释了哦。

Redis Cluster 是最好的选择吗?

之前有同学会问:是不是用 Redis 就应该上 Cluster,才算架构"高级"?

其实不一定哦。虽然 Redis Cluster 功能强大,但它对部署和运维的要求也更高,比如节点管理、slot 分配、扩容重平衡等都需要经验。

如果项目体量不大,使用单体架构就能满足需求,Redis 也只是用作缓存,偶尔中断不影响主流程,其实没必要一开始就用 Redis Cluster。

在这种情况下,单节点主从 + 哨兵(Sentinel)模式 是更合适、更轻量的选择,既能控制复杂度,也能满足基本的高可用需求。

那什么场景适合使用 Redis 哨兵模式(Sentinel)呢?

Redis Sentinel 是一种更轻量的高可用方案,我们可以在以下场景中使用:

  • 项目规模不大,不需要数据分片,只想实现主从自动切换;
  • 有两三台服务器可用,不想搭建完整的集群结构;
  • 系统更关注稳定性,不太需要横向扩展;
  • 团队对 Redis Cluster 运维经验不多,希望从简。

哨兵模式能自动监控主节点状态,发生故障时可自动切换主从,并通知客户端更新连接,整个过程对业务基本透明。


环境要求 & 部署建议

之前有同学会问:"我只有一台服务器,也能搭 Redis Cluster 吗?"

从技术上讲是可以的。我们也可以在一台机器上通过不同端口启动多个 Redis 实例,手动组建一个 Cluster,但是这种方式只适合本地测试或学习。要知道,它不具备任何高可用性,只要这台机器宕机,整个集群就失效了。

如果是两台服务器,也会存在主从节点集中在同一台机器上的问题,一样无法保障故障转移和数据安全。

正确做法(生产环境推荐)

如果我们的项目部署在多台服务器组成的集群环境中,则更推荐采用分布式的 Redis Cluster 部署方案:

节点 所在服务器
主节点 1 Server A
主节点 2 Server B
主节点 3 Server C
从节点 1 Server D
从节点 2 Server E
从节点 3 Server F

也就是说:3 个主节点 + 3 个从节点,最好部署在 6 台不同的机器上,这样才能实现真正的高可用和故障隔离。

最小高可用方案(3 台机器部署示例)

如果我们的服务器资源有限,也可以将主节点和从节点分布在 3 台机器上,只要确保主节点和它的对应从节点不在同一台机器上,依然可以实现基本的高可用:

  • Server1: 7000 (主A)7003 (从B)
  • Server2: 7001 (主B)7004 (从C)
  • Server3: 7002 (主C)7005 (从A)

这种结构可以保证:即使任意一台机器宕机,仍有主从节点可用,集群不会中断。


搭建 Redis Cluster(三主三从)

废话不多说了,我们现在就开始动手搭建一个简单的 Redis Cluster,用于熟悉和理解原理。

我这里手头有三台云服务器,分别配置了内外网 IP,并提前规划好了主机名(建议统一设置,后续配置和调试会方便很多):

编号 公网 IP 内网 IP 主机名
A 115.159.214.175 172.17.0.11 redis-node-1
B 101.43.14.89 172.17.0.14 redis-node-2
C 124.222.26.59 172.17.0.7 redis-node-3

为了实现最小部署的高可用结构,我们每台服务器都部署两个 Redis 实例:一个主节点、一个从节点。主从交叉分布,避免主从节点部署在同一台机器,确保任意一台服务器宕机不会影响整个集群。

Redis Cluster 节点部署结构如下:

服务器(主机名) Redis 实例端口 节点角色
redis-node-1 7000、7003 主1、从2
redis-node-2 7001、7004 主2、从3
redis-node-3 7002、7005 主3、从1

这个结构可以保证:

  • Redis Cluster 的三个主节点分布在三台服务器;
  • 每个主节点都有一个对应的从节点;
  • 主从节点不在同一台机器上,具备基本的故障隔离能力。

第一步:每台服务器安装 Redis 6.2

首先,我们需要在三台服务器上都安装 Redis。为了保持版本一致,本文以 Redis 6.2.6 为例进行演示。以下命令需要在 每台服务器上执行一次

bash 复制代码
# 安装依赖
yum install -y gcc jemalloc-devel wget make

# 下载 Redis 源码
wget http://download.redis.io/releases/redis-6.2.6.tar.gz

# 解压并进入目录
tar xzf redis-6.2.6.tar.gz && cd redis-6.2.6

# 编译并安装
make && make install

安装完成后,我们可以通过以下命令验证是否成功:

bash 复制代码
redis-server -v

看到 Redis 的版本信息即表示安装成功。

推荐统一使用 Redis 6.x 版本,原因是支持更好的集群特性和内存管理,适合生产环境部署。

第二步:创建 Redis 实例目录和配置文件

接下来,我们为每个 Redis 实例创建独立的工作目录,并生成对应的配置文件。

在每台服务器上,根据实例端口号,先创建好相关目录。例如在 redis-node-1 上:

bash 复制代码
mkdir -p /opt/redis-cluster/7000
mkdir -p /opt/redis-cluster/7003

redis-node-2redis-node-3 上,也请分别创建对应的端口目录,例如:

  • redis-node-2:70017004
  • redis-node-3:70027005

配置 redis.conf 文件

我们可以使用如下命令快速生成配置文件(以 7000 端口为例):

bash 复制代码
cat <<EOF > /opt/redis-cluster/7000/redis.conf
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
protected-mode no
daemonize yes
replica-read-only yes
bind 0.0.0.0
logfile "/var/log/redis_7000.log"
dir /opt/redis-cluster/7000
EOF

需要根据实际端口为每个实例修改 portlogfile 字段,例如:

  • 7001 就写成 port 7001logfile "/var/log/redis_7001.log"
  • 同理处理 7002 ~ 7005 的配置

配置说明我这里简要解释下:

  • cluster-enabled yes:开启 Cluster 模式
  • cluster-config-file:用于保存集群节点状态的本地文件(不用手动创建)
  • appendonly yes:开启 AOF 持久化
  • protected-mode no:关闭保护模式,方便内网通信
  • daemonize yes:后台运行 Redis
  • replica-read-only yes:限制从节点只读
  • bind 0.0.0.0:监听所有网卡,便于跨服务器连接
  • dir:数据和 AOF 文件的存储目录

第三步:启动 Redis 实例

配置完成后,我们需要在每台服务器上启动 Redis 实例。每台机器有两个端口实例,请根据实际路径执行以下命令(以 redis-node-1 为例):

bash 复制代码
redis-server /opt/redis-cluster/7000/redis.conf
redis-server /opt/redis-cluster/7003/redis.conf

在其他服务器上也依次启动:

  • redis-node-270017004
  • redis-node-370027005

启动完成后,可以使用 psnetstat 等命令确认 Redis 是否正常运行:

bash 复制代码
ps -ef | grep redis
netstat -tunlp | grep 7000

如果 Redis 没有启动成功,则需要检查配置文件路径、端口是否被占用、权限是否正确等问题。

第四步:创建 Redis Cluster

Redis 实例都启动后,就可以正式创建集群了。我们只需要在任意一台机器上执行以下命令(推荐在 redis-node-1 上操作),把所有节点的 内网 IP + 端口 列出来:

bash 复制代码
redis-cli --cluster create \
172.17.0.11:7000 \
172.17.0.14:7001 \
172.17.0.7:7002 \
172.17.0.14:7004 \
172.17.0.7:7005 \
172.17.0.11:7003 \
--cluster-replicas 1

执行后会出现一个确认提示,输入 yes 即可完成集群创建。

参数解释:

  • --cluster create:用于初始化集群;
  • 后面列出的 6 个地址:3 个主节点 + 3 个从节点,端口必须和实例一致;
  • --cluster-replicas 1:表示每个主节点会自动分配 1 个从节点,无需手动指定谁是主、谁是从;
  • 主从对应关系、slot 分配(16384 槽)等,都会自动完成,非常方便。

使用内网 IP 是为了避免节点之间跨公网通信,提升连接稳定性(但确保这些 IP 在所有节点间可互通)。

如果看到 [ERR], Unable to connect, 或 CLUSTERDOWN 之类错误,通常是端口未开放、防火墙没关闭或配置写错了。

创建 Redis Cluster 成功后的输出解析

如果我们执行 redis-cli --cluster create ... --cluster-replicas 1 命令,并看到类似如下输出,就说明集群创建成功了。

我们来简单解读一下图片中的关键内容:

  • >>> Performing hash slots allocation on 6 nodes...

    Redis 会自动把 16384 个槽位平均分配给 3 个主节点:

    • Master[0]:Slots 0 - 5460
    • Master[1]:Slots 5461 - 10922
    • Master[2]:Slots 10923 - 16383
  • Adding replica ...

    接下来 Redis 会自动将 3 个从节点分配给主节点,实现主从结构,示例中:

    • 7004 成为 7000 的从节点
    • 7005 成为 7001 的从节点
    • 7003 成为 7002 的从节点
  • Can I set the above configuration? (type 'yes' to accept):

    意思是我们需要输入 yes 确认进行上述分配。

  • >>> Nodes configuration updated

    节点之间完成握手,开始广播集群配置。

  • >>> Performing Cluster Check

    Redis 会做一次完整的检查,包括:

    • 所有主节点是否正确分配了槽位;
    • 每个主节点是否有对应从节点;
    • 所有节点是否达成一致([OK] All nodes agree about slots configuration);
    • 所有槽位是否都覆盖([OK] 16384 slots covered);

一旦看到这些绿色 [OK],就说明集群搭建成功,主从分布正确,槽位分配完整。

第五步:验证 Redis Cluster 状态

集群创建成功后,我们可以通过连接任意一个节点来查看集群状态、测试读写是否正常。

连接节点并查看集群信息

我们可以通过以下命令连接某个 Redis 实例(比如 7000):

bash 复制代码
redis-cli -c -p 7000

进入 Redis 命令行后,执行以下命令查看当前集群状态:

bash 复制代码
127.0.0.1:7000> cluster nodes

集群节点信息解释

执行 cluster nodes 后,会输出当前集群中所有节点的详细状态信息。我们来逐条拆解解释:

172.17.0.14:7001

  • 是一个主节点(master
  • 分配了槽位范围:5461 - 10922
  • @17001 表示 cluster bus 通信端口(7001 + 10000)
  • connected 表示节点状态正常

172.17.0.11:7003

  • 是一个从节点(slave),它的主节点是 f51a4f...,也就是 7002
  • 没有分配槽位(从节点不负责分片)
  • 状态正常

172.17.0.7:7005

  • 从节点,复制的是 7001(即 1ec565...
  • 无槽位,状态正常

172.17.0.11:7000

  • 本地连接节点(myself),也是主节点(master
  • 分配了槽位 0 - 5460

172.17.0.7:7002

  • 主节点,负责槽位 10923 - 16383
  • 状态正常

172.17.0.14:7004

  • 从节点,复制的是 7000(即 5ccaef...
  • 状态正常

从这张图我们可以看出:

  • 有 3 个主节点,分别负责 5461 个槽,正好组成完整的 16384 槽位;
  • 每个主节点都有一个对应的从节点,实现主从容灾;
  • 所有节点都处于 connected 状态,集群稳定可用。

验证 Redis Cluster 的数据读取是否正常

Redis Cluster 的一个核心特性就是:数据是按槽(slot)分片的,每个 key 会根据哈希槽定位到某个主节点上进行存储和访问。

我们来实际验证一下跨节点操作是否能正常工作,并观察 Redis Cluster 是否会自动跳转到正确的节点。

第一步:连接任意节点写入数据

在任意一台服务器上连接 Redis(比如 redis-node-1):

bash 复制代码
redis-cli -c -p 7000

然后写入一条数据:

bash 复制代码
127.0.0.1:7000> set user:1 zhangsan
-> Redirected to slot [10778] located at 172.17.0.14:7001
OK

我们将会看到类似下面的提示(如图所示):

提示含义:

  • user:1 这个 key 被哈希到了槽位 10778
  • Redis 发现当前节点(7000)不负责该槽,自动跳转到 172.17.0.14:7001 节点;
  • 并最终在目标节点成功执行 set 操作,返回 OK
  • 说明自动跳转、分片定位工作正常!

第二步:跨节点读取验证

现在换另一台服务器连接另一个节点(例如 redis-node-37002):

bash 复制代码
redis-cli -c -h 172.17.0.11 -p 7002
172.17.0.11:7002> get user:1
-> Redirected to slot [10778] located at 172.17.0.14:7001
"zhangsan"

Redis 会自动重定向请求,跳转到负责该槽位的主节点上完成读取,结果为 "zhangsan"说明整个集群读写逻辑通畅,节点跳转能力生效


扩容:新增主节点并分配槽位(业务量上升场景)

比如我们后面随着业务量逐渐上升,三主三从的 Redis Cluster 写入压力开始变大。为了提升性能,我们准备 新增一台服务器 172.17.0.3,作为新的主节点,加入到集群中,并分担一部分哈希槽(slot)写入压力。

第一步:在新服务器上部署 Redis 实例

和前面步骤一样,在新服务器(172.17.0.3)上执行:

bash 复制代码
# 安装 Redis(略,可复用之前步骤)

# 创建实例目录
mkdir -p /opt/redis-cluster/7006

# 创建配置文件
cat <<EOF > /opt/redis-cluster/7006/redis.conf
port 7006
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
protected-mode no
daemonize yes
replica-read-only yes
bind 0.0.0.0
logfile "/var/log/redis_7006.log"
dir /opt/redis-cluster/7006
EOF

# 启动 Redis 实例
redis-server /opt/redis-cluster/7006/redis.conf

第二步:将新节点加入 Redis 集群

在任意一个已加入集群的节点上执行 cluster meet 命令,让新节点加入集群:

bash 复制代码
redis-cli -c -p 7000 cluster meet 172.17.0.3 7006

执行完后,新节点会与集群中的其他节点进行握手、通信,成为集群成员,但此时还是一个"空闲节点",没有任何槽位分配

第三步:将槽位迁移一部分到新主节点

Redis 总共有 16384 个槽位,比如我们希望 4 个主节点平摊压力,可以把一部分槽分给新节点,比如 4096 个。

我们可以使用 Redis 提供的集群重分片命令:

bash 复制代码
redis-cli --cluster reshard 172.17.0.3:7006

按照提示依次输入:

  • 要移动的槽位数量:4096
  • 从哪些节点迁移(输入已有主节点的 node id,可以选多个)
  • 是否继续:yes

需要注意:

  • 我们可以输入多个主节点的 node id,表示从它们手中平均分出槽位;
  • 迁移过程会实时搬迁数据,不影响线上业务;
  • 如果想静默执行,可以配合 --cluster-from--cluster-to 选项使用自动模式(进阶玩法);

第四步:验证新节点是否生效

完成 reshard 槽位迁移操作后,我们可以通过以下命令来验证新主节点是否已经成功接管槽位:

bash 复制代码
redis-cli -c -p 7006 cluster nodes

这条命令会列出当前集群中所有节点的信息,包括各节点的角色、状态、以及分配到的哈希槽范围。

下图为执行结果示例:

从上图可以看出,新加入的主节点 172.17.0.3:7006 已成功分配到了多个槽位段:

yaml 复制代码
slots: 0--2389, 7510--8362, 12970--13822

而原有主节点的槽位范围也随之缩减,Redis Cluster 自动完成了数据迁移和状态更新,整个过程无需手动干预、不中断业务。

至此,我们的 Redis 集群已从原来的 3主结构扩容为 4主结构 ,槽位分布更均衡,系统写入能力得到提升,同时集群状态稳定,各节点均处于 connected 状态。


验证 Redis Cluster 主节点故障切换能力

为了验证 Redis Cluster 的高可用性,我们可以手动模拟一个主节点宕机的场景,观察集群是否能自动将从节点切换为主节点,实现故障转移。

步骤一:选择一个主节点并关闭它

比如我们要模拟 7000 这个主节点故障(可以任选一个):

bash 复制代码
redis-cli -p 7000 shutdown

执行后该节点将停止服务,相当于突然"下线"。

步骤二:查看集群状态变化

在任意一个还在线的节点上运行:

bash 复制代码
redis-cli -c -p 7001 cluster nodes

我们应该很快会看到以下变化:

  • 7000 节点状态变成 failhandshake
  • 它的从节点(比如 7004)会被自动提升为新的主节点(状态变为 master
  • 集群整体仍保持 16384 个槽位完整覆盖

它为什么能自动切换?

这是 Redis Cluster 的核心机制:

  • 每个主节点都有至少一个从节点;
  • 当集群中大多数主节点"达成共识"某个主节点下线时,会触发故障转移;
  • 对应的从节点会自动升格为新的主节点,继续对外服务。

步骤三:恢复原主节点

如果我们想恢复 7000 节点,只需重新启动:

bash 复制代码
redis-server /opt/redis-cluster/7000/redis.conf

它会自动以从节点身份加入,并开始同步当前的主节点数据。

通过手动关闭主节点、观察集群自动完成主从切换,我们验证了 Redis Cluster 的高可用能力。即使某个主节点发生故障,只要有可用的从节点,集群依然可以保持正常运行,不影响业务访问。


使用 systemd 管理 Redis 实例(支持自启与自动重启)

为了让 Redis 实例在服务器重启后自动启动、宕机后自动恢复,我们推荐使用 systemd 来管理 Redis 服务。以 Redis 端口 7000 为例,以下是完整配置方式。

步骤一:创建 systemd 启动服务文件

/etc/systemd/system/ 目录下创建服务文件:

bash 复制代码
vim /etc/systemd/system/redis7000.service

写入以下内容:

ini 复制代码
[Unit]
Description=Redis Instance 7000
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/redis-server /opt/redis-cluster/7000/redis.conf
Restart=always
User=root

[Install]
WantedBy=multi-user.target

需要注意:使用 systemd 时,Redis 的配置文件中必须设置 daemonize no,即禁用后台守护进程模式。

因为 systemd 本身负责服务的进程管理,上面我们开启了 daemonize yes,Redis 会在启动后立即 fork 到后台,而 systemd 会误以为服务"秒退",从而反复重启,最终导致启动失败。

步骤二:修改 Redis 配置文件

打开 Redis 配置文件:

bash 复制代码
vim /opt/redis-cluster/7000/redis.conf

确认或修改以下配置项:

ini 复制代码
daemonize no  # 必须为 no,systemd 才能正常管理

步骤三:让服务生效并启动

bash 复制代码
# 重载 systemd 配置
systemctl daemon-reexec

# 启动 Redis 实例
systemctl start redis7000

# 设置服务开机自启
systemctl enable redis7000

# 查看服务状态
systemctl status redis7000

我们现在有多个 Redis 实例(如 70017002),只需复制 redis7000.service,并分别修改对应端口与配置路径即可:

bash 复制代码
cp /etc/systemd/system/redis7000.service /etc/systemd/system/redis7001.service
# 然后修改端口和配置路径

这样配置完成后,Redis 将由 systemd 全面托管,实现开机自启、异常自动重启、集中日志等能力,是我们日常部署上线时比较推荐的做法。

最后:Redis Cluster 搭建只是开始,日常监控才是关键

至此,我们已经完成了一个完整的 Redis Cluster 架构搭建过程,从三主三从起步,到新增主节点扩容,再到 systemd 自启配置,整个流程基本覆盖了实际生产部署中所需的核心操作。

但要注意哦,搭建只是开始,稳定运行才是目标。

在日常运维中我们还需要关注以下几个方面:

  1. 节点健康监控

    • 实时监控每个节点的运行状态(是否在线、角色是否正常)
    • 可以使用 redis-cli cluster nodes 定时巡检,或集成监控系统自动拉取状态
  2. 集群监控与可视化

    • 推荐使用 Prometheus + Grafana 搭配 redis_exporter,实时展示:

      • 节点存活情况
      • 槽位分布是否完整
      • 主从同步延迟
      • 内存使用 / QPS 等性能指标
  3. 故障告警机制

    • 可通过自定义脚本监控节点端口、角色变更、slot coverage 状态
    • 配合钉钉/企业微信 webhook 实现实时告警,节点挂了立刻通知运维或开发人员
  4. 数据持久化与备份策略

    • 建议开启 AOF 或 RDB(甚至两者同时),并定期拷贝数据备份
    • 持久化目录需单独挂载数据盘,防止数据意外清除
  5. 安全性配置

    • 禁止公网暴露 Redis 端口;
    • 设置访问密码;
    • 使用防火墙或安全组限制只允许内网访问;
  6. 容量与扩展规划

    • 监控槽位分布和主节点负载,当某个节点压力明显偏高时及时执行 reshard
    • 支持横向扩容节点,保持服务的弹性和性能;

日常项目里,Redis Cluster 真的是一个挺靠谱的方案,不仅高可用、还能自动分片,主从切换也都帮我们搞定了。特别是像我们这种中等体量的项目,用起来刚刚好。

但真正难的不是搭,而是节点挂了你不知道,生产环境一片寂静,还以为它稳得像狗,实际上早就在默默崩坏🙂 所以,监控和告警真的别省,能响铃就别等出事再查日志。

毕竟如果不加告警出问题的话,你觉得优化项目快,还是老板优化你快?😅

相关推荐
终身学习基地20 分钟前
第一篇:Django简介
后端·python·django
Apifox2 小时前
Apifox 4月更新|Apifox在线文档支持LLMs.txt、评论支持使用@提及成员、支持为团队配置「IP 允许访问名单」
前端·后端·ai编程
我家领养了个白胖胖2 小时前
#和$符号使用场景 注意事项
java·后端·mybatis
寻月隐君2 小时前
如何高效学习一门技术:从知到行的飞轮效应
后端·github
Andya2 小时前
Java | 深拷贝与浅拷贝工具类解析和自定义实现
后端
Andya2 小时前
Java | 基于自定义注解与AOP切面实现数据权限管控的思路和实践
后端
云原生melo荣2 小时前
快速记忆Spring Bean的生命周期
后端·spring
阿里云腾讯云谷歌云AWS代理商_小赵2 小时前
腾讯云国际站:为什么Docker适合部署在云服务器?
后端
Java中文社群2 小时前
大模型向量数据库去重的N种实现方案!
java·人工智能·后端
小奏技术2 小时前
字节最新开源项目CompoundVM-在JDK8上启用JVM17
后端