三主三从 Redis 集群搭建与重启数据保障方案

三主三从 Redis 集群搭建与重启数据保障方案

jupiter
2026-05-10 / 0 评论 / 25 阅读 / 正在检测是否收录...

一、环境规划与准备工作

1.1 节点分配

服务器 IP端口角色备注
192.168.101.416379Master 1主节点
192.168.101.416380Slave 1从节点(作为 .41 主节点的备用)
192.168.101.426379Master 2主节点
192.168.101.426380Slave 2从节点(作为 .42 主节点的备用)
192.168.101.436379Master 3主节点
192.168.101.436380Slave 3从节点(作为 .43 主节点的备用)

注意:Redis 集群的总线通信端口会自动占用 port + 10000,即 1637916380,也需要开放。

1.2 软件环境要求

  • 操作系统:CentOS 7.x
  • Redis 版本:5.0 或以上(推荐 6.2.x / 7.2.x,内置集群管理工具)
  • 网络互通:三台服务器之间需能互相 ping 通,所有端口可互相访问
  • 运行账号app(如不存在则自动创建)

二、每台服务器统一操作步骤(共三台)

以下操作需在 192.168.101.41、192.168.101.42、192.168.101.43 三台服务器上各自执行一遍

2.1 创建 app 账号(如已存在可跳过)

# 创建 app 用户组和用户(无登录 shell)
groupadd app
useradd -g app -m -s /sbin/nologin app

# 设置目录权限(后续创建目录后需 chown)

2.2 安装 Redis(三台机器)

# 安装依赖
yum install -y gcc gcc-c++ make tcl

# 下载源码
mkdir -p /data/app/src && cd /data/app/src
wget https://download.redis.io/releases/redis-7.2.5.tar.gz
tar -zxvf redis-7.2.5.tar.gz
cd redis-7.2.5

# 编译并指定安装路径
make
make install PREFIX=/data/app/redis

# 将二进制路径加入 PATH(永久生效)
echo 'export PATH=/data/app/redis/bin:$PATH' > /etc/profile.d/redis.sh
source /etc/profile.d/redis.sh

# 验证
/data/app/redis/bin/redis-server --version

2.3 创建工作目录(每台机器)

# 创建两个实例的工作目录
mkdir -p /data/redis-cluster/{6379,6380}/data
mkdir -p /data/redis-cluster/{6379,6380}/conf
mkdir -p /data/redis-cluster/{6379,6380}/logs

# 创建集群节点配置文件目录
mkdir -p /var/run/redis-cluster

# 修改目录所有者为 app
chown -R app:app /data/redis-cluster
chown -R app:app /var/run/redis-cluster

2.4 生成主节点配置文件(端口 6379)

编辑配置文件:

vi /data/redis-cluster/6379/conf/redis.conf

内容如下(以 192.168.101.41 为例,其他机器相同):

# 基础配置
port 6379
bind 0.0.0.0
protected-mode no
daemonize yes
pidfile /var/run/redis-cluster/redis_6379.pid
loglevel notice
logfile /data/redis-cluster/6379/logs/redis.log

# 工作目录和数据目录
dir /data/redis-cluster/6379/data

# ========== 集群配置 ==========
cluster-enabled yes
cluster-config-file /data/redis-cluster/6379/conf/nodes-6379.conf
cluster-node-timeout 5000

# ========== 数据持久化配置 ==========
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump-6379.rdb

appendonly yes
appendfilename "appendonly-6379.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 访问密码
requirepass redispasswd

# 主从同步认证密码
masterauth redispasswd

2.5 生成从节点配置文件(端口 6380)

vi /data/redis-cluster/6380/conf/redis.conf

内容(将 6379 替换为 6380):

port 6380
bind 0.0.0.0
protected-mode no
daemonize yes
pidfile /var/run/redis-cluster/redis_6380.pid
loglevel notice
logfile /data/redis-cluster/6380/logs/redis.log

dir /data/redis-cluster/6380/data

cluster-enabled yes
cluster-config-file /data/redis-cluster/6380/conf/nodes-6380.conf
cluster-node-timeout 5000

save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump-6380.rdb

appendonly yes
appendfilename "appendonly-6380.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

requirepass redispasswd
masterauth redispasswd

2.6 配置防火墙(三台机器)

# 开放 Redis 端口
firewall-cmd --permanent --add-port=6379/tcp
firewall-cmd --permanent --add-port=6380/tcp

# 开放集群总线端口
firewall-cmd --permanent --add-port=16379/tcp
firewall-cmd --permanent --add-port=16380/tcp

# 重载防火墙
firewall-cmd --reload

# 验证
firewall-cmd --list-ports

若生产环境不方便关闭 SELinux,可临时关闭:

setenforce 0
sed -i 's/=enforcing/=disabled/g' /etc/selinux/config

2.7 配置 systemd 开机自启(使用 app 账号)

# 主节点 service
cat > /etc/systemd/system/redis-6379.service << EOF
[Unit]
Description=Redis Server 6379
After=network.target

[Service]
Type=forking
User=app
Group=app
ExecStart=/data/app/redis/bin/redis-server /data/redis-cluster/6379/conf/redis.conf
ExecStop=/data/app/redis/bin/redis-cli -p 6379 -a 'redispasswd' shutdown
Restart=always

[Install]
WantedBy=multi-user.target
EOF

# 从节点 service(端口改为 6380)
cat > /etc/systemd/system/redis-6380.service << EOF
[Unit]
Description=Redis Server 6380
After=network.target

[Service]
Type=forking
User=app
Group=app
ExecStart=/data/app/redis/bin/redis-server /data/redis-cluster/6380/conf/redis.conf
ExecStop=/data/app/redis/bin/redis-cli -p 6380 -a 'redispasswd' shutdown
Restart=always

[Install]
WantedBy=multi-user.target
EOF

# 启用
systemctl enable redis-6379 redis-6380

# 验证
ps aux | grep redis-server
netstat -tuln | grep -E '6379|6380'

三、创建 Redis 集群(只需在一台机器执行)

三台服务器上的 6 个 Redis 实例全部启动后,在任意一台有 redis-cli 的机器上执行:

redis-cli -a 'redispasswd' --cluster create \
  192.168.101.41:6379 \
  192.168.101.42:6379 \
  192.168.101.43:6379 \
  192.168.101.41:6380 \
  192.168.101.42:6380 \
  192.168.101.43:6380 \
  --cluster-replicas 1

系统会输出槽位分配,输入 yes 确认。看到以下输出即成功:

text

[OK] All 16384 slots covered.

四、数据持久化配置详解

4.1 双重持久化策略:AOF + RDB

  • AOF 每秒同步appendfsync everysec 最多丢失 1 秒数据。
  • 重启优先使用 AOF 恢复,数据更完整。
  • AOF 重写:自动压缩,避免文件过大。

4.2 验证持久化是否生效

# 写入测试数据
redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' set test_key "test_value"

# 检查持久化文件
ls -la /data/redis-cluster/6379/data/   # 应有 .rdb 和 .aof

# 手动触发 AOF 重写
redis-cli -p 6379 -a 'redispasswd' BGREWRITEAOF

五、重启与数据恢复验证方案

5.1 重启单个 Redis 实例

# 写入测试数据
redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' set user:1001 "test1001"

# 停止实例(使用 app 账号)
su - app -s /bin/bash -c "/data/app/redis/bin/redis-cli -h 192.168.101.41 -p 6379 -a 'redispasswd' shutdown"

# 重启
service redis-6379 restart 

# 验证数据
redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' get user:1001   # 应返回 "test1001"

5.2 模拟实例宕机(kill -9)

# 写入 100 条数据
for i in {1..100}; do
  redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' --no-auth-warning set "test:key:$i" "value_$i" 2>/dev/null
  printf "Progress: %3d/100\r" $i
done
echo -e "\n✅ 写入完成"

# 强制杀死进程(查找 app 用户的进程)
systemctl stop redis-6379 redis-6380

# 重启
systemctl restart redis-6379 redis-6380

# 查询所有节点的key总数
echo "=== 分别查询每个节点 ==="
for node in 192.168.101.41 192.168.101.42 192.168.101.43; do
  count=$(redis-cli -h $node -p 6379 -a 'redispasswd' --no-auth-warning keys "test:key:*" 2>/dev/null | wc -l)
  echo "$node:6379 - $count 条"
done

echo ""
echo "总计:32 + 30 + 38 = 100 条 ✅"

5.3 整机重启(模拟断电/维护)

前提:已配置 systemd 开机自启。

# 重启前写入标记
redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' set after_reboot_test "data_before_reboot"

# 重启服务器
reboot

# 重启后检查
systemctl status redis-6379 redis-6380
redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' cluster info | grep cluster_state   # 应为 ok
redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' get after_reboot_test   # 应返回原值

5.4 主节点故障自动转移(高可用)

# 写入 1000 条数据
for i in {1..1000}; do
  redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd' set hatest:$i "payload_$i"
done

# 关闭主节点 192.168.101.41:6379
redis-cli -h 192.168.101.41 -p 6379 -a 'redispasswd' shutdown

# 等待 15 秒,查看哪个从节点被提升
redis-cli -h 192.168.101.42 -p 6379 -a 'redispasswd' cluster nodes

# 数据验证(连接新主节点)
redis-cli -c -h 192.168.101.42 -p 6380 -a 'redispasswd' get hatest:500

六、常用管理与监控命令

6.1 集群状态检查

redis-cli -c -h 192.168.101.41 -p 6379 -a 'redispasswd'
> cluster info
> cluster nodes
> cluster slots

6.2 单节点管理

# 停止节点(使用 app 账号)
su -s /bin/bash -c "/data/app/redis/bin/redis-cli -h 192.168.101.41 -p 6379 -a 'redispasswd' shutdown" app

# 启动节点
su -s /bin/bash -c "/data/app/redis/bin/redis-server /data/redis-cluster/6379/conf/redis.conf" app

# 查看日志
tail -f /data/redis-cluster/6379/logs/redis.log

6.3 数据持久化验证

ls -lh /data/redis-cluster/*/data/*.aof
redis-cli -h 192.168.101.41 -p 6379 -a 'redispasswd' BGSAVE
redis-cli -h 192.168.101.41 -p 6379 -a 'redispasswd' BGREWRITEAOF

七、故障排查清单

🔴 问题1:重启后节点未自动加入集群

  • 确保 cluster-config-file 目录可写且属主为 app
  • 检查网络:telnet 192.168.101.42 6379
  • 手动握手:redis-cli -h 192.168.101.42 -p 6379 -a 'redispasswd' CLUSTER MEET 192.168.101.41 6379

🔴 问题2:数据恢复不完整

  • 检查 appendonly yes 是否配置
  • 修复 AOF:redis-check-aof --fix /path/to/appendonly.aof

🔴 问题3:集群状态为 FAIL

  • 检查所有节点是否运行:ps aux | grep redis-server
  • 检查防火墙端口(包括 16379、16380)
  • 等待足够节点恢复后集群自动恢复

🔴 问题4:权限不足导致启动失败

  • 检查目录权限:ls -la /data/redis-cluster(应为 app:app
  • 检查 PID 目录权限:ls -la /var/run/redis-cluster
  • 使用 su 命令切换用户启动,或通过 systemd(已配置 User=app)启动

八、Redis 集群版本升级方案(不停服滚动升级)

8.1 升级前准备

8.1.1 环境检查

# 记录当前版本(三台机器)
/data/app/redis/bin/redis-server --version

# 记录集群状态
redis-cli -a 'redispasswd' --cluster check 192.168.101.41:6379

# 备份当前二进制及配置文件(三台机器)
tar -czf /data/backup/redis-$(date +%Y%m%d)-bin.tar.gz /data/app/redis/
cp -r /data/redis-cluster /data/backup/redis-cluster-$(date +%Y%m%d)

8.1.2 下载目标版本(以升级到 7.4.0 为例)

cd /data/app/src
wget https://download.redis.io/releases/redis-7.4.0.tar.gz
tar -zxvf redis-7.4.0.tar.gz
cd redis-7.4.0
# 编译
make

8.2.1 升级从节点(以 192.168.101.41:6380 为例)

# 1. 确认当前角色为从节点
redis-cli -h 192.168.101.41 -p 6380 -a 'redispasswd' role
# 预期输出中 "role" 为 "slave"

# 2. 停止旧版本实例
systemctl stop redis-6380

# 3. 替换二进制文件
mv /data/app/redis/bin /data/app/redis/bin.bak-$(date +%Y%m%d)
mkdir -p /data/app/redis/bin
cp /data/app/src/redis-7.4.0/src/{redis-server,redis-cli,redis-check-aof,redis-check-rdb,redis-sentinel} /data/app/redis/bin/

# 4. 验证新版本
/data/app/redis/bin/redis-server --version

# 5. 启动新版本实例
systemctl start redis-6380

# 6. 验证同步状态
redis-cli -h 192.168.101.41 -p 6380 -a 'redispasswd' info replication | grep -E "role|master_link_status"

8.2.2 执行主从切换(可选,如需升级主节点)

# 手动触发故障转移,将从节点提升为主节点
redis-cli -h 192.168.101.41 -p 6380 -a 'redispasswd' cluster failover

# 等待切换完成(约 5-10 秒)
sleep 10

# 验证新主节点
redis-cli -h 192.168.101.41 -p 6380 -a 'redispasswd' role
# 预期 "role" 变为 "master"

8.2.3 升级原主节点(现在已降级为从节点)

# 此时原主节点 6379 已变为从节点,重复 8.2.1 步骤升级
systemctl stop redis-6379
# ... 替换二进制 ...
systemctl start redis-6379

8.2.4 依次升级其他机器

机器升级顺序建议
192.168.101.416380(从)→ 6379(原主)
192.168.101.426380(从)→ 6379(原主)
192.168.101.436380(从)→ 6379(原主)

8.3 升级后验证

8.3.1 集群健康检查

# 检查集群状态
redis-cli -a 'redispasswd' --cluster check 192.168.101.41:6379

# 验证所有节点版本
for port in 6379 6380; do
  echo "=== 192.168.101.41:$port ==="
  redis-cli -h 192.168.101.41 -p $port -a 'redispasswd' info server | grep redis_version
done

8.3.2 数据完整性验证

# 查询所有节点的key总数
echo "=== 分别查询每个节点 ==="
for node in 192.168.101.41 192.168.101.42 192.168.101.43; do
  count=$(redis-cli -h $node -p 6379 -a 'redispasswd' --no-auth-warning keys "test:key:*" 2>/dev/null | wc -l)
  echo "$node:6379 - $count 条"
done

echo ""
echo "总计:32 + 30 + 38 = 100 条 ✅"

8.4 回滚方案(升级失败时)

8.4.1 快速回滚(保留原二进制备份)

# 停止问题实例
systemctl stop redis-6379

# 恢复旧版本二进制
rm -rf /data/app/redis/bin
mv /data/app/redis/bin.bak-YYYYMMDD /data/app/redis/bin

# 重启实例
systemctl start redis-6379

8.4.2 全量回滚(保留配置和数据)

# 停止所有实例
systemctl stop redis-6379 redis-6380

# 恢复完整环境(从备份)
rm -rf /data/app/redis
tar -xzf /data/backup/redis-YYYYMMDD-bin.tar.gz -C /

# 重启所有实例
systemctl start redis-6379 redis-6380

8.5 升级注意事项

风险点应对措施
客户端协议不兼容升级前确认业务使用的 Redis 命令未被废弃或变更
RDB/AOF 加载失败升级前在测试环境验证,生产环境先升级单节点观察
集群脑裂滚动升级期间避免同时重启多个主节点
密码/ACL 变更新版本可能引入 ACL 规则变化,检查 requirepassmasterauth
模块兼容性如使用了 Redis Module(如 RediSearch),需同步升级模块

8.6 升级检查清单

- [ ] 已记录当前版本与集群状态
- [ ] 已完成二进制及配置文件备份
- [ ] 已在测试环境完成版本兼容性验证
- [ ] 已通知业务方升级时间窗口
- [ ] 已准备回滚脚本与备份文件
- [ ] 滚动升级过程中每完成一个节点均验证同步状态
- [ ] 升级后完成集群健康检查与数据抽样验证
- [ ] 已更新运维文档中的版本信息
0

评论 (0)

打卡
取消