Redis 持久化性能优化
持久化是 Redis 数据安全的基础,但不当的配置会严重影响性能。本文将深入持久化性能优化,分享实战经验。
一、性能影响分析
1.1 RDB 性能影响
RDB 的性能开销:
RDB 触发流程:
1. fork() 子进程(阻塞主线程)
2. 子进程写磁盘(不阻塞)
3. 父进程继续服务(可能受 fork 影响)
性能影响点:
┌─────────────────────────────────────┐
│ fork() 阻塞 │
│ - 数据量越大,阻塞越久 │
│ - 典型值:1GB 数据约 10-30ms │
├─────────────────────────────────────┤
│ 写磁盘 IO 竞争 │
│ - 子进程写 RDB 文件 │
│ - 可能影响主进程 IO │
├─────────────────────────────────────┤
│ 内存开销 │
│ - fork 使用 COW(写时复制) │
│ - 写操作频繁时,内存消耗增加 │
└─────────────────────────────────────┘
测试数据:
| 数据量 | fork 时间 | 推荐触发间隔 |
|---|---|---|
| 1GB | ~10ms | 每小时 |
| 5GB | ~50ms | 每 2 小时 |
| 10GB | ~100ms | 每 4 小时 |
| 50GB | ~500ms | 每天 |
1.2 AOF 性能影响
AOF 的性能开销:
AOF 写入流程:
1. 命令写入 AOF 缓冲区
2. 根据 appendfsync 策略刷盘
3. AOF 重写(定期)
性能影响点:
┌─────────────────────────────────────┐
│ 命令写入开销 │
│ - 每次写操作都要记录 AOF │
│ - 增加约 5-10% 延迟 │
├─────────────────────────────────────┤
│ 刷盘开销(appendfsync) │
│ - always:每次写操作都 fsync │
│ - everysec:每秒 fsync(推荐) │
│ - no:由 OS 决定 │
├─────────────────────────────────────┤
│ AOF 重写开销 │
│ - fork 子进程重写 │
│ - 类似 RDB 的 fork 阻塞 │
└─────────────────────────────────────┘
appendfsync 性能对比:
# 测试命令
redis-benchmark -q -t set -n 100000
# appendfsync always
# SET: 10000.00 requests per second (最慢)
# appendfsync everysec
# SET: 80000.00 requests per second (推荐)
# appendfsync no
# SET: 100000.00 requests per second (最快)
1.3 混合持久化性能
混合持久化的优势:
混合持久化性能特点:
1. AOF 重写时,前半部分写 RDB(快速)
2. 后半部分写增量命令(少量)
3. 总体比重写纯 AOF 快 30-50%
性能对比(10GB 数据):
┌─────────────────────────────────────┐
│ 纯 AOF 重写:~300 秒 │
│ 混合持久化:~180 秒 │
│ 提升:约 40% │
└─────────────────────────────────────┘
二、配置优化
2.1 RDB 优化配置
# ==================== 优化 save 配置 ====================
# 避免过于频繁的保存
# 不推荐:save 60 1000(太频繁)
# 推荐:
save 900 1 # 15 分钟至少 1 个键变化
save 300 10 # 5 分钟至少 10 个键变化
save 60 10000 # 1 分钟至少 10000 个键变化
# 或者完全关闭自动保存,手动触发
# save ""
# ==================== 优化 RDB 文件名 ====================
dbfilename dump.rdb
# ==================== 优化工作目录 ====================
# 使用 SSD 硬盘
dir /data/redis/ssd
# ==================== 压缩优化 ====================
# 开启 RDB 压缩(默认开启)
rdbcompression yes
# 压缩算法(Redis 5.0+)
# lzf:快速,压缩率低
# zstd:慢速,压缩率高
rdbcompression lzf
# ==================== 校验和 ====================
# 开启 RDB 校验和(轻微性能影响)
rdbchecksum yes
2.2 AOF 优化配置
# ==================== 基础配置 ====================
# 开启 AOF
appendonly yes
# AOF 文件名
appendfilename "appendonly.aof"
# AOF 目录(Redis 7.0+)
appenddirname "appendonlydir"
# ==================== 刷盘策略(关键) ====================
# 推荐:everysec(平衡性能和安全)
appendfsync everysec
# 高性能场景:no(可能丢失数据)
# appendfsync no
# 高安全场景:always(性能最低)
# appendfsync always
# ==================== 重写优化 ====================
# 重写期间不 fsync(避免 IO 竞争)
no-appendfsync-on-rewrite yes
# 自动重写触发条件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 128mb
# ==================== 混合持久化 ====================
# 开启混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes
# 加载截断的 AOF 文件
aof-load-truncated yes
# ==================== 重写触发优化 ====================
# 根据业务调整重写阈值
# 写操作频繁:提高阈值
auto-aof-rewrite-percentage 200
auto-aof-rewrite-min-size 512mb
# 写操作少:降低阈值
auto-aof-rewrite-percentage 50
auto-aof-rewrite-min-size 64mb
2.3 混合持久化优化
# 最佳实践配置
# 开启 AOF
appendonly yes
# 开启混合持久化
aof-use-rdb-preamble yes
# 每秒刷盘
appendfsync everysec
# 重写期间不 fsync
no-appendfsync-on-rewrite yes
# 合理设置重写阈值
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 256mb
# 允许加载不完整 AOF
aof-load-truncated yes
三、系统调优
3.1 磁盘 IO 优化
# ==================== 使用 SSD ====================
# 检查磁盘类型
lsblk -d -o name,rota
# 0 = SSD, 1 = HDD
# 查看磁盘性能
iostat -x 1
# ==================== 文件系统优化 ====================
# 使用 ext4 或 xfs
# 挂载选项优化
mount -o noatime,nodiratime,data=writeback /dev/sda1 /data
# /etc/fstab 配置
/dev/sda1 /data xfs noatime,nodiratime 0 0
# ==================== IO 调度器优化 ====================
# 查看当前调度器
cat /sys/block/sda/queue/scheduler
# 输出:[mq-deadline] kyber bfq none
# 设置为 none(SSD 推荐)
echo none > /sys/block/sda/queue/scheduler
# 永久生效
# /etc/default/grub
GRUB_CMDLINE_LINUX="elevator=none"
update-grub
# ==================== 预读取优化 ====================
# 减少预读取(Redis 是随机访问)
blockdev --setra 256 /dev/sda
# 查看当前值
blockdev --getra /dev/sda
3.2 内存优化
# ==================== 透明大页 ====================
# 禁用透明大页(避免 fork 延迟)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 永久生效
# /etc/rc.local
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# ==================== 过度分配 ====================
# 允许过度分配(避免 fork 失败)
echo 1 > /proc/sys/vm/overcommit_memory
# 永久生效
# /etc/sysctl.conf
vm.overcommit_memory = 1
# ==================== 交换空间 ====================
# 禁用 swap(或设置 swappiness=0)
sysctl vm.swappiness=0
swapoff -a
# 永久生效
# /etc/sysctl.conf
vm.swappiness = 0
3.3 网络优化
# ==================== TCP 参数 ====================
# /etc/sysctl.conf
# 增加 backlog
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 8192
# 快速回收
net.ipv4.tcp_tw_reuse = 1
# 保持连接
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 3
# 应用配置
sysctl -p
四、监控与诊断
4.1 关键指标监控
#!/bin/bash
# monitor_persistence.sh
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"
# 获取持久化信息
INFO=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT INFO Persistence)
# 提取关键指标
RDB_CHANGES=$(echo "$INFO" | grep "rdb_changes_since_last_save" | cut -d: -f2 | tr -d '\r')
RDB_LAST_TIME=$(echo "$INFO" | grep "rdb_last_save_time" | cut -d: -f2 | tr -d '\r')
RDB_LAST_STATUS=$(echo "$INFO" | grep "rdb_last_bgsave_status" | cut -d: -f2 | tr -d '\r')
RDB_LAST_TIME_SEC=$(echo "$INFO" | grep "rdb_last_bgsave_time_sec" | cut -d: -f2 | tr -d '\r')
AOF_ENABLED=$(echo "$INFO" | grep "aof_enabled" | cut -d: -f2 | tr -d '\r')
AOF_REWRITE=$(echo "$INFO" | grep "aof_rewrite_in_progress" | cut -d: -f2 | tr -d '\r')
AOF_LAST_TIME=$(echo "$INFO" | grep "aof_last_rewrite_time_sec" | cut -d: -f2 | tr -d '\r')
AOF_CUR_SIZE=$(echo "$INFO" | grep "aof_current_size" | cut -d: -f2 | tr -d '\r')
echo "=== RDB 指标 ==="
echo "上次保存后变化:$RDB_CHANGES"
echo "上次保存时间:$(date -d @$RDB_LAST_TIME)"
echo "上次保存状态:$RDB_LAST_STATUS"
echo "上次保存耗时:${RDB_LAST_TIME_SEC}秒"
echo ""
echo "=== AOF 指标 ==="
echo "AOF 开启:$AOF_ENABLED"
echo "重写进行中:$AOF_REWRITE"
echo "上次重写耗时:${AOF_LAST_TIME}秒"
echo "当前文件大小:$(($AOF_CUR_SIZE / 1024 / 1024))MB"
# 告警检查
if [ "$RDB_LAST_STATUS" != "ok" ]; then
echo "⚠️ 告警:RDB 保存失败"
fi
if [ "$RDB_LAST_TIME_SEC" -gt 300 ]; then
echo "⚠️ 告警:RDB 保存时间过长(>${RDB_LAST_TIME_SEC}秒)"
fi
if [ "$AOF_LAST_TIME" -gt 300 ]; then
echo "⚠️ 告警:AOF 重写时间过长(>${AOF_LAST_TIME}秒)"
fi
if [ "$AOF_CUR_SIZE" -gt 1073741824 ]; then
echo "⚠️ 告警:AOF 文件过大(>1GB)"
fi
4.2 慢查询监控
# 配置慢查询日志
redis-cli CONFIG SET slowlog-log-slower-than 10000 # 10ms
redis-cli CONFIG SET slowlog-max-len 128
# 查看慢查询
redis-cli SLOWLOG GET 10
# 输出示例
# 1) 1) (integer) 123
# 2) (integer) 1730793600
# 3) (integer) 15000
# 4) 1) "BGSAVE"
# 5) "127.0.0.1:6379"
# 6) ""
# 7) ""
# 分析慢查询
redis-cli SLOWLOG LEN
redis-cli SLOWLOG RESET
4.3 延迟监控
#!/bin/bash
# latency_monitor.sh
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"
echo "开始延迟监控(按 Ctrl+C 停止)..."
while true; do
# 测量 PING 延迟
START=$(date +%s%N)
redis-cli -h $REDIS_HOST -p $REDIS_PORT PING > /dev/null
END=$(date +%s%N)
LATENCY=$((($END - $START) / 1000000))
# 测量 SET 延迟
START=$(date +%s%N)
redis-cli -h $REDIS_HOST -p $REDIS_PORT SET __latency_test__ test > /dev/null
END=$(date +%s%N)
SET_LATENCY=$((($END - $START) / 1000000))
# 清理
redis-cli -h $REDIS_HOST -p $REDIS_PORT DEL __latency_test__ > /dev/null
echo "$(date '+%Y-%m-%d %H:%M:%S') - PING: ${LATENCY}ms, SET: ${SET_LATENCY}ms"
# 告警
if [ $LATENCY -gt 10 ]; then
echo "⚠️ PING 延迟过高:${LATENCY}ms"
fi
if [ $SET_LATENCY -gt 20 ]; then
echo "⚠️ SET 延迟过高:${SET_LATENCY}ms"
fi
sleep 1
done
4.4 使用 Redis 内置延迟监控
# Redis 2.8.13+ 提供延迟监控工具
# 延迟监控
redis-cli --latency
# 历史记录
redis-cli --latency-history -i 1
# 延迟分布
redis-cli --latency-dist
# 测试延迟
redis-cli --test-memory 1024
五、最佳实践
5.1 配置建议
# 生产环境推荐配置
# RDB 配置
save 900 1
save 300 10
save 60 10000
rdbcompression yes
rdbchecksum yes
# AOF 配置
appendonly yes
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 256mb
# 混合持久化
aof-use-rdb-preamble yes
aof-load-truncated yes
5.2 运维建议
-
定期检查持久化状态
# 每天检查 redis-cli INFO Persistence # 检查 RDB 文件 redis-check-rdb dump.rdb # 检查 AOF 文件 redis-check-aof appendonly.aof -
定期备份
# 备份脚本 # /usr/local/bin/redis-backup.sh BACKUP_DIR="/backup/redis" DATE=$(date +%Y%m%d_%H%M%S) # 触发 BGSAVE redis-cli BGSAVE # 等待完成 sleep 5 # 复制 RDB cp /var/lib/redis/dump.rdb $BACKUP_DIR/dump_$DATE.rdb # 删除 7 天前备份 find $BACKUP_DIR -name "dump_*.rdb" -mtime +7 -delete # 添加到 crontab # 0 2 * * * /usr/local/bin/redis-backup.sh -
性能基准测试
# 定期性能测试 redis-benchmark -q -t set,get -n 100000 -c 50 # 记录结果,对比历史数据 -
监控告警
- RDB/AOF 失败告警
- 持久化时间过长告警
- AOF 文件过大告警
- 延迟过高告警
5.3 故障处理
# 问题 1:RDB 保存失败
# 解决:检查磁盘空间、权限
df -h
ls -la /var/lib/redis/
# 问题 2:AOF 文件增长过快
# 解决:调整重写阈值
redis-cli CONFIG SET auto-aof-rewrite-percentage 200
redis-cli CONFIG SET auto-aof-rewrite-min-size 512mb
# 问题 3:fork 时间过长
# 解决:减少数据量、优化内存
# - 设置 maxmemory
# - 使用内存淘汰策略
redis-cli CONFIG SET maxmemory 4gb
redis-cli CONFIG SET maxmemory-policy allkeys-lru
# 问题 4:写延迟高
# 解决:调整刷盘策略
redis-cli CONFIG SET appendfsync everysec
# 或(如果可以接受数据丢失)
redis-cli CONFIG SET appendfsync no
六、总结
6.1 性能优化要点
-
RDB 优化
- 合理设置 save 条件
- 使用 SSD 硬盘
- 避免频繁 fork
-
AOF 优化
- 选择合适刷盘策略(推荐 everysec)
- 开启混合持久化
- 合理设置重写阈值
-
系统优化
- 禁用透明大页
- 允许过度分配
- 优化 IO 调度器
6.2 性能基准
| 配置 | QPS | 延迟 | 数据安全性 |
|---|---|---|---|
| appendfsync always | 10k | ~1ms | 最高 |
| appendfsync everysec | 80k | ~1ms | 高 |
| appendfsync no | 100k | ~0.5ms | 低 |
| 无持久化 | 120k | ~0.3ms | 无 |
参考资料
- Redis 官方文档 - Persistence
- Redis 性能调优指南
- 《Redis 设计与实现》第 13 章