Docker搭建Redis集群完全指南

Docker 搭建 Redis 集群完全指南:从原理到生产落地,踩坑实录

一篇讲透 Docker 环境下 Redis Cluster 的搭建、调优与生产级实战。含完整代码、避坑清单和 Spring Boot 接入方案,收藏即可复用。


为什么需要这篇?

Redis 集群是后端面试的高频考点,也是生产环境的高可用基石。但网上的教程大多停留在「跑通 demo」层面,真正落地时你会遇到:容器重启后集群崩溃、客户端被 MOVED 重定向到 127.0.0.1、从节点无法自动晋升......

这篇文章把 设计思路、完整代码、核心踩坑、生产调优、应用接入 一次讲清楚。所有代码均可直接复制使用。


一、整体架构设计

采用 Redis Cluster 原生方案 + Docker Compose 编排 ,最小高可用规格为 3 主 3 从共 6 节点

  • 3 个主节点分担 16384 个哈希槽,负责读写
  • 3 个从节点分别与主节点一一对应,提供故障转移能力
  • 通过 Docker 自定义桥接网络实现容器间固定 IP 通信
复制代码
复制代码
┌──────────────────────────────────────────┐
    │         Docker Bridge Network             │
    │     (redis-cluster-net, 172.28.0.0/16)    │
    └──────────────────────────────────────────┘
        ↑          ↑          ↑          ↑

┌────────┴───┐ ┌───┴──────┐ ┌─┴────────┐ ┌─┴────────┐

│ redis-7001 │ │redis-7002│ │redis-7003│ │ ... │

│ (主) │ │ (主) │ │ (主) │ │redis-7006│

└────────┬───┘ └───┬──────┘ └─┬────────┘ └─┬────────┘

↑ ↑ ↑ ↑

┌────────┴───┐ ┌───┴──────┐ ┌─┴────────┐ ┌─┴────────┐

│ redis-7004 │ │redis-7005│ │redis-7006│ │ (从) │

│ (从) │ │ (从) │ │ (从) │ │ │

└────────────┘ └──────────┘ └──────────┘ └──────────┘

复制代码
### 节点拓扑规划

| 节点序号 | 容器名 | 服务端口 | 集群总线端口 | 初始角色 | 固定 IP |
|----------|--------|----------|--------------|----------|---------|
| 1 | redis-7001 | 7001 | 17001 | 主节点 | 172.28.0.11 |
| 2 | redis-7002 | 7002 | 17002 | 主节点 | 172.28.0.12 |
| 3 | redis-7003 | 7003 | 17003 | 主节点 | 172.28.0.13 |
| 4 | redis-7004 | 7004 | 17004 | 从节点 | 172.28.0.14 |
| 5 | redis-7005 | 7005 | 17005 | 从节点 | 172.28.0.15 |
| 6 | redis-7006 | 7006 | 17006 | 从节点 | 172.28.0.16 |

> **关键概念**:集群总线端口 = 服务端口 + 10000,是节点间心跳同步、故障转移、数据迁移的专用通道。**必须与服务端口一起映射**,否则 `CLUSTER MEET` 直接失败,这是 90% 新手组网踩的第一个坑。

---

## 二、落地实操:从 0 到集群

### Step 1:准备配置文件

每个节点独立一份 `redis.conf`,以下是生产级完整配置模板(以 7001 节点为例,其余节点仅改端口和 IP):

```conf
# ========== 基础网络 ==========
bind 0.0.0.0
protected-mode no
port 6379
daemonize no

# ========== 集群核心 ==========
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000

# 🔥 关键三件套:显式声明对外访问地址,彻底解决 MOVED 重定向到内网/回环地址的问题
cluster-announce-ip 172.28.0.11        # 容器固定 IP
cluster-announce-port 6379             # 容器内服务端口
cluster-announce-bus-port 16379        # 容器内总线端口

# ========== 安全认证(生产必开)==========
# 所有节点密码必须完全一致
requirepass your_redis_pwd
masterauth your_redis_pwd

# ========== 持久化 ==========
appendonly yes
appendfsync everysec
save 900 1
save 300 10

# ========== 内存管理 ==========
maxmemory 400mb
maxmemory-policy allkeys-lru

亮点解读:

  • cluster-announce-* 三件套配置:显式声明节点对外地址,防止容器重启后 IP 漂移导致集群脑裂,这是最容易被忽略的关键配置
  • requirepass + masterauth 双保险:前者管控客户端访问,后者保障主从同步和总线通信认证,缺一不可
  • maxmemory + allkeys-lru:前置内存上限和淘汰策略,防止大 key 或流量突增导致节点 OOM

整理了面试真题、每日技术知识点、系统学习路线,√X搜「Rain的Java 大神之路」

每天拆一个知识点,陪你悄悄变强,有空来坐坐。


Step 2:编写 docker-compose.yml

yaml 复制代码
version: '3.8'

# 自定义静态子网,彻底解决容器重启 IP 漂移问题
networks:
  redis-cluster-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16

services:
  redis-7001:
    image: redis:7.2.5-alpine
    container_name: redis-7001
    restart: always
    ports:
      - "7001:6379"       # 客户端通信端口
      - "17001:16379"     # 集群总线端口(Gossip 协议专用)
    volumes:
      - ./cluster/7001/redis.conf:/etc/redis/redis.conf
      - ./cluster/7001/data:/data    # 全量挂载:含 AOF/RDB + 集群元数据 nodes.conf
    networks:
      redis-cluster-net:
        ipv4_address: 172.28.0.11
    mem_limit: 512m       # 资源配额,防止单节点 OOM 拖垮宿主机
    cpus: "0.5"
    command: redis-server /etc/redis/redis.conf

  redis-7002:
    image: redis:7.2.5-alpine
    container_name: redis-7002
    restart: always
    ports:
      - "7002:6379"
      - "17002:16379"
    volumes:
      - ./cluster/7002/redis.conf:/etc/redis/redis.conf
      - ./cluster/7002/data:/data
    networks:
      redis-cluster-net:
        ipv4_address: 172.28.0.12
    mem_limit: 512m
    cpus: "0.5"
    command: redis-server /etc/redis/redis.conf

  redis-7003:
    image: redis:7.2.5-alpine
    container_name: redis-7003
    restart: always
    ports:
      - "7003:6379"
      - "17003:16379"
    volumes:
      - ./cluster/7003/redis.conf:/etc/redis/redis.conf
      - ./cluster/7003/data:/data
    networks:
      redis-cluster-net:
        ipv4_address: 172.28.0.13
    mem_limit: 512m
    cpus: "0.5"
    command: redis-server /etc/redis/redis.conf

  redis-7004:
    image: redis:7.2.5-alpine
    container_name: redis-7004
    restart: always
    ports:
      - "7004:6379"
      - "17004:16379"
    volumes:
      - ./cluster/7004/redis.conf:/etc/redis/redis.conf
      - ./cluster/7004/data:/data
    networks:
      redis-cluster-net:
        ipv4_address: 172.28.0.14
    mem_limit: 512m
    cpus: "0.5"
    command: redis-server /etc/redis/redis.conf

  redis-7005:
    image: redis:7.2.5-alpine
    container_name: redis-7005
    restart: always
    ports:
      - "7005:6379"
      - "17005:16379"
    volumes:
      - ./cluster/7005/redis.conf:/etc/redis/redis.conf
      - ./cluster/7005/data:/data
    networks:
      redis-cluster-net:
        ipv4_address: 172.28.0.15
    mem_limit: 512m
    cpus: "0.5"
    command: redis-server /etc/redis/redis.conf

  redis-7006:
    image: redis:7.2.5-alpine
    container_name: redis-7006
    restart: always
    ports:
      - "7006:6379"
      - "17006:16379"
    volumes:
      - ./cluster/7006/redis.conf:/etc/redis/redis.conf
      - ./cluster/7006/data:/data
    networks:
      redis-cluster-net:
        ipv4_address: 172.28.0.16
    mem_limit: 512m
    cpus: "0.5"
    command: redis-server /etc/redis/redis.conf

配置亮点总结:

设计点 解决的问题
自定义静态子网 + 固定 IP 分配 容器重启后 IP 漂移导致集群节点失联
双端口严格映射(服务 + 总线) 覆盖服务访问与 Gossip 通信两条核心链路
配置与数据双目录挂载 持久化 nodes.conf 集群身份元数据,容器重建不丢失节点身份
内存/CPU 资源配额 避免单节点 OOM 挤占宿主机资源
alpine 精简镜像 + always 自愈 兼顾镜像体积与服务可用性

Step 3:启动容器 & 一键组建集群

bash 复制代码
# 启动所有容器
docker-compose up -d

# 等待节点完全启动
sleep 10

# 一键创建集群(--cluster-yes 跳过交互确认,适配 CI/CD)
docker exec -it redis-7001 redis-cli --cluster create \
  172.28.0.11:6379 \
  172.28.0.12:6379 \
  172.28.0.13:6379 \
  172.28.0.14:6379 \
  172.28.0.15:6379 \
  172.28.0.16:6379 \
  --cluster-replicas 1 \
  --cluster-yes

Redis 会自动分配主从关系和 16384 个哈希槽,输出类似:

复制代码
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica ...
[OK] All nodes agree about slots configuration.

致命提醒 :组网命令中 绝对不能用 127.0.0.1,必须填写宿主机真实 IP 或容器固定 IP。否则节点会把集群地址注册为本地回环,跨节点通信直接失败。

Step 4:验证集群状态

bash 复制代码
# 查看集群节点(确认 3 master + 3 slave)
redis-cli -h 127.0.0.1 -p 7001 cluster nodes

# 查看槽位分布
redis-cli -h 127.0.0.1 -p 7001 cluster slots

# 读写验证(-c 开启集群重定向)
redis-cli -c -h 127.0.0.1 -p 7001 -a your_redis_pwd set foo bar

能正常重定向并返回 OK,说明分片和迁移机制工作正常。


三、生产级自动化部署脚本

以下脚本集成了 连通性预检 → 自动组网 → 健康校验 全流程,可直接接入 CI/CD 流水线:

bash 复制代码
#!/bin/bash
# ========== 全局变量 ==========
HOST_IP="宿主机真实IP"
PASSWORD="your_redis_pwd"
START_PORT=7001
NODE_COUNT=6

# ========== 前置校验:全节点连通性检测 ==========
echo "🔍 开始校验所有节点连通性..."
for ((i=0; i<NODE_COUNT; i++))
do
  port=$((START_PORT + i))
  if ! redis-cli -h $HOST_IP -p $port -a $PASSWORD ping > /dev/null 2>&1; then
    echo "❌ 节点$port 连通失败,请检查配置!"
    exit 1
  fi
  echo "✅ 节点$port 连通正常"
done

# ========== 非交互式组建集群 ==========
echo "🚀 开始组建 Redis 集群..."
echo "yes" | redis-cli -a $PASSWORD --cluster create \
  $HOST_IP:7001 $HOST_IP:7002 $HOST_IP:7003 \
  $HOST_IP:7004 $HOST_IP:7005 $HOST_IP:7006 \
  --cluster-replicas 1

# ========== 组网后健康校验 ==========
if [ $? -eq 0 ]; then
  echo "🎉 集群组建成功!集群状态:"
  redis-cli -h $HOST_IP -p 7001 -a $PASSWORD cluster info | grep cluster_state
else
  echo "❌ 集群组建失败,请排查节点日志!"
  exit 1
fi

脚本亮点:

  • 前置连通性校验:提前拦截端口不通、密码错误等基础问题,避免组网中途异常
  • --cluster-yes 非交互模式:无需人工确认,直接接入自动化部署流水线
  • 组网后自动健康校验:快速输出集群状态,降低部署后验证成本

四、Spring Boot 接入 Redis 集群

集群搭好了,应用端怎么连?以下是 Spring Boot + Lettuce 的生产级配置:

yaml 复制代码
# application.yml
spring:
  redis:
    cluster:
      nodes:
        - 192.168.1.100:7001
        - 192.168.1.100:7002
        - 192.168.1.100:7003
        - 192.168.1.100:7004
        - 192.168.1.100:7005
        - 192.168.1.100:7006
    password: your_redis_pwd
    lettuce:
      pool:
        max-active: 20
        max-idle: 10
      cluster:
        refresh:
          adaptive: true       # 自适应拓扑刷新
          period: 30s          # 定时刷新周期

关键配置解读:

  • adaptive: true:开启自适应拓扑刷新,当集群发生扩缩容或故障转移时,客户端自动感知新拓扑,无需重启
  • period: 30s:定时兜底刷新,防止自适应事件丢失
  • 使用 Lettuce 而非 Jedis:Lettuce 原生支持集群拓扑刷新和连接池共享,线程安全,高并发场景性能更优

五、核心踩坑与技术难点

这是全文最值钱的部分------每一个都是真实踩过的坑:

序号 技术难点 问题表现 根因 解决方案
1 集群 IP 寻址异常(最高频) 客户端报 MOVED 127.0.0.1;跨节点迁移失败;心跳失联 Redis 默认注册容器内网 IP/回环地址,外部无法路由 配置 cluster-announce-ip 显式声明对外 IP;组网命令禁用 127.0.0.1
2 集群总线端口未映射 CLUSTER MEET 超时,Gossip 协议不通 只映射了服务端口,遗漏了总线端口 每个节点同时暴露服务端口和总线端口(+10000),防火墙一并放行
3 自动故障转移失效 主节点宕机,从节点无法晋升,集群只读 仅配了 requirepass,未配 masterauth;或各节点密码不一致 所有节点同时配置 requirepass + masterauth,密码全集群统一
4 容器重启后集群崩溃 节点丢失集群身份,槽位数据不可用 nodes.conf 未持久化,容器重建后生成新节点 ID 数据目录完整挂载到宿主机;搭配静态 IP,避免 IP 漂移
5 跨宿主机网络不通 多服务器部署时节点无法建立心跳 Docker bridge 网络为宿主机隔离,容器 IP 无法跨主机路由 方案一:cluster-announce-ip + 宿主机端口映射;方案二:Docker Overlay 跨主机网络
6 单宿主机脑裂风险 宿主机宕机全集群不可用 3 个主节点全在同一台机器,不满足「半数以上存活」选举规则 生产环境必须跨 3 台及以上宿主机部署主节点
7 在线扩缩容阻塞 reshard 迁移槽位时请求超时 大 key 迁移或业务高峰期操作 指定 --cluster-timeout,使用 pipeline 批量迁移,选择低峰期操作
8 监控盲区 集群出问题后才发现,定位困难 缺少监控体系 接入 redis-exporter + Prometheus + Grafana,重点监控 cluster_statecluster_slots_fail

六、生产环境进阶建议

持久化策略

  • 开启 appendonly yes + appendfsync everysec,兼顾性能与安全
  • 可叠加 aof-use-rdb-preamble yes 混合持久化,加速重启恢复
  • 配合 save 900 1 / save 300 10 RDB 快照,双保险

监控告警

接入 redis-exporter + Prometheus + Grafana,核心告警规则:

yaml 复制代码
# 典型告警规则
- alert: RedisClusterDown
  expr: redis_cluster_state != 1
  for: 1m
  labels:
    severity: critical
  annotations:
    summary: "Redis 集群状态异常"

- alert: RedisClusterSlotsFail
  expr: redis_cluster_slots_fail > 0
  for: 30s
  labels:
    severity: warning
  annotations:
    summary: "Redis 集群存在失败槽位"

重点监控指标:cluster_statecluster_slots_failcluster_known_nodes、各节点内存使用率。

动态扩缩容

  • 扩容redis-cli --cluster add-node 加入新节点 → reshard 迁移槽位
  • 缩容 :先 rebalance 迁移槽位 → 再 del-node 移除节点,全程在线不中断
  • K8s 环境:生产建议使用 StatefulSet + Headless Service,让 Redis Cluster 自行管理节点 IP

故障转移验证

手动停止一个主节点容器,观察从节点是否自动晋升为主;原主节点恢复后应自动转为从节点。如果失败,优先排查 masterauth 配置和密码一致性。


七、整体架构全景图


总结

Docker + Compose 搭建 Redis Cluster,核心抓住 五个关键点

  1. 端口双开:服务端口 + 集群总线端口(+10000),缺一不可
  2. IP 固定 :静态子网 + 固定 IP 分配,或 cluster-announce-ip 显式声明,杜绝 IP 漂移
  3. 密码统一requirepass + masterauth 全节点一致,保障故障转移正常
  4. 数据持久化 :完整挂载数据目录,持久化 nodes.conf + AOF/RDB
  5. 客户端适配 :开启集群拓扑刷新(Lettuce adaptive),正确处理 MOVED 重定向

掌握这五点,无论是面试回答还是生产落地,都能稳扎稳打。


整理了面试真题、每日技术知识点、系统学习路线,√X搜「Rain的Java 大神之路」

每天拆一个知识点,陪你悄悄变强,有空来坐坐。

相关推荐
大鹏说大话1 小时前
PHP 微服务架构实战:从单体应用到分布式系统的演进之路
微服务·架构·php
智购科技无人售货机厂家1 小时前
2026自动售货机远程运维平台设计:从设备诊断到预测性维护的工程实践~YH
运维·python·物联网·架构·django·scikit-learn
Raas1001 小时前
大模型网关和API网关区别是什么?MAI Gateway统一AI流量治理
java·大数据·运维·人工智能·gateway·企业级·ai网关
jj_ccwgw1 小时前
Kafka KRaft 多机集群安装指南
后端
BioRunYiXue1 小时前
RACE技术全攻略:从全长克隆到靶基因验证
java·javascript·网络·人工智能·科技·算法·eclipse
小蒜学长1 小时前
基于Django的社区团购购物平台的设计与实现(代码+数据库+LW)
数据库·后端·python·django
灯澜忆梦1 小时前
【基于GO的Web开发9】gin框架返回json
前端·后端·golang·gin
AC赳赳老秦1 小时前
个保法下数据处理:OpenClaw 自动过滤公开数据中的个人信息,保障采集分析合规性
java·python·sqlite·json·php·deepseek·openclaw
延凡科技1 小时前
从 “黑灯工厂“ 到 “数字孪生“:智慧工厂平台落地实践
大数据·物联网·架构·数字孪生