环境说明

一、系统准备

1.1 安装依赖

dnf update -y
dnf install -y gcc gcc-c++ make wget tcl git

# 检查gcc版本
gcc --version

1.2 防火墙和SELinux配置

# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# SELinux配置
getenforce
setenforce 0

# 禁用SELinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

二、Redis安装

源码编译安装Redis 5.0.x

# 创建Redis用户
useradd -r -s /bin/false redis

# 创建安装目录
mkdir -p /usr/local/redis
cd /usr/local/redis

# 创建数据目录
mkdir -p /data/redis
chown -R redis:redis /data/redis
chmod 750 /data/redis

# 日志目录
mkdir -p /var/log/redis
chown -R redis:redis /var/log/redis
chmod 750 /var/log/redis

# 配置文件目录
mkdir -p /etc/redis
chown -R redis:redis /etc/redis
chmod 750 /etc/redis

# 下载Redis 5.0.14(稳定版本)
wget http://download.redis.io/releases/redis-5.0.14.tar.gz

# 解压
tar -zxvf redis-5.0.14.tar.gz
cd redis-5.0.14

# 编译
make && make install

三、 系统服务配置

3.1 主节点配置文件

# 编辑配置文件
vim /etc/redis/redis_master.conf

基本配置

bind 0.0.0.0
port 6379
timeout 300
tcp-keepalive 300
tcp-backlog 511

守护进程配置

daemonize yes
pidfile /var/run/redis_master.pid
logfile /var/log/redis/redis_master.log
loglevel notice

数据配置

dir /data/redis
dbfilename dump.rdb
appendfilename “appendonly.aof”
appendonly yes
appendfsync everysec

内存配置

maxmemory 2gb
maxmemory-policy allkeys-lru

安全配置

protected-mode no
requirepass xxxxxxxxx

持久化配置

save 900 1
save 300 10
save 60 10000
rdbcompression yes
rdbchecksum yes

慢查询日志

slowlog-log-slower-than 10000
slowlog-max-len 128

客户端配置

maxclients 10000

AOF配置

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes

网络配置

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

chown redis:redis /etc/redis/redis_master.conf
chmod 640 /etc/redis/redis_master.conf


### 3.2 从节点配置文件
vim /etc/redis/redis_slave.conf

基本配置

bind 0.0.0.0
port 6379
timeout 300
tcp-keepalive 300
tcp-backlog 511

守护进程配置

daemonize yes
pidfile /var/run/redis_slave.pid
logfile /var/log/redis/redis_slave.log
loglevel notice

数据配置

dir /data/redis
dbfilename dump.rdb
appendfilename “appendonly.aof”
appendonly yes
appendfsync everysec

内存配置

maxmemory 2gb
maxmemory-policy allkeys-lru

安全配置

protected-mode no
requirepass xxxxxxxxx
masterauth xxxxxxxxx

主从配置

replicaof 172.50.1.24 6379
replica-read-only yes

持久化配置

save 900 1
save 300 10
save 60 10000
rdbcompression yes
rdbchecksum yes

慢查询日志

slowlog-log-slower-than 10000
slowlog-max-len 128

客户端配置

maxclients 10000

AOF配置

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes

网络配置

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

chown redis:redis /etc/redis/redis_slave.conf
chmod 640 /etc/redis/redis_slave.conf


### 3.3 创建systemd服务文件
主:
vim /etc/systemd/system/redis.service

[Unit]
Description=Redis In-Memory Data Store (Port 6379)
After=network.target

[Service]
Type=forking
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis_master.conf
ExecStop=/usr/local/bin/redis-cli -p 6379 -a xxxxxxxxx shutdown
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

从:
vim /etc/systemd/system/redis.service

[Unit]
Description=Redis In-Memory Data Store (Port 6379)
After=network.target

[Service]
Type=forking
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis_slave.conf
ExecStop=/usr/local/bin/redis-cli -p 6379 -a xxxxxxxxx shutdown
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target


### 3.4 启动和管理服务

启动Redis服务

systemctl daemon-reload
systemctl start redis
systemctl enable redis

查看状态

systemctl status redis

查看日志

journalctl -u redis -f


## 四、验证主从配置

### 4.1 主节点验证

连接主节点

redis-cli -h 172.50.1.24 -a your_redis_password

查看主从信息

info replication

172.50.1.24:6379> info replication

Replication

role:master
connected_slaves:1
slave0:ip=172.50.1.25,port=6379,state=online,offset=112,lag=1
master_replid:a9de7b70741b96324cea556c3337b371fd779c1b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:112
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:112


### 4.2 从节点验证

连接从节点

redis-cli -h 172.50.1.25 -a xxxxxxxxx

查看主从信息

info replication

172.50.1.25:6379> info replication

Replication

role:slave
master_host:172.50.1.24
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:756
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a9de7b70741b96324cea556c3337b371fd779c1b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:756
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:756


## 五、故障转移与数据恢复

### 5.1 故障场景说明
当主节点(172.50.1.24)发生宕机或不可用时,需要将现有的从节点(172.50.1.25)提升为新的主节点,确保服务可用性。Redis 5.0不支持自动故障转移,需要手动操作。

### 5.2 故障检测与确认

#### 5.2.1 检查主节点状态

在主节点服务器上检查Redis进程

ps aux | grep redis

检查Redis服务状态

systemctl status redis

检查端口是否监听

netstat -tlnp | grep 6379

尝试连接主节点(从节点服务器上执行)

redis-cli -h 172.50.1.24 -a xxxxxxxxx ping


#### 5.2.2 确认主从同步状态

在从节点上检查主从状态

redis-cli -h 172.50.1.25 -a xxxxxxxxx info replication

查看主从连接状态,如果master_link_status为down,说明主节点已不可用


### 5.3 从节点升主操作(一般不需要,从节点只做只读实例、数据备份使用)

#### 5.3.1 停止从节点复制

连接从节点

redis-cli -h 172.50.1.25 -a xxxxxxxxx

停止复制,将从节点提升为主节点

127.0.0.1:6379> SLAVEOF NO ONE

验证节点已提升为主节点

127.0.0.1:6379> info replication


#### 5.3.2 修改配置文件

备份原配置文件

cp /etc/redis/redis_slave.conf /etc/redis/redis_slave.conf.backup

修改从节点配置文件,移除主从配置

vim /etc/redis/redis_slave.conf


需要修改或注释掉的配置:

注释掉原有的主从配置

replicaof 172.50.1.24 6379

masterauth xxxxxxxxx

确保从节点可写(默认就是可写的)

replica-read-only yes # 可以改为no,允许写入


#### 5.3.3 重启Redis服务

重启Redis服务以应用新配置

systemctl restart redis

检查服务状态

systemctl status redis


### 5.4 应用连接配置更新(一般不会到这步,除非主节点恢复不了了紧急情况使用)

#### 5.4.1 更新应用配置
通知所有应用服务将Redis连接地址从原主节点IP(172.50.1.24)改为新的主节点IP(172.50.1.25)。

#### 5.4.2 验证服务可用性

在新主节点上测试基本操作

redis-cli -h 172.50.1.25 -a xxxxxxxxx

测试读写操作

172.50.1.25:6379> set test_key “test_value”
172.50.1.25:6379> get test_key
172.50.1.25:6379> del test_key


### 5.5 原主节点恢复(一般不会到这步,除非主节点恢复不了了紧急情况使用)

#### 5.5.1 原主节点修复后重新加入
当原主节点(172.50.1.24)修复完成后,可以将其配置为新的从节点加入集群。

##### 5.5.1.1 修改原主节点配置

备份原配置文件

cp /etc/redis/redis_master.conf /etc/redis/redis_master.conf.backup

修改配置文件,改为从节点配置

vim /etc/redis/redis_master.conf


修改内容:

添加主从配置

replicaof 172.50.1.25 6379
masterauth xxxxxxxxx

确保只读模式

replica-read-only yes


##### 5.5.1.2 重启原主节点服务

重启Redis服务

systemctl restart redis

检查主从状态

redis-cli -h 172.50.1.24 -a xxxxxxxxx info replication


### 5.6 数据备份与恢复

#### 5.6.1 定期数据备份
创建备份脚本:

创建备份目录

mkdir -p /data/redis/backup

创建备份脚本

vim /usr/local/bin/redis_backup.sh

#!/bin/bash

Redis数据备份脚本

配置参数(主从注意区别IP和密码)

REDISHOST=”172.50.1.25”
REDIS_PORT=”6379”
REDIS_PASSWORD=”xxxxxxxxx”
BACKUP_DIR=”/data/redis/backup”
DATE=$(date +%Y%m%d
%H%M%S)

创建备份目录

mkdir -p $BACKUP_DIR

执行备份

redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD BGSAVE

等待备份完成

sleep 5

复制备份文件

cp /data/redis/dump.rdb $BACKUPDIR/dump$DATE.rdb
cp /data/redis/appendonly.aof $BACKUPDIR/appendonly$DATE.aof

清理7天前的备份

find $BACKUP_DIR -name “.rdb” -mtime +7 -delete
find $BACKUP_DIR -name “
.aof” -mtime +7 -delete

echo “Redis backup completed at $DATE”


设置定时任务:

添加执行权限

chmod +x /usr/local/bin/redis_backup.sh

添加到crontab(每天凌晨2点备份)

echo “0 2 * /usr/local/bin/redis_backup.sh” | crontab -


#### 5.6.2 数据恢复

##### 5.6.2.1 从备份恢复数据

停止Redis服务

systemctl stop redis

备份当前数据

cp /data/redis/dump.rdb /data/redis/dump.rdb.backup.$(date +%Y%m%d_%H%M%S)

恢复备份数据

cp /data/redis/backup/dump_20240101_020000.rdb /data/redis/dump.rdb

启动Redis服务

systemctl start redis

验证数据

redis-cli -h 172.50.1.25 -a xxxxxxxxx keys “*”


### 5.7 故障转移脚本(正式环境手动调用)

创建自动化故障转移脚本:

创建故障转移脚本

vim /usr/local/bin/redis_failover.sh

#!/bin/bash

Redis主从故障转移脚本 - 企业微信通知版

配置参数

MASTER_IP=”172.50.1.24”
SLAVE_IP=”172.50.1.25”
MASTER_PASSWORD=”xxxxxxxxx”
SLAVE_PASSWORD=”xxxxxxxxx”
WX_KEY=”ebc925fe-4279-4716-a7d7-96d0ba331f26”
WEBHOOK_URL=”https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${WX_KEY}”

发送企业微信消息函数

send_wechat_alert() {

local message="$1"
curl -H "Content-Type: application/json" \
     -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}" \
     "$WEBHOOK_URL" >/dev/null 2>&1

}

检查主节点状态

if redis-cli -h $MASTER_IP -a $MASTER_PASSWORD ping &>/dev/null; then

# 主节点正常,静默退出
exit 0

fi

主节点不可用,开始故障转移

检查从节点状态

if ! redis-cli -h $SLAVE_IP -a $SLAVE_PASSWORD ping &>/dev/null; then

send_wechat_alert "🚨 Redis故障转移失败\n主节点 $MASTER_IP 和从节点 $SLAVE_IP 均不可用,无法进行故障转移"
exit 1

fi

执行故障转移

redis-cli -h $SLAVE_IP -a $SLAVE_PASSWORD SLAVEOF NO ONE

验证故障转移结果

if redis-cli -h $SLAVE_IP -a $SLAVE_PASSWORD info replication | grep -q “role:master”; then

send_wechat_alert "✅ Redis故障转移成功\n主节点 $MASTER_IP 已故障,从节点 $SLAVE_IP 已成功提升为新的主节点,请及时更新应用配置"

else

send_wechat_alert "❌ Redis故障转移失败\n尝试将从节点 $SLAVE_IP 提升为主节点失败,请手动处理"
exit 1

fi


设置脚本权限:

chmod +x /usr/local/bin/redis_failover.sh


### 5.8 监控与告警

#### 5.8.1 创建监控脚本

创建监控脚本

vim /usr/local/bin/redis_monitor.sh

#!/bin/bash

Redis主从监控脚本

配置参数 - 请根据实际情况修改

MASTER_IP=”172.50.1.24”
SLAVE_IP=”172.50.1.25”
MASTER_PASSWORD=”xxxxxxxxx”
SLAVE_PASSWORD=”xxxxxxxxx”
WX_KEY=”ebc925fe-4279-4716-a7d7-96d0ba331f26”
WEBHOOK_URL=”https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${WX_KEY}”

状态文件路径

STATE_DIR=”/tmp/redis_monitor”
STATE_FILE=”$STATE_DIR/alert_state”
DEDUP_HOURS=12
DEDUP_SECONDS=$((DEDUP_HOURS * 3600))

创建状态目录

mkdir -p “$STATE_DIR”

发送企业微信消息函数

send_wechat_alert() {

local message="$1"
local alert_type="$2"
local current_time=$(date +%s)

# 检查是否应该发送告警
if should_send_alert "$alert_type" "$current_time"; then
    curl -H "Content-Type: application/json" \
         -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}" \
         "$WEBHOOK_URL" >/dev/null 2>&1

    # 更新发送时间
    update_alert_time "$alert_type" "$current_time"
fi

}

检查是否应该发送告警

should_send_alert() {

local alert_type="$1"
local current_time="$2"

# 如果状态文件不存在,允许发送
if [ ! -f "$STATE_FILE" ]; then
    return 0
fi

# 获取上次发送时间
local last_time=$(grep "^$alert_type:" "$STATE_FILE" | cut -d: -f2)

# 如果该类型告警从未发送过,允许发送
if [ -z "$last_time" ]; then
    return 0
fi

# 计算时间差
local time_diff=$((current_time - last_time))

# 如果时间差大于12小时,允许发送
if [ $time_diff -ge $DEDUP_SECONDS ]; then
    return 0
fi

return 1

}

更新告警发送时间

update_alert_time() {

local alert_type="$1"
local current_time="$2"

# 如果文件不存在,创建文件
if [ ! -f "$STATE_FILE" ]; then
    echo "$alert_type:$current_time" > "$STATE_FILE"
    return
fi

# 检查该类型告警是否已存在
if grep -q "^$alert_type:" "$STATE_FILE"; then
    # 更新已存在的记录
    sed -i "s/^$alert_type:.*/$alert_type:$current_time/" "$STATE_FILE"
else
    # 添加新记录
    echo "$alert_type:$current_time" >> "$STATE_FILE"
fi

}

清理过期状态(可选,保留7天前的记录)

cleanup_old_states() {

local current_time=$(date +%s)
local expire_seconds=$((7 * 24 * 3600))

if [ -f "$STATE_FILE" ]; then
    local temp_file=$(mktemp)
    while IFS=: read -r alert_type timestamp; do
        local time_diff=$((current_time - timestamp))
        if [ $time_diff -lt $expire_seconds ]; then
            echo "$alert_type:$timestamp" >> "$temp_file"
        fi
    done < "$STATE_FILE"
    mv "$temp_file" "$STATE_FILE"
fi

}

主监控逻辑

main() {

# 清理过期状态
cleanup_old_states

# 检查主节点状态
if ! /usr/local/bin/redis-cli -h $MASTER_IP -a $MASTER_PASSWORD ping &>/dev/null; then
    # 主节点异常
    if /usr/local/bin/redis-cli -h $SLAVE_IP -a $SLAVE_PASSWORD ping &>/dev/null; then
        send_wechat_alert "⚠️ Redis主节点故障告警\n主节点 $MASTER_IP 不可用,从节点 $SLAVE_IP 正常,请及时处理故障转移" "master_down"
    else
        send_wechat_alert "🚨 Redis集群故障告警\n主节点 $MASTER_IP 和从节点 $SLAVE_IP 均不可用,请立即处理!" "both_down"
    fi
else
    # 主节点正常,检查从节点状态
    if ! /usr/local/bin/redis-cli -h $SLAVE_IP -a $SLAVE_PASSWORD ping &>/dev/null; then
        send_wechat_alert "⚠️ Redis从节点故障告警\n主节点 $MASTER_IP 正常,但从节点 $SLAVE_IP 不可用,请检查从节点状态" "slave_down"
    else
        # 检查主从同步状态
        slave_count=$(/usr/local/bin/redis-cli -h $MASTER_IP -a $MASTER_PASSWORD info replication | grep "connected_slaves" | cut -d: -f2 | tr -d '\r')
        if [ "$slave_count" != "1" ]; then
            send_wechat_alert "⚠️ Redis主从同步异常\n主节点 $MASTER_IP 正常,但从节点同步异常,连接从节点数量:$slave_count" "sync_error"
        fi
    fi
fi

}

执行主函数

main


#### 5.8.2 设置定时监控
使用已创建的企业微信监控脚本(支持12小时去重功能):

复制脚本到系统目录

cp /usr/local/bin/redis_monitor_wechat.sh /usr/local/bin/redis_monitor.sh
cp /usr/local/bin/redis_failover_wechat.sh /usr/local/bin/redis_failover.sh

添加执行权限

chmod +x /usr/local/bin/redis_monitor.sh
chmod +x /usr/local/bin/redis_failover.sh

每5分钟检查一次(支持12小时去重,相同类型告警12小时内只发送一次)

echo “/5 * /usr/local/bin/redis_monitor.sh” | crontab -


#### 5.8.3 企业微信配置说明
1. **修改Webhook Key**:将脚本中的`WX_KEY`替换为你的实际企业微信群机器人key
2. **测试消息推送**:

# 测试监控脚本
/usr/local/bin/redis_monitor.sh

# 测试故障转移脚本
/usr/local/bin/redis_failover.sh

3. **12小时去重功能**:
   - 相同类型的告警12小时内只发送一次
   - 状态文件保存在`/tmp/redis_monitor/alert_state`
   - 支持4种告警类型独立去重:master_down、both_down、slave_down、sync_error
4. **手动重置告警**:如需立即重新发送告警,可删除状态文件

rm -f /tmp/redis_monitor/alert_state

5. **脚本位置**:监控脚本已放置在`script/redis_monitor.sh`和`script/redis_failover.sh`,可直接使用

### 5.9 注意事项

1. **数据一致性**:故障转移后,原主节点上的未同步数据可能会丢失
2. **客户端重连**:应用需要支持Redis连接重试和故障转移
3. **密码安全**:确保密码强度足够,定期更换密码
4. **监控告警**:建议配合监控系统(如Prometheus)实现自动告警
5. **备份策略**:定期执行数据备份,验证备份可用性
6. **测试演练**:定期进行故障转移演练,确保流程可靠

### 5.10 故障转移检查清单

- [ ] 确认主节点确实不可用
- [ ] 确认从节点数据是最新的
- [ ] 执行从节点升主操作
- [ ] 更新应用配置
- [ ] 验证服务可用性
- [ ] 通知相关人员
- [ ] 记录故障转移过程
- [ ] 安排原主节点修复
- [ ] 测试原主节点重新加入集群