1. Redis迁移概述

Redis数据迁移是运维工作中的重要环节,涉及数据备份、迁移、验证和集群管理等多个方面。本文将详细介绍Redis数据迁移与集群运维的实战经验,包括数据迁移策略、集群管理、故障处理、性能优化的完整解决方案。

1.1 核心功能

  1. 数据迁移: 不同Redis实例间的数据迁移
  2. 集群管理: Redis集群的部署、监控和管理
  3. 故障处理: 常见故障的诊断和处理
  4. 性能优化: 集群性能调优和监控
  5. 数据备份: 数据备份和恢复策略

1.2 技术架构

1
2
3
源Redis → 数据导出 → 数据转换 → 目标Redis → 数据验证
↓ ↓ ↓ ↓ ↓
备份策略 → 迁移工具 → 格式转换 → 集群部署 → 一致性检查

2. 环境准备

2.1 系统要求

1
2
3
4
5
6
7
8
9
10
11
12
# 检查系统版本
cat /etc/os-release

# 检查内存使用情况
free -h

# 检查磁盘空间
df -h

# 检查网络连接
ping redis-source-server
ping redis-target-server

2.2 Redis版本检查

1
2
3
4
5
6
7
8
# 检查源Redis版本
redis-cli -h source-server -p 6379 info server | grep redis_version

# 检查目标Redis版本
redis-cli -h target-server -p 6379 info server | grep redis_version

# 检查Redis配置
redis-cli -h source-server -p 6379 config get "*"

3. 数据迁移脚本

3.1 Redis数据导出脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/bin/bash
# redis_export.sh - Redis数据导出脚本
# @author 运维实战

# 配置参数
SOURCE_HOST="source-redis-server"
SOURCE_PORT="6379"
SOURCE_PASSWORD=""
EXPORT_FILE="/tmp/redis_export.rdb"
LOG_FILE="/var/log/redis_export.log"

# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

# 检查Redis连接
check_redis_connection() {
log "检查Redis连接..."

if [ -n "$SOURCE_PASSWORD" ]; then
redis-cli -h $SOURCE_HOST -p $SOURCE_PORT -a $SOURCE_PASSWORD ping
else
redis-cli -h $SOURCE_HOST -p $SOURCE_PORT ping
fi

if [ $? -eq 0 ]; then
log "Redis连接正常"
return 0
else
log "Redis连接失败"
return 1
fi
}

# 获取Redis信息
get_redis_info() {
log "获取Redis信息..."

if [ -n "$SOURCE_PASSWORD" ]; then
redis-cli -h $SOURCE_HOST -p $SOURCE_PORT -a $SOURCE_PASSWORD info > /tmp/redis_info.txt
else
redis-cli -h $SOURCE_HOST -p $SOURCE_PORT info > /tmp/redis_info.txt
fi

# 提取关键信息
DB_SIZE=$(grep "db0:keys=" /tmp/redis_info.txt | awk -F'=' '{print $2}' | awk -F',' '{print $1}')
USED_MEMORY=$(grep "used_memory_human:" /tmp/redis_info.txt | awk -F':' '{print $2}')

log "数据库大小: $DB_SIZE keys"
log "内存使用: $USED_MEMORY"
}

# 执行BGSAVE
execute_bgsave() {
log "执行BGSAVE..."

if [ -n "$SOURCE_PASSWORD" ]; then
redis-cli -h $SOURCE_HOST -p $SOURCE_PORT -a $SOURCE_PASSWORD bgsave
else
redis-cli -h $SOURCE_HOST -p $SOURCE_PORT bgsave
fi

# 等待BGSAVE完成
while true; do
if [ -n "$SOURCE_PASSWORD" ]; then
LASTSAVE=$(redis-cli -h $SOURCE_HOST -p $SOURCE_PORT -a $SOURCE_PASSWORD lastsave)
else
LASTSAVE=$(redis-cli -h $SOURCE_HOST -p $SOURCE_PORT lastsave)
fi

CURRENT_TIME=$(date +%s)
if [ $CURRENT_TIME -gt $LASTSAVE ]; then
log "BGSAVE完成"
break
fi

log "等待BGSAVE完成..."
sleep 5
done
}

# 复制RDB文件
copy_rdb_file() {
log "复制RDB文件..."

# 获取RDB文件路径
if [ -n "$SOURCE_PASSWORD" ]; then
RDB_PATH=$(redis-cli -h $SOURCE_HOST -p $SOURCE_PORT -a $SOURCE_PASSWORD config get dir | tail -1)
else
RDB_PATH=$(redis-cli -h $SOURCE_HOST -p $SOURCE_PORT config get dir | tail -1)
fi

RDB_FILE="$RDB_PATH/dump.rdb"

# 复制文件
scp $SOURCE_HOST:$RDB_FILE $EXPORT_FILE

if [ $? -eq 0 ]; then
log "RDB文件复制成功: $EXPORT_FILE"

# 检查文件大小
FILE_SIZE=$(ls -lh $EXPORT_FILE | awk '{print $5}')
log "RDB文件大小: $FILE_SIZE"
else
log "RDB文件复制失败"
exit 1
fi
}

# 主函数
main() {
log "开始Redis数据导出..."

# 检查Redis连接
if ! check_redis_connection; then
exit 1
fi

# 获取Redis信息
get_redis_info

# 执行BGSAVE
execute_bgsave

# 复制RDB文件
copy_rdb_file

log "Redis数据导出完成"
}

# 执行主函数
main "$@"

3.2 Redis数据导入脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/bin/bash
# redis_import.sh - Redis数据导入脚本
# @author 运维实战

# 配置参数
TARGET_HOST="target-redis-server"
TARGET_PORT="6379"
TARGET_PASSWORD=""
IMPORT_FILE="/tmp/redis_export.rdb"
LOG_FILE="/var/log/redis_import.log"

# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

# 检查目标Redis连接
check_target_redis() {
log "检查目标Redis连接..."

if [ -n "$TARGET_PASSWORD" ]; then
redis-cli -h $TARGET_HOST -p $TARGET_PORT -a $TARGET_PASSWORD ping
else
redis-cli -h $TARGET_HOST -p $TARGET_PORT ping
fi

if [ $? -eq 0 ]; then
log "目标Redis连接正常"
return 0
else
log "目标Redis连接失败"
return 1
fi
}

# 停止Redis服务
stop_redis_service() {
log "停止Redis服务..."

# 检查Redis进程
REDIS_PID=$(ps aux | grep redis-server | grep -v grep | awk '{print $2}')

if [ -n "$REDIS_PID" ]; then
log "停止Redis进程: $REDIS_PID"
kill -TERM $REDIS_PID

# 等待进程停止
while kill -0 $REDIS_PID 2>/dev/null; do
log "等待Redis进程停止..."
sleep 2
done

log "Redis服务已停止"
else
log "Redis服务未运行"
fi
}

# 备份现有数据
backup_existing_data() {
log "备份现有数据..."

# 获取Redis数据目录
if [ -n "$TARGET_PASSWORD" ]; then
DATA_DIR=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT -a $TARGET_PASSWORD config get dir | tail -1)
else
DATA_DIR=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT config get dir | tail -1)
fi

BACKUP_DIR="/tmp/redis_backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR

# 备份现有RDB文件
if [ -f "$DATA_DIR/dump.rdb" ]; then
cp "$DATA_DIR/dump.rdb" "$BACKUP_DIR/"
log "现有数据已备份到: $BACKUP_DIR"
else
log "未找到现有RDB文件"
fi
}

# 导入数据
import_data() {
log "导入数据..."

# 获取Redis数据目录
if [ -n "$TARGET_PASSWORD" ]; then
DATA_DIR=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT -a $TARGET_PASSWORD config get dir | tail -1)
else
DATA_DIR=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT config get dir | tail -1)
fi

# 复制RDB文件
cp $IMPORT_FILE "$DATA_DIR/dump.rdb"

if [ $? -eq 0 ]; then
log "数据导入成功"

# 设置文件权限
chown redis:redis "$DATA_DIR/dump.rdb"
chmod 644 "$DATA_DIR/dump.rdb"
else
log "数据导入失败"
exit 1
fi
}

# 启动Redis服务
start_redis_service() {
log "启动Redis服务..."

# 启动Redis服务
systemctl start redis

if [ $? -eq 0 ]; then
log "Redis服务启动成功"

# 等待服务完全启动
sleep 5

# 检查服务状态
if check_target_redis; then
log "Redis服务运行正常"
else
log "Redis服务启动失败"
exit 1
fi
else
log "Redis服务启动失败"
exit 1
fi
}

# 验证数据
verify_data() {
log "验证数据..."

# 获取数据库大小
if [ -n "$TARGET_PASSWORD" ]; then
DB_SIZE=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT -a $TARGET_PASSWORD dbsize)
else
DB_SIZE=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT dbsize)
fi

log "目标数据库大小: $DB_SIZE keys"

# 检查内存使用
if [ -n "$TARGET_PASSWORD" ]; then
USED_MEMORY=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT -a $TARGET_PASSWORD info memory | grep used_memory_human | awk -F':' '{print $2}')
else
USED_MEMORY=$(redis-cli -h $TARGET_HOST -p $TARGET_PORT info memory | grep used_memory_human | awk -F':' '{print $2}')
fi

log "内存使用: $USED_MEMORY"
}

# 主函数
main() {
log "开始Redis数据导入..."

# 检查目标Redis连接
if ! check_target_redis; then
exit 1
fi

# 备份现有数据
backup_existing_data

# 停止Redis服务
stop_redis_service

# 导入数据
import_data

# 启动Redis服务
start_redis_service

# 验证数据
verify_data

log "Redis数据导入完成"
}

# 执行主函数
main "$@"

4. Redis集群管理脚本

4.1 集群部署脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/bin/bash
# redis_cluster_deploy.sh - Redis集群部署脚本
# @author 运维实战

# 集群配置
CLUSTER_NODES=(
"192.168.1.10:7000"
"192.168.1.10:7001"
"192.168.1.11:7000"
"192.168.1.11:7001"
"192.168.1.12:7000"
"192.168.1.12:7001"
)

REDIS_VERSION="6.2.7"
REDIS_USER="redis"
REDIS_HOME="/opt/redis"
CLUSTER_CONFIG_DIR="/etc/redis/cluster"

# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 安装Redis
install_redis() {
log "安装Redis $REDIS_VERSION..."

# 下载Redis源码
cd /tmp
wget http://download.redis.io/releases/redis-$REDIS_VERSION.tar.gz
tar xzf redis-$REDIS_VERSION.tar.gz
cd redis-$REDIS_VERSION

# 编译安装
make && make install

if [ $? -eq 0 ]; then
log "Redis安装成功"
else
log "Redis安装失败"
exit 1
fi
}

# 创建Redis用户
create_redis_user() {
log "创建Redis用户..."

if ! id $REDIS_USER &>/dev/null; then
useradd -r -s /bin/false $REDIS_USER
log "Redis用户创建成功"
else
log "Redis用户已存在"
fi
}

# 创建目录结构
create_directories() {
log "创建目录结构..."

# 创建Redis主目录
mkdir -p $REDIS_HOME/{bin,conf,data,logs}

# 创建集群配置目录
mkdir -p $CLUSTER_CONFIG_DIR

# 设置权限
chown -R $REDIS_USER:$REDIS_USER $REDIS_HOME
chown -R $REDIS_USER:$REDIS_USER $CLUSTER_CONFIG_DIR

log "目录结构创建完成"
}

# 生成集群配置文件
generate_cluster_config() {
log "生成集群配置文件..."

for node in "${CLUSTER_NODES[@]}"; do
IFS=':' read -r host port <<< "$node"

# 生成配置文件
cat > $CLUSTER_CONFIG_DIR/redis-$port.conf << EOF
# Redis集群配置文件
port $port
bind $host
cluster-enabled yes
cluster-config-file nodes-$port.conf
cluster-node-timeout 5000
appendonly yes
appendfilename "appendonly-$port.aof"
dir $REDIS_HOME/data
logfile $REDIS_HOME/logs/redis-$port.log
pidfile /var/run/redis-$port.pid
daemonize yes
protected-mode no
EOF

log "配置文件生成: redis-$port.conf"
done
}

# 启动Redis节点
start_redis_nodes() {
log "启动Redis节点..."

for node in "${CLUSTER_NODES[@]}"; do
IFS=':' read -r host port <<< "$node"

# 启动Redis服务
redis-server $CLUSTER_CONFIG_DIR/redis-$port.conf

if [ $? -eq 0 ]; then
log "Redis节点启动成功: $host:$port"
else
log "Redis节点启动失败: $host:$port"
exit 1
fi
done
}

# 创建集群
create_cluster() {
log "创建Redis集群..."

# 等待所有节点启动
sleep 10

# 创建集群
redis-cli --cluster create "${CLUSTER_NODES[@]}" --cluster-replicas 1 --cluster-yes

if [ $? -eq 0 ]; then
log "Redis集群创建成功"
else
log "Redis集群创建失败"
exit 1
fi
}

# 验证集群
verify_cluster() {
log "验证Redis集群..."

# 检查集群状态
redis-cli -c -h 192.168.1.10 -p 7000 cluster nodes

# 检查集群信息
redis-cli -c -h 192.168.1.10 -p 7000 cluster info

log "集群验证完成"
}

# 主函数
main() {
log "开始Redis集群部署..."

# 安装Redis
install_redis

# 创建Redis用户
create_redis_user

# 创建目录结构
create_directories

# 生成集群配置文件
generate_cluster_config

# 启动Redis节点
start_redis_nodes

# 创建集群
create_cluster

# 验证集群
verify_cluster

log "Redis集群部署完成"
}

# 执行主函数
main "$@"

4.2 集群监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/bin/bash
# redis_cluster_monitor.sh - Redis集群监控脚本
# @author 运维实战

# 集群节点配置
CLUSTER_NODES=(
"192.168.1.10:7000"
"192.168.1.10:7001"
"192.168.1.11:7000"
"192.168.1.11:7001"
"192.168.1.12:7000"
"192.168.1.12:7001"
)

LOG_FILE="/var/log/redis_cluster_monitor.log"
ALERT_EMAIL="admin@example.com"

# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

# 检查节点状态
check_node_status() {
local node=$1
IFS=':' read -r host port <<< "$node"

# 检查节点是否响应
if redis-cli -h $host -p $port ping > /dev/null 2>&1; then
return 0
else
return 1
fi
}

# 获取节点信息
get_node_info() {
local node=$1
IFS=':' read -r host port <<< "$node"

# 获取节点状态
redis-cli -h $host -p $port info replication | grep -E "(role|master_host|master_port|connected_slaves)"
redis-cli -h $host -p $port info memory | grep -E "(used_memory_human|maxmemory_human)"
redis-cli -h $host -p $port info stats | grep -E "(total_commands_processed|instantaneous_ops_per_sec)"
}

# 检查集群状态
check_cluster_status() {
log "检查集群状态..."

local healthy_nodes=0
local total_nodes=${#CLUSTER_NODES[@]}

for node in "${CLUSTER_NODES[@]}"; do
if check_node_status $node; then
log "节点健康: $node"
((healthy_nodes++))
else
log "节点异常: $node"
send_alert "Redis节点异常: $node"
fi
done

log "健康节点数: $healthy_nodes/$total_nodes"

if [ $healthy_nodes -lt $total_nodes ]; then
send_alert "Redis集群节点异常,健康节点数: $healthy_nodes/$total_nodes"
fi
}

# 检查内存使用
check_memory_usage() {
log "检查内存使用..."

for node in "${CLUSTER_NODES[@]}"; do
IFS=':' read -r host port <<< "$node"

# 获取内存使用率
USED_MEMORY=$(redis-cli -h $host -p $port info memory | grep used_memory: | awk -F: '{print $2}')
MAX_MEMORY=$(redis-cli -h $host -p $port info memory | grep maxmemory: | awk -F: '{print $2}')

if [ "$MAX_MEMORY" != "0" ]; then
USAGE_PERCENT=$((USED_MEMORY * 100 / MAX_MEMORY))

if [ $USAGE_PERCENT -gt 80 ]; then
log "内存使用率过高: $node - $USAGE_PERCENT%"
send_alert "Redis内存使用率过高: $node - $USAGE_PERCENT%"
else
log "内存使用率正常: $node - $USAGE_PERCENT%"
fi
fi
done
}

# 检查复制延迟
check_replication_lag() {
log "检查复制延迟..."

for node in "${CLUSTER_NODES[@]}"; do
IFS=':' read -r host port <<< "$node"

# 获取节点角色
ROLE=$(redis-cli -h $host -p $port info replication | grep role: | awk -F: '{print $2}')

if [ "$ROLE" = "slave" ]; then
# 获取复制延迟
LAG=$(redis-cli -h $host -p $port info replication | grep master_repl_offset | awk -F: '{print $2}')

if [ $LAG -gt 1000000 ]; then
log "复制延迟过高: $node - $LAG"
send_alert "Redis复制延迟过高: $node - $LAG"
else
log "复制延迟正常: $node - $LAG"
fi
fi
done
}

# 发送告警
send_alert() {
local message=$1
log "发送告警: $message"

# 发送邮件告警
echo "$message" | mail -s "Redis集群告警" $ALERT_EMAIL

# 发送钉钉告警(如果有配置)
if [ -n "$DINGTALK_WEBHOOK" ]; then
curl -X POST "$DINGTALK_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}"
fi
}

# 生成监控报告
generate_report() {
log "生成监控报告..."

REPORT_FILE="/tmp/redis_cluster_report_$(date +%Y%m%d_%H%M%S).txt"

echo "Redis集群监控报告" > $REPORT_FILE
echo "生成时间: $(date)" >> $REPORT_FILE
echo "================================" >> $REPORT_FILE

for node in "${CLUSTER_NODES[@]}"; do
echo "节点: $node" >> $REPORT_FILE
get_node_info $node >> $REPORT_FILE
echo "------------------------" >> $REPORT_FILE
done

log "监控报告生成: $REPORT_FILE"
}

# 主函数
main() {
log "开始Redis集群监控..."

# 检查集群状态
check_cluster_status

# 检查内存使用
check_memory_usage

# 检查复制延迟
check_replication_lag

# 生成监控报告
generate_report

log "Redis集群监控完成"
}

# 执行主函数
main "$@"

5. 故障处理脚本

5.1 故障诊断脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/bin/bash
# redis_troubleshoot.sh - Redis故障诊断脚本
# @author 运维实战

# 配置参数
REDIS_HOST="localhost"
REDIS_PORT="6379"
REDIS_PASSWORD=""

# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 检查Redis服务状态
check_redis_service() {
log "检查Redis服务状态..."

# 检查进程
REDIS_PID=$(ps aux | grep redis-server | grep -v grep | awk '{print $2}')

if [ -n "$REDIS_PID" ]; then
log "Redis进程运行中: PID $REDIS_PID"
return 0
else
log "Redis进程未运行"
return 1
fi
}

# 检查Redis连接
check_redis_connection() {
log "检查Redis连接..."

if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD ping
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT ping
fi

if [ $? -eq 0 ]; then
log "Redis连接正常"
return 0
else
log "Redis连接失败"
return 1
fi
}

# 检查Redis配置
check_redis_config() {
log "检查Redis配置..."

# 检查配置文件
CONFIG_FILE="/etc/redis/redis.conf"

if [ -f "$CONFIG_FILE" ]; then
log "配置文件存在: $CONFIG_FILE"

# 检查关键配置
grep -E "^(bind|port|daemonize|logfile|dir)" $CONFIG_FILE
else
log "配置文件不存在: $CONFIG_FILE"
fi
}

# 检查Redis日志
check_redis_logs() {
log "检查Redis日志..."

# 检查日志文件
LOG_FILE="/var/log/redis/redis-server.log"

if [ -f "$LOG_FILE" ]; then
log "日志文件存在: $LOG_FILE"

# 检查最近的错误
tail -50 $LOG_FILE | grep -i error
else
log "日志文件不存在: $LOG_FILE"
fi
}

# 检查系统资源
check_system_resources() {
log "检查系统资源..."

# 检查内存使用
free -h

# 检查磁盘空间
df -h

# 检查CPU使用
top -bn1 | grep "Cpu(s)"
}

# 检查网络连接
check_network() {
log "检查网络连接..."

# 检查端口监听
netstat -tlnp | grep $REDIS_PORT

# 检查防火墙
iptables -L | grep $REDIS_PORT
}

# 修复常见问题
fix_common_issues() {
log "修复常见问题..."

# 检查并修复权限问题
REDIS_DATA_DIR="/var/lib/redis"

if [ -d "$REDIS_DATA_DIR" ]; then
chown -R redis:redis $REDIS_DATA_DIR
chmod 755 $REDIS_DATA_DIR
log "修复数据目录权限"
fi

# 检查并修复日志目录权限
REDIS_LOG_DIR="/var/log/redis"

if [ -d "$REDIS_LOG_DIR" ]; then
chown -R redis:redis $REDIS_LOG_DIR
chmod 755 $REDIS_LOG_DIR
log "修复日志目录权限"
fi
}

# 重启Redis服务
restart_redis_service() {
log "重启Redis服务..."

# 停止服务
systemctl stop redis

# 等待服务停止
sleep 5

# 启动服务
systemctl start redis

# 检查服务状态
if systemctl is-active --quiet redis; then
log "Redis服务重启成功"
return 0
else
log "Redis服务重启失败"
return 1
fi
}

# 主函数
main() {
log "开始Redis故障诊断..."

# 检查Redis服务状态
if ! check_redis_service; then
log "Redis服务未运行,尝试启动..."
systemctl start redis
sleep 5
fi

# 检查Redis连接
if ! check_redis_connection; then
log "Redis连接失败,检查配置..."
check_redis_config
check_redis_logs
check_system_resources
check_network

# 修复常见问题
fix_common_issues

# 重启服务
restart_redis_service
else
log "Redis服务运行正常"
fi

log "Redis故障诊断完成"
}

# 执行主函数
main "$@"

6. 性能优化脚本

6.1 性能调优脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/bin/bash
# redis_performance_tune.sh - Redis性能调优脚本
# @author 运维实战

# 配置参数
REDIS_HOST="localhost"
REDIS_PORT="6379"
REDIS_PASSWORD=""

# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 分析Redis性能
analyze_performance() {
log "分析Redis性能..."

# 获取性能指标
if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD info stats > /tmp/redis_stats.txt
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD info memory > /tmp/redis_memory.txt
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD info clients > /tmp/redis_clients.txt
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT info stats > /tmp/redis_stats.txt
redis-cli -h $REDIS_HOST -p $REDIS_PORT info memory > /tmp/redis_memory.txt
redis-cli -h $REDIS_HOST -p $REDIS_PORT info clients > /tmp/redis_clients.txt
fi

# 分析关键指标
TOTAL_COMMANDS=$(grep "total_commands_processed:" /tmp/redis_stats.txt | awk -F: '{print $2}')
INSTANTANEOUS_OPS=$(grep "instantaneous_ops_per_sec:" /tmp/redis_stats.txt | awk -F: '{print $2}')
USED_MEMORY=$(grep "used_memory_human:" /tmp/redis_memory.txt | awk -F: '{print $2}')
CONNECTED_CLIENTS=$(grep "connected_clients:" /tmp/redis_clients.txt | awk -F: '{print $2}')

log "总命令数: $TOTAL_COMMANDS"
log "每秒操作数: $INSTANTANEOUS_OPS"
log "内存使用: $USED_MEMORY"
log "连接客户端数: $CONNECTED_CLIENTS"
}

# 优化内存配置
optimize_memory() {
log "优化内存配置..."

# 获取当前内存配置
if [ -n "$REDIS_PASSWORD" ]; then
MAX_MEMORY=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config get maxmemory | tail -1)
else
MAX_MEMORY=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT config get maxmemory | tail -1)
fi

if [ "$MAX_MEMORY" = "0" ]; then
log "设置最大内存限制..."

# 获取系统内存
SYSTEM_MEMORY=$(free -m | grep Mem | awk '{print $2}')
REDIS_MEMORY=$((SYSTEM_MEMORY * 70 / 100)) # 使用70%的系统内存

if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config set maxmemory "${REDIS_MEMORY}mb"
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT config set maxmemory "${REDIS_MEMORY}mb"
fi

log "设置最大内存: ${REDIS_MEMORY}MB"
else
log "最大内存已设置: ${MAX_MEMORY}MB"
fi
}

# 优化持久化配置
optimize_persistence() {
log "优化持久化配置..."

# 检查当前持久化配置
if [ -n "$REDIS_PASSWORD" ]; then
SAVE_CONFIG=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config get save | tail -1)
APPENDONLY=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config get appendonly | tail -1)
else
SAVE_CONFIG=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT config get save | tail -1)
APPENDONLY=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT config get appendonly | tail -1)
fi

log "当前SAVE配置: $SAVE_CONFIG"
log "当前AOF配置: $APPENDONLY"

# 优化SAVE配置
if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config set save "900 1 300 10 60 10000"
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT config set save "900 1 300 10 60 10000"
fi

log "优化SAVE配置完成"
}

# 优化网络配置
optimize_network() {
log "优化网络配置..."

# 设置TCP keepalive
if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config set tcp-keepalive 60
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT config set tcp-keepalive 60
fi

# 设置超时时间
if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config set timeout 300
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT config set timeout 300
fi

log "网络配置优化完成"
}

# 优化客户端配置
optimize_clients() {
log "优化客户端配置..."

# 设置最大客户端数
if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config set maxclients 10000
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT config set maxclients 10000
fi

log "客户端配置优化完成"
}

# 保存配置
save_config() {
log "保存配置..."

if [ -n "$REDIS_PASSWORD" ]; then
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD config rewrite
else
redis-cli -h $REDIS_HOST -p $REDIS_PORT config rewrite
fi

log "配置保存完成"
}

# 主函数
main() {
log "开始Redis性能调优..."

# 分析性能
analyze_performance

# 优化内存配置
optimize_memory

# 优化持久化配置
optimize_persistence

# 优化网络配置
optimize_network

# 优化客户端配置
optimize_clients

# 保存配置
save_config

log "Redis性能调优完成"
}

# 执行主函数
main "$@"

7. 总结

Redis数据迁移与集群运维是运维工作中的重要组成部分。通过本文的详细介绍,我们了解了:

  1. 数据迁移: 使用RDB文件进行数据迁移
  2. 集群管理: Redis集群的部署、监控和管理
  3. 故障处理: 常见故障的诊断和处理
  4. 性能优化: 集群性能调优和监控
  5. 自动化运维: 脚本化运维提高效率

通过合理的运维策略和工具,可以确保Redis集群的稳定运行和高性能。


运维实战要点:

  • 数据迁移前做好备份,确保数据安全
  • 集群部署时注意网络配置和防火墙设置
  • 定期监控集群状态,及时发现问题
  • 性能调优需要根据实际业务场景进行
  • 故障处理要有完整的诊断流程

代码注解说明:

  • 日志函数: 统一日志格式,便于问题追踪
  • 错误处理: 完善的错误检查和异常处理
  • 配置管理: 灵活的配置参数管理
  • 监控告警: 实时监控和告警机制
  • 自动化运维: 脚本化运维提高效率