使用Docker搭建Redis分片集群
使用Docker和Docker Compose搭建Redis 3主3从分片集群及其扩缩容实践
1. 简介
Redis分片集群概念
Redis Cluster(Redis集群)是Redis官方提供的分布式解决方案,它能够在多个Redis节点之间自动分配数据,提供高可用性和横向扩展能力。分片集群通过一致性哈希算法将16384个哈希槽分配给不同的主节点,每个主节点负责一部分数据的存储和处理。
分片集群的优势
- 高可用性:当某个主节点故障时,其从节点可以自动提升为主节点,保证服务不中断
- 数据分片:数据自动分布在多个节点上,突破单机内存限制
- 读写分离:从节点可以分担读请求,提高系统并发能力
- 弹性扩容:可以动态添加或删除节点,实现集群的弹性伸缩
- 故障自愈:集群具备自动故障检测和恢复能力
为什么选择Docker容器化部署
- 环境一致性:容器化确保开发、测试、生产环境的一致性
- 快速部署:通过Docker Compose可以一键启动整个集群
- 资源隔离:每个Redis实例运行在独立的容器中,避免资源冲突
- 易于管理:容器化使得集群的启动、停止、监控更加便捷
- 可移植性:可以在任何支持Docker的环境中快速部署
2. 环境准备
环境要求
- 操作系统:Windows 10/11 Pro、Linux、macOS
- Docker版本:≥ 20.10.0
- Docker Compose版本:≥ 2.0.0
- 内存要求:至少4GB可用内存
- 磁盘空间:至少2GB可用磁盘空间
验证环境
执行以下命令验证环境:
# 检查Docker版本
docker --version
# 检查Docker Compose版本
docker-compose --version
# 检查Docker服务状态
docker info
网络配置建议
为了确保Redis集群在Docker环境中的稳定运行,建议进行以下网络配置:
# 检查Docker网络配置
docker network ls
# 创建自定义网络(如果需要)
docker network create --driver bridge --subnet=172.20.0.0/16 redis-cluster-network
网络规划:
- 子网范围:172.20.0.0/16
- 节点IP分配:172.20.0.2 - 172.20.0.7
- 预留扩容IP:172.20.0.8 - 172.20.0.20
3. 集群架构设计
3主3从集群架构
我们将构建一个包含6个Redis实例的集群:
集群网络拓扑
架构特点
- 主节点:负责处理读写请求,存储数据分片
- 从节点:主节点的副本,提供数据备份和读请求处理
- 哈希槽分配:16384个槽位平均分配给3个主节点
- 自动故障转移:主节点故障时,对应从节点自动提升为主节点
分片策略和数据分布原理
Redis Cluster使用一致性哈希算法进行数据分片:
哈希槽分布图
数据路由流程
-
哈希槽机制:
- 总共16384个哈希槽(0-16383)
- 每个key通过CRC16算法计算哈希值
- 哈希值对16384取模确定槽位
-
数据分布策略:
槽位分配: Master 1: 0-5460 (5461个槽) Master 2: 5461-10922 (5462个槽) Master 3: 10923-16383(5461个槽) -
路由机制:
- 客户端直接计算key对应的槽位
- 如果访问错误节点,会收到MOVED重定向
- 支持批量操作的Hash Tag功能
故障转移机制
4. Docker Compose配置文件
创建docker-compose.yml文件:
version: '3.8'
services:
# Redis集群节点1 - 主节点
redis-node-1:
image: redis:7.2-alpine
container_name: redis-node-1
ports:
- "7001:7001"
- "17001:17001"
volumes:
- ./redis-node-1.conf:/usr/local/etc/redis/redis.conf
- redis-node-1-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- redis-cluster
restart: unless-stopped
# Redis集群节点2 - 主节点
redis-node-2:
image: redis:7.2-alpine
container_name: redis-node-2
ports:
- "7002:7002"
- "17002:17002"
volumes:
- ./redis-node-2.conf:/usr/local/etc/redis/redis.conf
- redis-node-2-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- redis-cluster
restart: unless-stopped
# Redis集群节点3 - 主节点
redis-node-3:
image: redis:7.2-alpine
container_name: redis-node-3
ports:
- "7003:7003"
- "17003:17003"
volumes:
- ./redis-node-3.conf:/usr/local/etc/redis/redis.conf
- redis-node-3-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- redis-cluster
restart: unless-stopped
# Redis集群节点4 - 从节点
redis-node-4:
image: redis:7.2-alpine
container_name: redis-node-4
ports:
- "7004:7004"
- "17004:17004"
volumes:
- ./redis-node-4.conf:/usr/local/etc/redis/redis.conf
- redis-node-4-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- redis-cluster
restart: unless-stopped
# Redis集群节点5 - 从节点
redis-node-5:
image: redis:7.2-alpine
container_name: redis-node-5
ports:
- "7005:7005"
- "17005:17005"
volumes:
- ./redis-node-5.conf:/usr/local/etc/redis/redis.conf
- redis-node-5-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- redis-cluster
restart: unless-stopped
# Redis集群节点6 - 从节点
redis-node-6:
image: redis:7.2-alpine
container_name: redis-node-6
ports:
- "7006:7006"
- "17006:17006"
volumes:
- ./redis-node-6.conf:/usr/local/etc/redis/redis.conf
- redis-node-6-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- redis-cluster
restart: unless-stopped
networks:
redis-cluster:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
volumes:
redis-node-1-data:
redis-node-2-data:
redis-node-3-data:
redis-node-4-data:
redis-node-5-data:
redis-node-6-data:
关键配置项说明
- image: 使用Redis 7.2官方Alpine镜像,体积小、安全性高
- ports: 映射Redis服务端口和集群总线端口(服务端口+10000)
- volumes: 挂载配置文件和数据目录,实现数据持久化
- networks: 创建专用网络,确保容器间通信
- restart: 设置容器重启策略,提高服务可用性
5. Redis配置文件
每个节点需要单独的配置文件。以redis-node-1.conf为例:
# 基础配置
port 7001
bind 0.0.0.0
protected-mode no
daemonize no
# 集群配置
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 15000
cluster-announce-ip 172.20.0.2
cluster-announce-port 7001
cluster-announce-bus-port 17001
# 持久化配置
appendonly yes
appendfilename "appendonly-7001.aof"
save 900 1
save 300 10
save 60 10000
# 内存管理
maxmemory 512mb
maxmemory-policy allkeys-lru
# 日志配置
loglevel notice
logfile ""
# 安全配置
# requirepass your_password_here
# masterauth your_password_here
其他节点配置文件
创建其余5个配置文件,主要修改以下参数:
redis-node-2.conf:
port 7002
cluster-config-file nodes-7002.conf
cluster-announce-ip 172.20.0.3
cluster-announce-port 7002
cluster-announce-bus-port 17002
appendfilename "appendonly-7002.aof"
redis-node-3.conf:
port 7003
cluster-config-file nodes-7003.conf
cluster-announce-ip 172.20.0.4
cluster-announce-port 7003
cluster-announce-bus-port 17003
appendfilename "appendonly-7003.aof"
redis-node-4.conf:
port 7004
cluster-config-file nodes-7004.conf
cluster-announce-ip 172.20.0.5
cluster-announce-port 7004
cluster-announce-bus-port 17004
appendfilename "appendonly-7004.aof"
redis-node-5.conf:
port 7005
cluster-config-file nodes-7005.conf
cluster-announce-ip 172.20.0.6
cluster-announce-port 7005
cluster-announce-bus-port 17005
appendfilename "appendonly-7005.aof"
redis-node-6.conf:
port 7006
cluster-config-file nodes-7006.conf
cluster-announce-ip 172.20.0.7
cluster-announce-port 7006
cluster-announce-bus-port 17006
appendfilename "appendonly-7006.aof"
5. 集群部署步骤
步骤1:创建项目目录
# 创建项目目录
mkdir redis-cluster
cd redis-cluster
# 创建配置文件目录
mkdir configs
步骤2:创建配置文件
将上述配置文件分别保存为对应的文件名。
步骤3:启动Redis容器
# 启动所有Redis节点
docker-compose up -d
# 查看容器状态
docker-compose ps
# 查看容器日志
docker-compose logs redis-node-1
步骤4:验证容器启动
# 查看网络连接
docker network ls
# 查看容器IP地址
docker inspect redis-node-1 | findstr IPAddress
6. 集群初始化
方法一:使用redis-cli创建集群
# 进入任意一个Redis容器
docker exec -it redis-node-1 /bin/sh
# 创建集群(在容器内执行)
redis-cli --cluster create \
172.20.0.2:7001 \
172.20.0.3:7002 \
172.20.0.4:7003 \
172.20.0.5:7004 \
172.20.0.6:7005 \
172.20.0.7:7006 \
--cluster-replicas 1
# 输入 yes 确认创建集群
方法二:使用宿主机redis-cli(如果已安装)
# 从宿主机直接创建集群
redis-cli --cluster create \
127.0.0.1:7001 \
127.0.0.1:7002 \
127.0.0.1:7003 \
127.0.0.1:7004 \
127.0.0.1:7005 \
127.0.0.1:7006 \
--cluster-replicas 1
集群创建成功标志
成功创建后会看到类似输出:
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.20.0.5:7004 to 172.20.0.2:7001
Adding replica 172.20.0.6:7005 to 172.20.0.3:7002
Adding replica 172.20.0.7:7006 to 172.20.0.4:7003
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
>>> Performing Cluster Check (using node 172.20.0.2:7001)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
7. 集群功能测试
查看集群状态
# 连接到集群任意节点
docker exec -it redis-node-1 redis-cli -p 7001
# 查看集群信息
CLUSTER INFO
# 查看集群节点
CLUSTER NODES
# 退出redis-cli
exit
测试数据读写
# 连接到集群(启用集群模式)
docker exec -it redis-node-1 redis-cli -c -p 7001
# 设置一些测试数据
SET key1 "Hello Redis Cluster"
SET key2 "This is node 2"
SET key3 "Distributed data"
# 读取数据
GET key1
GET key2
GET key3
# 查看key分布在哪个槽位
CLUSTER KEYSLOT key1
CLUSTER KEYSLOT key2
CLUSTER KEYSLOT key3
验证数据分片
# 查看每个节点的key数量
docker exec redis-node-1 redis-cli -p 7001 DBSIZE
docker exec redis-node-2 redis-cli -p 7002 DBSIZE
docker exec redis-node-3 redis-cli -p 7003 DBSIZE
性能测试
# 使用redis-benchmark进行性能测试
docker exec redis-node-1 redis-benchmark -h 127.0.0.1 -p 7001 -t set,get -n 10000 -c 50
8. 集群扩容操作
随着业务增长,我们可能需要扩展Redis集群以提高处理能力和存储容量。本节将详细说明如何安全地向现有3主3从集群添加新节点。
扩容方案设计
我们将演示两种扩容场景:
- 添加1主1从:扩展为4主4从集群
- 为现有主节点添加从节点:提高读取性能
扩容前的准备工作
# 1. 备份现有集群配置
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES > cluster_backup.txt
# 2. 检查集群当前状态
docker exec redis-node-1 redis-cli -p 7001 CLUSTER INFO
# 3. 检查数据分布情况
docker exec redis-node-1 redis-cli -p 7001 --cluster check 127.0.0.1:7001
方案一:添加1主1从节点
步骤1:更新Docker Compose配置
创建新的docker-compose-expanded.yml文件,添加两个新节点:
version: '3.8'
services:
# ...existing services...
# 这里省略原有的6个节点配置
# Redis集群节点7 - 新主节点
redis-node-7:
image: redis:7.2-alpine
container_name: redis-node-7
ports:
- "7007:7007"
- "17007:17007"
volumes:
- ./redis-node-7.conf:/usr/local/etc/redis/redis.conf
- redis-node-7-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
redis-cluster:
ipv4_address: 172.20.0.8
restart: unless-stopped
# Redis集群节点8 - 新从节点
redis-node-8:
image: redis:7.2-alpine
container_name: redis-node-8
ports:
- "7008:7008"
- "17008:17008"
volumes:
- ./redis-node-8.conf:/usr/local/etc/redis/redis.conf
- redis-node-8-data:/data
command: redis-server /usr/local/etc/redis/redis.conf
networks:
redis-cluster:
ipv4_address: 172.20.0.9
restart: unless-stopped
volumes:
# ...existing volumes...
redis-node-7-data:
redis-node-8-data:
步骤2:创建新节点配置文件
redis-node-7.conf(新主节点):
# 基础配置
port 7007
bind 0.0.0.0
protected-mode no
daemonize no
# 集群配置
cluster-enabled yes
cluster-config-file nodes-7007.conf
cluster-node-timeout 15000
cluster-announce-ip 172.20.0.8
cluster-announce-port 7007
cluster-announce-bus-port 17007
# 持久化配置
appendonly yes
appendfilename "appendonly-7007.aof"
save 900 1
save 300 10
save 60 10000
# 内存管理
maxmemory 512mb
maxmemory-policy allkeys-lru
# 日志配置
loglevel notice
logfile ""
redis-node-8.conf(新从节点):
# 基础配置
port 7008
bind 0.0.0.0
protected-mode no
daemonize no
# 集群配置
cluster-enabled yes
cluster-config-file nodes-7008.conf
cluster-node-timeout 15000
cluster-announce-ip 172.20.0.9
cluster-announce-port 7008
cluster-announce-bus-port 17008
# 持久化配置
appendonly yes
appendfilename "appendonly-7008.aof"
save 900 1
save 300 10
save 60 10000
# 内存管理
maxmemory 512mb
maxmemory-policy allkeys-lru
# 日志配置
loglevel notice
logfile ""
步骤3:启动新节点
# 启动新节点
docker-compose -f docker-compose-expanded.yml up -d redis-node-7 redis-node-8
# 验证新节点启动成功
docker-compose -f docker-compose-expanded.yml ps
# 检查新节点日志
docker-compose -f docker-compose-expanded.yml logs redis-node-7
docker-compose -f docker-compose-expanded.yml logs redis-node-8
步骤4:将新节点加入集群
# 1. 将新主节点加入集群
docker exec -it redis-node-1 redis-cli --cluster add-node 172.20.0.8:7007 172.20.0.2:7001
# 2. 将新从节点加入集群
docker exec -it redis-node-1 redis-cli --cluster add-node 172.20.0.9:7008 172.20.0.2:7001
# 3. 获取新主节点的Node ID
docker exec redis-node-7 redis-cli -p 7007 CLUSTER NODES | findstr myself
# 4. 设置node-8为node-7的从节点(替换<node-7-id>为实际ID)
docker exec redis-node-8 redis-cli -p 7008 CLUSTER REPLICATE <node-7-id>
步骤5:重新分片数据
# 启动重新分片向导
docker exec -it redis-node-1 redis-cli --cluster reshard 172.20.0.2:7001
# 按提示输入:
# 1. 要移动多少槽位?建议输入:4096 (16384/4)
# 2. 目标节点ID?输入新主节点的ID
# 3. 源节点?输入 all (从所有现有主节点获取槽位)
# 4. 确认?输入 yes
步骤6:验证扩容结果
# 检查集群状态
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES
# 检查槽位分布
docker exec redis-node-1 redis-cli --cluster check 172.20.0.2:7001
# 测试新节点功能
docker exec -it redis-node-7 redis-cli -c -p 7007
SET test-expansion "Data on new node"
GET test-expansion
方案二:为现有主节点添加从节点
如果只需要提高读取性能而不增加存储容量,可以为现有主节点添加额外的从节点。
添加额外从节点的步骤
# 1. 启动新的从节点容器
docker-compose -f docker-compose-expanded.yml up -d redis-node-9
# 2. 将新节点加入集群
docker exec -it redis-node-1 redis-cli --cluster add-node 172.20.0.10:7009 172.20.0.2:7001
# 3. 获取目标主节点ID(例如node-1)
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES | findstr master
# 4. 设置新节点为指定主节点的从节点
docker exec redis-node-9 redis-cli -p 7009 CLUSTER REPLICATE <master-node-id>
9. 集群缩容操作
当系统负载降低或需要节约资源时,可以安全地移除部分节点。缩容操作需要格外小心,以确保数据完整性。
缩容前的检查
# 1. 检查集群健康状态
docker exec redis-node-1 redis-cli --cluster check 172.20.0.2:7001
# 2. 备份集群数据
docker exec redis-node-1 redis-cli -p 7001 BGSAVE
# 3. 检查要移除节点的角色和数据
docker exec redis-node-7 redis-cli -p 7007 CLUSTER NODES
docker exec redis-node-7 redis-cli -p 7007 DBSIZE
安全移除从节点
移除从节点相对简单,因为从节点不持有唯一数据:
# 1. 获取要移除的从节点ID
docker exec redis-node-8 redis-cli -p 7008 CLUSTER NODES | findstr myself
# 2. 从集群中移除从节点
docker exec -it redis-node-1 redis-cli --cluster del-node 172.20.0.2:7001 <slave-node-id>
# 3. 停止并移除容器
docker stop redis-node-8
docker rm redis-node-8
# 4. 验证移除结果
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES
安全移除主节点
移除主节点需要先迁移其持有的槽位:
步骤1:迁移槽位数据
# 1. 检查要移除主节点的槽位分配
docker exec redis-node-7 redis-cli -p 7007 CLUSTER NODES | findstr master
# 2. 使用reshard命令迁移槽位
docker exec -it redis-node-1 redis-cli --cluster reshard 172.20.0.2:7001
# 按提示操作:
# - 要移动多少槽位?输入该节点的所有槽位数量
# - 目标节点ID?选择其他主节点的ID
# - 源节点?输入要移除的主节点ID
# - 确认迁移?输入 yes
步骤2:移除空主节点
# 1. 确认节点已无槽位分配
docker exec redis-node-7 redis-cli -p 7007 CLUSTER NODES
# 2. 移除节点
docker exec -it redis-node-1 redis-cli --cluster del-node 172.20.0.2:7001 <empty-master-node-id>
# 3. 停止并移除容器
docker stop redis-node-7
docker rm redis-node-7
步骤3:验证缩容结果
# 检查集群状态
docker exec redis-node-1 redis-cli --cluster check 172.20.0.2:7001
# 验证数据完整性
docker exec -it redis-node-1 redis-cli -c -p 7001
KEYS *
GET test-expansion # 验证之前的测试数据
批量缩容操作
如果需要同时移除多个节点,建议按以下顺序:
# 1. 先移除所有从节点
for slave in node-4 node-5 node-6; do
echo "Removing $slave..."
# 执行移除从节点的命令
docker exec -it redis-node-1 redis-cli --cluster del-node 172.20.0.2:7001 <slave-node-id>
docker stop redis-node-$slave
docker rm redis-node-$slave
echo "$slave removed."
# 验证移除结果
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES
echo "Current cluster nodes:"
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES
echo "-------------------------"
sleep 2 # 等待集群稳定
done
# 2. 再移除主节点(逐个迁移槽位)
for master in node-2 node-3; do
echo "Migrating slots from $master..."
# 执行槽位迁移和节点移除
docker exec -it redis-node-1 redis-cli --cluster reshard
docker exec -it redis-node-1 redis-cli --cluster del-node 172.20.0.2:7001 <master-node-id>
docker stop redis-node-$master
docker rm redis-node-$master
echo "$master removed."
# 验证移除结果
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES
echo "Current cluster nodes:"
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES
echo "-------------------------"
sleep 2 # 等待集群稳定
done
7. 集群功能测试
模拟主节点故障
# 停止一个主节点(例如node-1)
docker stop redis-node-1
# 查看集群状态
docker exec -it redis-node-2 redis-cli -c -p 7002 CLUSTER NODES
# 测试数据读写是否正常
docker exec -it redis-node-2 redis-cli -c -p 7002
SET test-failover "Failover test"
GET test-failover
观察故障转移过程
故障转移通常在几秒内完成:
- 集群检测到主节点不可达
- 该主节点的从节点开始选举
- 选举成功的从节点提升为新的主节点
- 集群重新分配槽位
恢复故障节点
# 重新启动故障节点
docker start redis-node-1
# 检查节点状态(此时node-1会变成从节点)
docker exec -it redis-node-1 redis-cli -p 7001 CLUSTER NODES
故障转移测试
测试集群的高可用性是验证集群功能的重要环节:
模拟主节点故障
# 1. 记录当前集群状态
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES > cluster_before_failure.txt
# 2. 停止一个主节点(例如node-1)
docker stop redis-node-1
# 3. 等待几秒钟,观察故障转移
Start-Sleep -Seconds 10
# 4. 检查集群状态变化
docker exec -it redis-node-2 redis-cli -c -p 7002 CLUSTER NODES
# 5. 测试集群是否仍可正常工作
docker exec -it redis-node-2 redis-cli -c -p 7002
SET failover-test "Cluster still works"
GET failover-test
观察故障恢复
# 1. 重新启动故障节点
docker start redis-node-1
# 2. 检查节点重新加入集群的状态
docker exec redis-node-1 redis-cli -p 7001 CLUSTER NODES
# 3. 验证数据一致性
docker exec -it redis-node-1 redis-cli -c -p 7001
GET failover-test
数据一致性验证
# 创建测试脚本验证数据一致性
$testScript = @"
#!/bin/bash
for i in {1..100}; do
docker exec redis-node-1 redis-cli -c -p 7001 SET "test_key_$i" "value_$i"
done
echo "Data written, now checking consistency..."
for node in 2 3; do
echo "Checking node $node:"
for i in {1..100}; do
result=`docker exec redis-node-$node redis-cli -c -p 700$node GET "test_key_$i"`
if [ "$result" != "value_$i" ]; then
echo "Inconsistency found for key test_key_$i"
fi
done
done
"@
$testScript | Out-File -FilePath "test_consistency.sh" -Encoding UTF8
10. 常见问题与解决方案
扩容相关问题
问题1:新节点无法加入集群
错误现象:
[ERR] Sorry, can't connect to node 172.20.0.8:7007
原因分析:
- 网络配置错误
- 端口映射问题
- 防火墙阻拦
解决方案:
# 1. 检查容器网络连通性
docker exec redis-node-1 ping 172.20.0.8
# 2. 检查端口映射
docker port redis-node-7
# 3. 验证Redis服务状态
docker exec redis-node-7 redis-cli -p 7007 ping
# 4. 检查集群配置
docker exec redis-node-7 redis-cli -p 7007 CLUSTER NODES
问题2:重新分片过程中断
错误现象:
[ERR] Calling MIGRATE ERR syntax error
解决方案:
# 1. 检查集群状态
docker exec redis-node-1 redis-cli --cluster check 172.20.0.2:7001
# 2. 手动修复不一致的槽位
docker exec redis-node-1 redis-cli --cluster fix 172.20.0.2:7001
# 3. 重新开始分片操作
docker exec -it redis-node-1 redis-cli --cluster reshard 172.20.0.2:7001
缩容相关问题
问题3:无法移除主节点
错误现象:
[ERR] Node 172.20.0.8:7007 is not empty! Reshard data away and try again.
解决方案:
# 1. 检查节点槽位分配
docker exec redis-node-7 redis-cli -p 7007 CLUSTER NODES | findstr 172.20.0.8
# 2. 迁移所有槽位到其他节点
docker exec -it redis-node-1 redis-cli --cluster reshard 172.20.0.2:7001
# 3. 确认槽位迁移完成后再次尝试移除
docker exec -it redis-node-1 redis-cli --cluster del-node 172.20.0.2:7001 <node-id>
问题4:数据迁移过程中性能下降
解决方案:
# 1. 调整迁移并发度
docker exec redis-node-1 redis-cli CONFIG SET cluster-migration-barrier 2
# 2. 在业务低峰期进行迁移
# 3. 监控集群负载情况
docker exec redis-node-1 redis-cli INFO stats
性能相关问题
问题5:集群响应延迟增加
诊断步骤:
# 1. 检查集群节点延迟
docker exec redis-node-1 redis-cli --latency -i 1
# 2. 检查网络延迟
docker exec redis-node-1 redis-cli --cluster check 172.20.0.2:7001
# 3. 分析慢查询日志
docker exec redis-node-1 redis-cli SLOWLOG GET 10
11. 性能优化建议
Docker资源优化
容器资源限制
更新docker-compose.yml,添加资源限制:
services:
redis-node-1:
# ...existing configuration...
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
ulimits:
memlock:
soft: -1
hard: -1
系统级优化
# 1. 调整Docker daemon配置
# 编辑 %USERPROFILE%\.docker\daemon.json
$daemonConfig = @{
"storage-driver" = "overlay2"
"log-driver" = "json-file"
"log-opts" = @{
"max-size" = "10m"
"max-file" = "3"
}
"default-ulimits" = @{
"memlock" = @{
"Hard" = -1
"Name" = "memlock"
"Soft" = -1
}
}
} | ConvertTo-Json -Depth 3
$daemonConfig | Out-File -FilePath "$env:USERPROFILE\.docker\daemon.json" -Encoding UTF8
Redis集群优化
关键配置参数
为每个Redis节点添加性能优化配置:
# 网络优化
tcp-keepalive 300
tcp-backlog 511
timeout 0
# 内存优化
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
# 持久化优化
stop-writes-on-bgsave-error no
rdbcompression yes
rdbchecksum yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
# 集群优化
cluster-require-full-coverage no
cluster-node-timeout 15000
cluster-slave-validity-factor 10
cluster-migration-barrier 1
监控和调优
# 1. 创建性能监控脚本
$monitorScript = @"
# Redis集群性能监控脚本
while ($true) {
Write-Host "=== Redis Cluster Performance Monitor ===" -ForegroundColor Green
Write-Host "Time: $(Get-Date)" -ForegroundColor Yellow
# 检查每个节点的内存使用
for ($i=1; $i -le 6; $i++) {
$memory = docker exec redis-node-$i redis-cli -p 700$i INFO memory | Select-String "used_memory_human"
Write-Host "Node $i Memory: $memory"
}
# 检查集群状态
$clusterInfo = docker exec redis-node-1 redis-cli -p 7001 CLUSTER INFO | Select-String "cluster_state"
Write-Host "Cluster State: $clusterInfo"
# 检查连接数
$connections = docker exec redis-node-1 redis-cli -p 7001 INFO clients | Select-String "connected_clients"
Write-Host "Connections: $connections"
Start-Sleep -Seconds 30
}
"@
$monitorScript | Out-File -FilePath "monitor_cluster.ps1" -Encoding UTF8
# 2. 运行监控脚本
# powershell -ExecutionPolicy Bypass -File monitor_cluster.ps1
生产环境建议
安全配置
# 启用密码认证
requirepass your_strong_password_here
masterauth your_strong_password_here
# 绑定特定接口
bind 127.0.0.1 172.20.0.2
# 启用保护模式
protected-mode yes
# 重命名危险命令
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG "CONFIG_b840fc02d524045429941cc15f59e41cb7be6c52"
备份策略
# 1. 创建自动备份脚本
$backupScript = @"
# Redis集群备份脚本
$backupDir = "C:\redis-backups\$(Get-Date -Format 'yyyy-MM-dd')"
New-Item -ItemType Directory -Path $backupDir -Force
# 备份每个主节点
foreach ($node in @(1,2,3)) {
Write-Host "Backing up redis-node-$node..."
docker exec redis-node-$node redis-cli -p 700$node BGSAVE
# 等待备份完成
do {
Start-Sleep -Seconds 5
$lastSave = docker exec redis-node-$node redis-cli -p 700$node LASTSAVE
} while ($lastSave -eq $previousSave)
# 复制备份文件
docker cp redis-node-$node`:/data/dump.rdb $backupDir\node-$node-dump.rdb
Write-Host "Node $node backup completed."
}
# 清理7天前的备份
Get-ChildItem "C:\redis-backups" | Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-7)} | Remove-Item -Recurse -Force
"@
$backupScript | Out-File -FilePath "backup_cluster.ps1" -Encoding UTF8
# 2. 设置定时任务
# schtasks /create /tn "Redis Cluster Backup" /tr "powershell -ExecutionPolicy Bypass -File C:\path\to\backup_cluster.ps1" /sc daily /st 02:00

浙公网安备 33010602011771号