Redis分片集群

Redis分片集群

概述

Redis 分片集群(Redis Cluster)通过数据分片实现水平扩展,支持高可用和故障自动转移。本文档涵盖三主三从集群的部署、缩容、扩容、备份与恢复操作。

核心概念

  • 数据分片:16384 个哈希槽均匀分布在各主节点
  • 主从复制:每个主节点至少一个从节点,实现高可用
  • 故障转移:主节点故障时从节点自动提升为主节点
  • 无中心架构:所有节点均可接收请求并路由到正确节点

适用场景

  • 大规模数据存储需要水平扩展
  • 高并发读写需要负载均衡
  • 需要自动故障转移的高可用架构

部署

1. 创建 Docker Compose 编排文件

docker-compose.yaml(三主三从配置):

services:
  redis-node-1:
    image: docker.io/redis:5.0.5
    container_name: redis-node-1
    command: redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --cluster-migration-barrier 1
      --cluster-require-full-coverage no
      --appendonly yes
      --port 17001
      --requirepass moxigame
      --masterauth moxigame
    network_mode: host
    volumes:
      - ./data/node-1:/data
    restart: unless-stopped

  redis-node-2:
    image: docker.io/redis:5.0.5
    container_name: redis-node-2
    command: redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --cluster-migration-barrier 1
      --cluster-require-full-coverage no
      --appendonly yes
      --port 17002
      --requirepass moxigame
      --masterauth moxigame
    network_mode: host
    volumes:
      - ./data/node-2:/data
    restart: unless-stopped

  redis-node-3:
    image: docker.io/redis:5.0.5
    container_name: redis-node-3
    command: redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --cluster-migration-barrier 1
      --cluster-require-full-coverage no
      --appendonly yes
      --port 17003
      --requirepass moxigame
      --masterauth moxigame
    network_mode: host
    volumes:
      - ./data/node-3:/data
    restart: unless-stopped

  redis-node-4:
    image: docker.io/redis:5.0.5
    container_name: redis-node-4
    command: redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --cluster-migration-barrier 1
      --cluster-require-full-coverage no
      --appendonly yes
      --port 17004
      --requirepass moxigame
      --masterauth moxigame
    network_mode: host
    volumes:
      - ./data/node-4:/data
    restart: unless-stopped

  redis-node-5:
    image: docker.io/redis:5.0.5
    container_name: redis-node-5
    command: redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --cluster-migration-barrier 1
      --cluster-require-full-coverage no
      --appendonly yes
      --port 17005
      --requirepass moxigame
      --masterauth moxigame
    network_mode: host
    volumes:
      - ./data/node-5:/data
    restart: unless-stopped

  redis-node-6:
    image: docker.io/redis:5.0.5
    container_name: redis-node-6
    command: redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --cluster-migration-barrier 1
      --cluster-require-full-coverage no
      --appendonly yes
      --port 17006
      --requirepass moxigame
      --masterauth moxigame
    network_mode: host
    volumes:
      - ./data/node-6:/data
    restart: unless-stopped

2. 启动服务

docker compose up -d

查看启动状态:

docker compose ps

3. 创建集群

redis-cli -a moxigame --cluster create \
  10.0.1.247:17001 10.0.1.247:17002 10.0.1.247:17003 \
  10.0.1.247:17004 10.0.1.247:17005 10.0.1.247:17006 \
  --cluster-replicas 1 --cluster-yes

参数说明

  • --cluster-replicas 1:每个主节点分配 1 个从节点
  • --cluster-yes:自动确认集群创建
  • -a moxigame:认证密码

4. 验证集群状态

redis-cli -a moxigame -c -p 17001 cluster info
redis-cli -a moxigame -c -p 17001 cluster nodes

缩容

缩容从节点

# 1. 查看节点列表,获取要删除的从节点 ID
redis-cli -a moxigame -c -p 17001 cluster nodes | grep 17004

# 2. 删除从节点
redis-cli -a moxigame --cluster del-node 10.0.1.247:17001 <从节点ID>

# 3. 确认已删除
redis-cli -a moxigame -c -p 17001 cluster nodes | grep 17004

# 4. 检查集群状态
redis-cli -a moxigame -c -p 17001 cluster info | grep cluster_state
# 输出 cluster_state:ok

缩容主节点

主节点缩容需先迁移哈希槽,再删除节点。

# 1. 查看要删除的主节点信息
redis-cli -a moxigame -c -p 17001 cluster nodes | grep 17003
# 记录:节点 ID(如 04d6252fe6ca1f48b3a4cd7ca37baa1c817a8786)
# 记录:持有的哈希槽范围(如 10923-16383,共 5461 个槽)

# 2. 进入任意主节点容器
docker exec -it redis-node-1 bash

# 3. 执行槽位迁移
redis-cli -a moxigame --cluster reshard 10.0.1.247:17001

交互步骤

提示 输入
How many slots do you want to move? 5461(源节点持有的槽数)
What is the receiving node ID? 目标节点 ID(如 17001 的 ID)
Source node #1? 源节点 ID(17003 的 ID)
Source node #2? done
Do you want to proceed? yes
# 4. 迁移完成验证:确认源节点已无槽位
redis-cli -a moxigame -c -p 17001 cluster nodes | grep 17003

# 5. 删除主节点
redis-cli -a moxigame --cluster del-node 10.0.1.247:17001 <主节点ID>

# 6. 最终验证
redis-cli -a moxigame -c -p 17001 cluster nodes | grep -E "17003|17006"
redis-cli -a moxigame -c -p 17001 cluster info | grep cluster_slots_assigned
# 输出 cluster_slots_assigned:16384 表示槽位完整

# 7. 测试数据读写
redis-cli -a moxigame -c -p 17001 set test_reshard "success"
redis-cli -a moxigame -c -p 17001 get test_reshard

扩容

添加新节点

# 1. 新节点已启动(如 17004),加入集群
redis-cli -a moxigame --cluster add-node 10.0.1.247:17004 10.0.1.247:17001

# 2. 查看新节点状态(默认为主节点)
redis-cli -a moxigame -c -p 17001 cluster nodes | grep 17004

# 3. 将新节点设置为从节点(如需要)
redis-cli -a moxigame -c -p 17001 cluster replicate <主节点ID>

# 4. 为新节点分配哈希槽(reshard)
redis-cli -a moxigame --cluster reshard 10.0.1.247:17001

迁移槽位到新节点

# 示例:从所有现有主节点迁移槽位到新节点
redis-cli -a moxigame --cluster rebalance 10.0.1.247:17001 \
  --cluster-threshold 1 --cluster-weight 10.0.1.247:17004=1

备份

方法一:RDB 文件备份(推荐)

# 1. 进入节点容器
docker exec -it redis-node-1 bash

# 2. 触发 RDB 持久化
redis-cli -a moxigame -c -p 17001 save

# 3. 退出容器,备份数据目录
docker compose down
tar -czf redis_backup_$(date +%Y%m%d).tar.gz ./data/
docker compose up -d

方法二:持续备份

# 使用脚本定时备份
cat > backup_redis.sh <<'EOF'
#!/bin/bash
BACKUP_DIR=/backup/redis
DATE=$(date +%Y%m%d_%H%M%S)
docker exec redis-node-1 redis-cli -a moxigame save
tar -czf $BACKUP_DIR/redis_data_$DATE.tar.gz ./data/
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
EOF
chmod +x backup_redis.sh

# 添加到 crontab(每天凌晨 2 点执行)
0 2 * * * /path/to/backup_redis.sh

恢复

RDB 恢复

# 1. 停止所有节点
docker compose down

# 2. 清空数据目录(或恢复备份文件)
rm -rf ./data/*

# 3. 解压备份文件
tar -xzf redis_backup_20260101.tar.gz -C ./

# 4. 启动服务
docker compose up -d

# 5. 验证数据
redis-cli -a moxigame -c -p 17001 cluster nodes
redis-cli -a moxigame -c -p 17001 get <test_key>

完整集群恢复

如果集群元数据丢失,需重新创建集群:

# 1. 停止并清理数据
docker compose down
rm -rf ./data/*

# 2. 恢复 RDB 文件到各节点目录
# (将备份的 RDB 文件放入对应节点目录)

# 3. 启动节点
docker compose up -d

# 4. 重新创建集群
redis-cli -a moxigame --cluster create \
  10.0.1.247:17001 10.0.1.247:17002 10.0.1.247:17003 \
  10.0.1.247:17004 10.0.1.247:17005 10.0.1.247:17006 \
  --cluster-replicas 1 --cluster-yes

配置参数说明

参数 说明
cluster-enabled yes 启用集群模式
cluster-config-file nodes.conf 集群节点配置文件
cluster-node-timeout 5000 节点超时时间(毫秒)
cluster-migration-barrier 1 从节点迁移最少主节点数量
cluster-require-full-coverage no 部分槽位不可用时仍提供服务
appendonly yes 开启 AOF 持久化
requirepass 客户端连接密码
masterauth 从节点连接主节点密码

常用管理命令

操作 命令
查看集群信息 redis-cli -a 密码 -c -p 端口 cluster info
查看节点列表 redis-cli -a 密码 -c -p 端口 cluster nodes
检查集群状态 redis-cli -a 密码 --cluster check 地址:端口
查看哈希槽分配 redis-cli -a 密码 --cluster info 地址:端口
查看节点间的槽位 redis-cli -a 密码 -c -p 端口 cluster slots

常见问题与注意事项

集群创建失败

  1. 确认所有节点已正常启动:docker compose ps
  2. 检查节点间网络是否互通(network_mode: host 需宿主机端口开放)
  3. 确认防火墙放行 17001-17006 端口
  4. 检查配置文件是否一致(密码、端口)

缩容时提示"Node contains slots"

主节点必须先将所有哈希槽迁移至其他节点,才能执行删除。

扩容节点加入失败

# 清除节点数据重新加入
docker exec -it redis-node-4 rm -rf /data/*
docker compose restart redis-node-4
redis-cli -a moxigame --cluster add-node 10.0.1.247:17004 10.0.1.247:17001

集群脑裂或状态不一致

# 检查集群状态
redis-cli -a moxigame --cluster check 10.0.1.247:17001

# 修复集群
redis-cli -a moxigame --cluster fix 10.0.1.247:17001

密码配置不一致

所有节点 requirepassmasterauth 需保持一致,否则主从复制会失败。

备份恢复后集群状态异常

恢复 RDB 后,节点可能包含不一致的集群元数据,需重新创建集群:

# 清除集群元数据
rm -f ./data/*/nodes.conf
docker compose restart

# 重新创建集群
redis-cli -a moxigame --cluster create ...

参考链接