Docker搭建Redis集群完全指南

[复制链接]
发表于 2026-8-24 15:45:44 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
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 通信
  1. [/code][code]┌──────────────────────────────────────────┐
  2.     │         Docker Bridge Network             │
  3.     │     (redis-cluster-net, 172.28.0.0/16)    │
  4.     └──────────────────────────────────────────┘
  5.         ↑          ↑          ↑          ↑
复制代码
┌────────┴───┐ ┌───┴──────┐ ┌─┴────────┐ ┌─┴────────┐
│ redis-7001 │ │redis-7002│ │redis-7003│ │  ...     │
│   (主)     │ │  (主)    │ │  (主)    │ │redis-7006│
└────────┬───┘ └───┬──────┘ └─┬────────┘ └─┬────────┘
↑          ↑          ↑             ↑
┌────────┴───┐ ┌───┴──────┐ ┌─┴────────┐ ┌─┴────────┐
│ redis-7004 │ │redis-7005│ │redis-7006│ │  (从)    │
│   (从)     │ │  (从)    │ │  (从)    │ │          │
└────────────┘ └──────────┘ └──────────┘ └──────────┘
  1. ### 节点拓扑规划
  2. | 节点序号 | 容器名 | 服务端口 | 集群总线端口 | 初始角色 | 固定 IP |
  3. |----------|--------|----------|--------------|----------|---------|
  4. | 1 | redis-7001 | 7001 | 17001 | 主节点 | 172.28.0.11 |
  5. | 2 | redis-7002 | 7002 | 17002 | 主节点 | 172.28.0.12 |
  6. | 3 | redis-7003 | 7003 | 17003 | 主节点 | 172.28.0.13 |
  7. | 4 | redis-7004 | 7004 | 17004 | 从节点 | 172.28.0.14 |
  8. | 5 | redis-7005 | 7005 | 17005 | 从节点 | 172.28.0.15 |
  9. | 6 | redis-7006 | 7006 | 17006 | 从节点 | 172.28.0.16 |
  10. > **关键概念**:集群总线端口 = 服务端口 + 10000,是节点间心跳同步、故障转移、数据迁移的专用通道。**必须与服务端口一起映射**,否则 `CLUSTER MEET` 直接失败,这是 90% 新手组网踩的第一个坑。
  11. ---
  12. ## 二、落地实操:从 0 到集群
  13. ### Step 1:准备配置文件
  14. 每个节点独立一份 `redis.conf`,以下是生产级完整配置模板(以 7001 节点为例,其余节点仅改端口和 IP):
  15. ```conf
  16. # ========== 基础网络 ==========
  17. bind 0.0.0.0
  18. protected-mode no
  19. port 6379
  20. daemonize no
  21. # ========== 集群核心 ==========
  22. cluster-enabled yes
  23. cluster-config-file nodes.conf
  24. cluster-node-timeout 5000
  25. # 🔥 关键三件套:显式声明对外访问地址,彻底解决 MOVED 重定向到内网/回环地址的问题
  26. cluster-announce-ip 172.28.0.11        # 容器固定 IP
  27. cluster-announce-port 6379             # 容器内服务端口
  28. cluster-announce-bus-port 16379        # 容器内总线端口
  29. # ========== 安全认证(生产必开)==========
  30. # 所有节点密码必须完全一致
  31. requirepass your_redis_pwd
  32. masterauth your_redis_pwd
  33. # ========== 持久化 ==========
  34. appendonly yes
  35. appendfsync everysec
  36. save 900 1
  37. save 300 10
  38. # ========== 内存管理 ==========
  39. maxmemory 400mb
  40. maxmemory-policy allkeys-lru
复制代码
亮点解读:

  • cluster-announce-* 三件套配置:显式声明节点对外地点,防止容器重启后 IP 漂移导致集群脑裂,这是最容易被忽略的关键配置
  • requirepass + masterauth 双保险:前者管控客户端访问,后者保障主从同步和总线通信认证,缺一不可
  • maxmemory + allkeys-lru:前置内存上限和淘汰计谋,防止大 key 或流量突增导致节点 OOM
Step 2:编写 docker-compose.yml
  1. version: '3.8'
  2. # 自定义静态子网,彻底解决容器重启 IP 漂移问题
  3. networks:
  4.   redis-cluster-net:
  5.     driver: bridge
  6.     ipam:
  7.       config:
  8.         - subnet: 172.28.0.0/16
  9. services:
  10.   redis-7001:
  11.     image: redis:7.2.5-alpine
  12.     container_name: redis-7001
  13.     restart: always
  14.     ports:
  15.       - "7001:6379"       # 客户端通信端口
  16.       - "17001:16379"     # 集群总线端口(Gossip 协议专用)
  17.     volumes:
  18.       - ./cluster/7001/redis.conf:/etc/redis/redis.conf
  19.       - ./cluster/7001/data:/data    # 全量挂载:含 AOF/RDB + 集群元数据 nodes.conf
  20.     networks:
  21.       redis-cluster-net:
  22.         ipv4_address: 172.28.0.11
  23.     mem_limit: 512m       # 资源配额,防止单节点 OOM 拖垮宿主机
  24.     cpus: "0.5"
  25.     command: redis-server /etc/redis/redis.conf
  26.   redis-7002:
  27.     image: redis:7.2.5-alpine
  28.     container_name: redis-7002
  29.     restart: always
  30.     ports:
  31.       - "7002:6379"
  32.       - "17002:16379"
  33.     volumes:
  34.       - ./cluster/7002/redis.conf:/etc/redis/redis.conf
  35.       - ./cluster/7002/data:/data
  36.     networks:
  37.       redis-cluster-net:
  38.         ipv4_address: 172.28.0.12
  39.     mem_limit: 512m
  40.     cpus: "0.5"
  41.     command: redis-server /etc/redis/redis.conf
  42.   redis-7003:
  43.     image: redis:7.2.5-alpine
  44.     container_name: redis-7003
  45.     restart: always
  46.     ports:
  47.       - "7003:6379"
  48.       - "17003:16379"
  49.     volumes:
  50.       - ./cluster/7003/redis.conf:/etc/redis/redis.conf
  51.       - ./cluster/7003/data:/data
  52.     networks:
  53.       redis-cluster-net:
  54.         ipv4_address: 172.28.0.13
  55.     mem_limit: 512m
  56.     cpus: "0.5"
  57.     command: redis-server /etc/redis/redis.conf
  58.   redis-7004:
  59.     image: redis:7.2.5-alpine
  60.     container_name: redis-7004
  61.     restart: always
  62.     ports:
  63.       - "7004:6379"
  64.       - "17004:16379"
  65.     volumes:
  66.       - ./cluster/7004/redis.conf:/etc/redis/redis.conf
  67.       - ./cluster/7004/data:/data
  68.     networks:
  69.       redis-cluster-net:
  70.         ipv4_address: 172.28.0.14
  71.     mem_limit: 512m
  72.     cpus: "0.5"
  73.     command: redis-server /etc/redis/redis.conf
  74.   redis-7005:
  75.     image: redis:7.2.5-alpine
  76.     container_name: redis-7005
  77.     restart: always
  78.     ports:
  79.       - "7005:6379"
  80.       - "17005:16379"
  81.     volumes:
  82.       - ./cluster/7005/redis.conf:/etc/redis/redis.conf
  83.       - ./cluster/7005/data:/data
  84.     networks:
  85.       redis-cluster-net:
  86.         ipv4_address: 172.28.0.15
  87.     mem_limit: 512m
  88.     cpus: "0.5"
  89.     command: redis-server /etc/redis/redis.conf
  90.   redis-7006:
  91.     image: redis:7.2.5-alpine
  92.     container_name: redis-7006
  93.     restart: always
  94.     ports:
  95.       - "7006:6379"
  96.       - "17006:16379"
  97.     volumes:
  98.       - ./cluster/7006/redis.conf:/etc/redis/redis.conf
  99.       - ./cluster/7006/data:/data
  100.     networks:
  101.       redis-cluster-net:
  102.         ipv4_address: 172.28.0.16
  103.     mem_limit: 512m
  104.     cpus: "0.5"
  105.     command: redis-server /etc/redis/redis.conf
复制代码
配置亮点总结:
设计点办理的问题自界说静态子网 + 固定 IP 分配容器重启后 IP 漂移导致集群节点失联双端口严酷映射(服务 + 总线)覆盖服务访问与 Gossip 通信两条核心链路配置与数据双目录挂载持久化 nodes.conf 集群身份元数据,容器重建不丢失节点身份内存/CPU 资源配额避免单节点 OOM 挤占宿主机资源alpine 精简镜像 + always 自愈兼顾镜像体积与服务可用性Step 3:启动容器 & 一键组建集群
  1. # 启动所有容器
  2. docker-compose up -d
  3. # 等待节点完全启动
  4. sleep 10
  5. # 一键创建集群(--cluster-yes 跳过交互确认,适配 CI/CD)
  6. docker exec -it redis-7001 redis-cli --cluster create \
  7.   172.28.0.11:6379 \
  8.   172.28.0.12:6379 \
  9.   172.28.0.13:6379 \
  10.   172.28.0.14:6379 \
  11.   172.28.0.15:6379 \
  12.   172.28.0.16:6379 \
  13.   --cluster-replicas 1 \
  14.   --cluster-yes
复制代码
Redis 会自动分配主从关系和 16384 个哈希槽,输出类似:
  1. >>> Performing hash slots allocation on 6 nodes...
  2. Master[0] -> Slots 0 - 5460
  3. Master[1] -> Slots 5461 - 10922
  4. Master[2] -> Slots 10923 - 16383
  5. Adding replica ...
  6. [OK] All nodes agree about slots configuration.
复制代码
致命提示:组网命令中 绝对不能用 127.0.0.1,必须填写宿主机真实 IP 或容器固定 IP。否则节点会把集群地点注册为本地回环,跨节点通信直接失败。
Step 4:验证集群状态
  1. # 查看集群节点(确认 3 master + 3 slave)
  2. redis-cli -h 127.0.0.1 -p 7001 cluster nodes
  3. # 查看槽位分布
  4. redis-cli -h 127.0.0.1 -p 7001 cluster slots
  5. # 读写验证(-c 开启集群重定向)
  6. redis-cli -c -h 127.0.0.1 -p 7001 -a your_redis_pwd set foo bar
复制代码
能正常重定向并返回 OK,说明分片和迁移机制工作正常。
三、生产级自动化部署脚本

以下脚本集成了 连通性预检 → 自动组网 → 健康校验 全流程,可直接接入 CI/CD 流水线:
  1. #!/bin/bash
  2. # ========== 全局变量 ==========
  3. HOST_IP="宿主机真实IP"
  4. PASSWORD="your_redis_pwd"
  5. START_PORT=7001
  6. NODE_COUNT=6
  7. # ========== 前置校验:全节点连通性检测 ==========
  8. echo "🔍 开始校验所有节点连通性..."
  9. for ((i=0; i<NODE_COUNT; i++))
  10. do
  11.   port=$((START_PORT + i))
  12.   if ! redis-cli -h $HOST_IP -p $port -a $PASSWORD ping > /dev/null 2>&1; then
  13.     echo "❌ 节点$port 连通失败,请检查配置!"
  14.     exit 1
  15.   fi
  16.   echo "✅ 节点$port 连通正常"
  17. done
  18. # ========== 非交互式组建集群 ==========
  19. echo "🚀 开始组建 Redis 集群..."
  20. echo "yes" | redis-cli -a $PASSWORD --cluster create \
  21.   $HOST_IP:7001 $HOST_IP:7002 $HOST_IP:7003 \
  22.   $HOST_IP:7004 $HOST_IP:7005 $HOST_IP:7006 \
  23.   --cluster-replicas 1
  24. # ========== 组网后健康校验 ==========
  25. if [ $? -eq 0 ]; then
  26.   echo "🎉 集群组建成功!集群状态:"
  27.   redis-cli -h $HOST_IP -p 7001 -a $PASSWORD cluster info | grep cluster_state
  28. else
  29.   echo "❌ 集群组建失败,请排查节点日志日志!"
  30.   exit 1
  31. fi
复制代码
脚本亮点:

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

集群搭好了,应用端怎么连?以下是 Spring Boot + Lettuce 的生产级配置:
  1. # application.yml
  2. spring:
  3.   redis:
  4.     cluster:
  5.       nodes:
  6.         - 192.168.1.100:7001
  7.         - 192.168.1.100:7002
  8.         - 192.168.1.100:7003
  9.         - 192.168.1.100:7004
  10.         - 192.168.1.100:7005
  11.         - 192.168.1.100:7006
  12.     password: your_redis_pwd
  13.     lettuce:
  14.       pool:
  15.         max-active: 20
  16.         max-idle: 10
  17.       cluster:
  18.         refresh:
  19.           adaptive: true       # 自适应拓扑刷新
  20.           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.12集群总线端口未映射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_state、cluster_slots_fail六、生产环境进阶建议

持久化计谋


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

接入 redis-exporter + Prometheus + Grafana,核心告警规则:
  1. # 典型告警规则
  2. - alert: RedisClusterDown
  3.   expr: redis_cluster_state != 1
  4.   for: 1m
  5.   labels:
  6.     severity: critical
  7.   annotations:
  8.     summary: "Redis 集群状态异常"
  9. - alert: RedisClusterSlotsFail
  10.   expr: redis_cluster_slots_fail > 0
  11.   for: 30s
  12.   labels:
  13.     severity: warning
  14.   annotations:
  15.     summary: "Redis 集群存在失败槽位"
复制代码
重点监控指标:cluster_state、cluster_slots_fail、cluster_known_nodes、各节点内存使用率。
动态扩缩容


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

手动停止一个主节点容器,观察从节点是否自动提升为主;原主节点恢复后应自动转为从节点。假如失败,优先排查 masterauth 配置和暗码同等性。
七、整体架构全景图


总结

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

  • 端口双开:服务端口 + 集群总线端口(+10000),缺一不可
  • IP 固定:静态子网 + 固定 IP 分配,或 cluster-announce-ip 显式声明,杜绝 IP 漂移
  • 暗码统一:requirepass + masterauth 全节点同等,保障故障转移正常
  • 数据持久化:完整挂载数据目录,持久化 nodes.conf + AOF/RDB
  • 客户端适配:开启集群拓扑刷新(Lettuce adaptive),正确处置惩罚 MOVED 重定向
掌握这五点,无论是面试回答还是生产落地,都能稳扎稳打。
个人博客“www.javadashen.com”
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表