背景
在我之前的一家公司,曾负责一个中等体量的项目。虽然业务量不大,但为了确保系统具备良好的扩展性和可用性,我们整体采用了集群架构。其中数据库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-2
和 redis-node-3
上,也请分别创建对应的端口目录,例如:
- redis-node-2:
7001
和7004
- redis-node-3:
7002
和7005
配置 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
需要根据实际端口为每个实例修改 port
和 logfile
字段,例如:
7001
就写成port 7001
、logfile "/var/log/redis_7001.log"
- 同理处理
7002 ~ 7005
的配置
配置说明我这里简要解释下:
cluster-enabled yes
:开启 Cluster 模式cluster-config-file
:用于保存集群节点状态的本地文件(不用手动创建)appendonly yes
:开启 AOF 持久化protected-mode no
:关闭保护模式,方便内网通信daemonize yes
:后台运行 Redisreplica-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-2
:7001
、7004
redis-node-3
:7002
、7005
启动完成后,可以使用 ps
或 netstat
等命令确认 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
- Master[0]:Slots
-
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-3
的 7002
):
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
节点状态变成fail
或handshake
- 它的从节点(比如
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 实例(如 7001
、7002
),只需复制 redis7000.service
,并分别修改对应端口与配置路径即可:
bash
cp /etc/systemd/system/redis7000.service /etc/systemd/system/redis7001.service
# 然后修改端口和配置路径
这样配置完成后,Redis 将由 systemd 全面托管,实现开机自启、异常自动重启、集中日志等能力,是我们日常部署上线时比较推荐的做法。
最后:Redis Cluster 搭建只是开始,日常监控才是关键
至此,我们已经完成了一个完整的 Redis Cluster 架构搭建过程,从三主三从起步,到新增主节点扩容,再到 systemd 自启配置,整个流程基本覆盖了实际生产部署中所需的核心操作。
但要注意哦,搭建只是开始,稳定运行才是目标。
在日常运维中我们还需要关注以下几个方面:
-
节点健康监控
- 实时监控每个节点的运行状态(是否在线、角色是否正常)
- 可以使用
redis-cli cluster nodes
定时巡检,或集成监控系统自动拉取状态
-
集群监控与可视化
-
推荐使用
Prometheus + Grafana
搭配redis_exporter
,实时展示:- 节点存活情况
- 槽位分布是否完整
- 主从同步延迟
- 内存使用 / QPS 等性能指标
-
-
故障告警机制
- 可通过自定义脚本监控节点端口、角色变更、slot coverage 状态
- 配合钉钉/企业微信 webhook 实现实时告警,节点挂了立刻通知运维或开发人员
-
数据持久化与备份策略
- 建议开启 AOF 或 RDB(甚至两者同时),并定期拷贝数据备份
- 持久化目录需单独挂载数据盘,防止数据意外清除
-
安全性配置
- 禁止公网暴露 Redis 端口;
- 设置访问密码;
- 使用防火墙或安全组限制只允许内网访问;
-
容量与扩展规划
- 监控槽位分布和主节点负载,当某个节点压力明显偏高时及时执行
reshard
; - 支持横向扩容节点,保持服务的弹性和性能;
- 监控槽位分布和主节点负载,当某个节点压力明显偏高时及时执行
日常项目里,Redis Cluster 真的是一个挺靠谱的方案,不仅高可用、还能自动分片,主从切换也都帮我们搞定了。特别是像我们这种中等体量的项目,用起来刚刚好。
但真正难的不是搭,而是节点挂了你不知道,生产环境一片寂静,还以为它稳得像狗,实际上早就在默默崩坏🙂 所以,监控和告警真的别省,能响铃就别等出事再查日志。
毕竟如果不加告警出问题的话,你觉得优化项目快,还是老板优化你快?😅