Redis 线上问题排查完整手册
本手册专门针对Redis生产环境故障排查,涵盖内存、性能、连接、数据一致性、集群架构等核心问题,提供详细的中文说明和实战经验总结。
🚨 快速诊断命令集合
Redis线上出现问题时,首先需要获取基本状态信息。以下命令可以快速了解Redis当前运行状况:
bash
# 1. 检查Redis服务是否正常响应
redis-cli ping
# 正常返回:PONG,如果无响应说明服务异常
# 2. 获取服务器基本信息(版本、运行时间、配置等)
redis-cli info server
# 3. 检查内存使用情况(最重要的监控指标)
redis-cli info memory
# 4. 查看操作统计信息(QPS、命令执行次数等)
redis-cli info stats
# 5. 检查主从复制状态
redis-cli info replication
# 6. 查看持久化相关信息
redis-cli info persistence
📅 一、内存问题深度排查
🔍 问题背景与成因
Redis内存问题是线上最常见的故障类型,主要包括:
- 内存泄漏:程序bug导致内存无法释放
- 大Key问题:单个key占用内存过大,影响性能
- 内存碎片:频繁的内存分配释放导致碎片化
- 过期策略失效:大量过期key未及时清理
- 配置不当:maxmemory设置过高或过期策略不合理
🎯 症状识别与判断
出现以下情况时,应重点排查内存问题:
- 系统层面:Redis进程被OOM Killer杀死,系统内存不足
- 应用层面:响应速度明显变慢,客户端连接超时
- 监控告警:内存使用率持续上升,达到告警阀值
- 业务影响:缓存命中率下降,数据库压力增大
🔧 详细排查步骤
第一步:检查整体内存使用情况
bash
# 获取详细的内存统计信息
redis-cli info memory
# 重点关注以下指标:
# used_memory_human: Redis实际使用内存(人类可读格式)
# used_memory_rss_human: 系统分配给Redis的物理内存
# mem_fragmentation_ratio: 内存碎片率(正常范围1.0-1.5)
# used_memory_peak_human: 历史内存使用峰值
# maxmemory_human: 设置的最大内存限制
第二步:识别和分析大Key
bash
# 扫描并统计各数据类型的大key(耗时较长,建议在从库执行)
redis-cli --bigkeys
# 手动检查特定key的内存占用(Redis 4.0+)
redis-cli memory usage key_name
# 批量检查多个key的内存使用情况
redis-cli --scan --pattern "user:*" | xargs -I {} redis-cli memory usage {}
# 分析key的详细结构(了解数据类型和元素数量)
redis-cli debug object key_name
第三步:检查过期key和清理策略
bash
# 查看各数据库的key统计信息
redis-cli info keyspace
# 输出示例:db0:keys=10000,expires=3000,avg_ttl=7200000
# 检查特定key的过期时间
redis-cli ttl key_name
# 返回值:-1(永不过期) -2(key不存在) >0(剩余秒数)
# 获取当前的过期策略配置
redis-cli config get maxmemory-policy
第四步:分析内存碎片情况
bash
# 获取详细的内存统计(Redis 4.0+)
redis-cli memory stats
# 查看内存分配器信息
redis-cli memory malloc-stats
💡 解决方案与优化策略
立即缓解内存压力
bash
# 1. 清理特定模式的过期key(谨慎使用,会阻塞服务)
redis-cli eval "
local keys = redis.call('keys', ARGV[1])
local count = 0
for i=1,#keys do
if redis.call('ttl', keys[i]) == -1 then
redis.call('del', keys[i])
count = count + 1
end
end
return count
" 0 "temp:*"
# 2. 手动触发内存碎片整理(Redis 4.0+)
redis-cli memory purge
# 3. 设置合理的内存限制和淘汰策略
redis-cli config set maxmemory 4gb
redis-cli config set maxmemory-policy allkeys-lru
长期优化措施
bash
# 1. 启用惰性删除,减少删除大key时的阻塞
redis-cli config set lazyfree-lazy-eviction yes
redis-cli config set lazyfree-lazy-expire yes
redis-cli config set lazyfree-lazy-server-del yes
# 2. 调整过期key的清理频率
redis-cli config set hz 100 # 增加后台任务频率
# 3. 优化数据结构,减少内存占用
# 例如:将大hash拆分为多个小hash
# 将长字符串压缩存储
⚡ 二、性能问题深度分析
🔍 问题背景与成因
Redis性能问题通常表现为响应延迟增加,主要原因包括:
- 慢查询命令:复杂度高的命令(如keys、sort等)
- 阻塞操作:持久化、主从同步等阻塞主线程
- 网络问题:带宽不足、网络延迟、连接池配置不当
- 系统资源:CPU、内存、磁盘IO成为瓶颈
- 配置问题:不合理的持久化配置、内存淘汰策略等
🎯 性能问题识别
以下现象提示可能存在性能问题:
- 响应延迟:平均响应时间超过正常基线
- 超时增加:客户端频繁出现连接或读取超时
- QPS下降:每秒处理请求数明显降低
- CPU异常:Redis进程CPU使用率异常高或异常低
🔧 性能排查详细步骤
第一步:检查慢查询日志
bash
# 获取最近的慢查询记录(默认显示10条)
redis-cli slowlog get 10
# 查看慢查询的配置阀值(微秒为单位)
redis-cli config get slowlog-log-slower-than
# 建议生产环境设置为10000微秒(10毫秒)
# 查看慢查询日志的最大长度
redis-cli config get slowlog-max-len
# 清空慢查询日志
redis-cli slowlog reset
第二步:分析连接和操作统计
bash
# 查看客户端连接信息
redis-cli info clients
# 重点关注:
# connected_clients: 当前连接数
# client_recent_max_input_buffer: 最大输入缓冲区
# client_recent_max_output_buffer: 最大输出缓冲区
# 查看详细的统计信息
redis-cli info stats
# 重点关注:
# total_commands_processed: 总命令执行数
# instantaneous_ops_per_sec: 当前QPS
# total_net_input_bytes: 网络输入字节数
# total_net_output_bytes: 网络输出字节数
第三步:实时监控命令执行
bash
# 实时监控所有执行的命令(生产环境慎用,影响性能)
redis-cli monitor
# 监控特定时间段的延迟情况
redis-cli --latency-history
# 每15秒输出一次延迟统计
# 监控内在延迟(内部操作延迟)
redis-cli --intrinsic-latency 60
# 运行60秒,检测系统本身的延迟
第四步:检查阻塞操作
bash
# 查看持久化相关信息
redis-cli info persistence
# 重点关注:
# rdb_bgsave_in_progress: 是否正在进行RDB备份
# aof_rewrite_in_progress: 是否正在进行AOF重写
# 查看最后一次成功保存的时间
redis-cli lastsave
# 查看主从同步延迟(在从库执行)
redis-cli info replication
# 关注master_repl_offset和slave_repl_offset的差值
💡 性能优化解决方案
慢查询优化
bash
# 1. 合理设置慢查询阀值(生产环境建议10ms)
redis-cli config set slowlog-log-slower-than 10000
# 2. 增加日志保存数量,便于分析
redis-cli config set slowlog-max-len 1000
# 3. 禁用或重命名危险的慢命令
redis-cli config set rename-command-keys "KEYS_DANGEROUS"
redis-cli config set rename-command-flushall "FLUSHALL_DANGEROUS"
持久化优化
bash
# 1. 调整RDB持久化策略(减少频率)
redis-cli config set save "1800 1 600 100 300 1000"
# 含义:1800秒内至少1个key改变,或600秒内100个key改变,或300秒内1000个key改变
# 2. 优化AOF配置
redis-cli config set appendonly yes
redis-cli config set appendfsync everysec # 每秒同步一次
redis-cli config set auto-aof-rewrite-percentage 100
redis-cli config set auto-aof-rewrite-min-size 128mb
网络和连接优化
bash
# 1. 启用TCP长连接保活
redis-cli config set tcp-keepalive 300
# 2. 调整客户端连接超时
redis-cli config set timeout 0 # 0表示不超时,根据实际情况调整
# 3. 限制单个客户端的输出缓冲区大小
redis-cli config set client-output-buffer-limit "normal 0 0 0"
🔌 三、连接问题完全排查指南
🔍 连接问题的常见场景
Redis连接问题在高并发环境下特别常见,主要包括:
- 连接数耗尽:达到maxclients限制,新连接被拒绝
- 连接池配置不当:客户端连接池参数设置不合理
- 网络问题:网络不稳定、防火墙限制、DNS解析问题
- 认证问题:密码错误、权限不足
- 系统资源限制:操作系统的文件描述符限制
🎯 连接问题症状
- 连接拒绝:客户端报"Connection refused"错误
- 连接超时:建立连接时间过长或读取超时
- 连接不稳定:连接频繁断开重连
- 连接池耗尽:应用报连接池获取不到连接
🔧 连接问题排查步骤
第一步:检查当前连接状态
bash
# 查看连接统计信息
redis-cli info clients
# 重点指标说明:
# connected_clients: 当前连接的客户端数量
# client_recent_max_input_buffer: 最近客户端最大输入缓冲区大小
# client_recent_max_output_buffer: 最近客户端最大输出缓冲区大小
# blocked_clients: 被阻塞的客户端数量(通常是BLPOP等阻塞命令)
# 获取最大客户端连接数配置
redis-cli config get maxclients
第二步:分析具体的连接详情
bash
# 查看所有客户端连接的详细信息
redis-cli client list
# 输出包含每个连接的:
# - addr: 客户端地址和端口
# - fd: 文件描述符
# - name: 连接名称
# - age: 连接存活时间
# - idle: 空闲时间
# - flags: 连接标志
# - db: 当前数据库
# - sub/psub: 订阅的频道数
# 按连接时间排序,查找异常连接
redis-cli client list | sort -k4 -n
第三步:检查网络和系统配置
bash
# 检查Redis网络相关配置
redis-cli config get bind # 绑定的IP地址
redis-cli config get port # 端口号
redis-cli config get protected-mode # 保护模式
redis-cli config get timeout # 客户端超时时间
redis-cli config get tcp-keepalive # TCP保活时间
# 在系统层面检查网络连接(需要系统管理员权限)
netstat -tlnp | grep 6379 # 查看Redis端口监听状态
ss -tnlp | grep 6379 # 使用ss命令查看连接状态(推荐)
💡 连接问题解决方案
连接数限制优化
bash
# 1. 增加最大客户端连接数(根据服务器性能调整)
redis-cli config set maxclients 2000
# 2. 设置合理的客户端超时时间
redis-cli config set timeout 300 # 5分钟超时
# 3. 启用TCP keepalive,及时清理死连接
redis-cli config set tcp-keepalive 300 # 5分钟保活探测
强制清理异常连接
bash
# 1. 根据IP地址杀死特定客户端连接
redis-cli client kill ip 192.168.1.100
# 2. 杀死空闲时间超过指定秒数的连接
redis-cli client kill idle 3600 # 杀死空闲1小时以上的连接
# 3. 根据连接类型杀死连接
redis-cli client kill type normal # 杀死普通连接
redis-cli client kill type master # 杀死主从复制连接(谨慎使用)
# 4. 批量清理异常连接的脚本
redis-cli eval "
local clients = redis.call('client', 'list')
local killed = 0
for client in clients:gmatch('[^\r\n]+') do
local idle = client:match('idle=(%d+)')
if idle and tonumber(idle) > 7200 then -- 空闲超过2小时
local addr = client:match('addr=([%d%.]+:%d+)')
if addr then
redis.call('client', 'kill', 'addr', addr)
killed = killed + 1
end
end
end
return killed
" 0
系统级优化
bash
# 检查系统文件描述符限制
ulimit -n
# 临时增加文件描述符限制(需要root权限)
ulimit -n 65535
# 永久修改(编辑 /etc/security/limits.conf)
echo "redis soft nofile 65535" >> /etc/security/limits.conf
echo "redis hard nofile 65535" >> /etc/security/limits.conf
📦 四、数据一致性问题深度诊断
🔍 数据一致性问题类型
数据一致性是Redis集群和主从架构中的核心问题:
- 主从数据不同步:网络延迟、配置错误导致主从数据差异
- 数据意外丢失:持久化配置问题、服务器故障、误操作
- 缓存穿透:大量请求未命中缓存,直接冲击数据库
- 缓存雪崩:大量缓存同时失效,系统压力激增
- 脑裂问题:网络分区导致出现多个主节点
🎯 数据问题识别标准
- 业务层面:数据查询结果不一致,缓存命中率异常低
- 监控指标:主从延迟过大,持久化失败告警
- 系统表现:数据库负载突增,应用响应慢
🔧 数据一致性排查流程
第一步:检查主从复制状态
bash
# 在主库执行,检查主库状态
redis-cli info replication
# 重点关注:
# role:master # 确认当前实例角色
# connected_slaves:1 # 连接的从库数量
# master_repl_offset:12345 # 主库复制偏移量
# 在从库执行,检查从库状态
redis-cli info replication
# 重点关注:
# role:slave # 确认从库角色
# master_host:192.168.1.10 # 主库地址
# master_port:6379 # 主库端口
# master_link_status:up # 与主库连接状态
# slave_repl_offset:12340 # 从库复制偏移量
# slave_read_only:1 # 是否只读模式
第二步:检查数据同步延迟
bash
# 计算主从同步延迟
# 主库偏移量 - 从库偏移量 = 延迟的字节数
# 在主库写入测试数据
redis-cli set sync_test_$(date +%s) "test_value"
# 立即在从库检查是否同步
redis-cli get sync_test_$(date +%s)
# 检查复制积压缓冲区配置
redis-cli config get repl-backlog-size
redis-cli config get repl-backlog-ttl
第三步:验证持久化完整性
bash
# 检查持久化状态
redis-cli info persistence
# 重点关注:
# rdb_last_save_time:1609459200 # 最后RDB保存时间
# rdb_last_bgsave_status:ok # 最后备份状态
# aof_enabled:1 # AOF是否启用
# aof_last_write_status:ok # AOF写入状态
# 检查持久化文件
redis-cli config get dir # 获取数据目录
redis-cli config get dbfilename # 获取RDB文件名
redis-cli config get appendfilename # 获取AOF文件名
# 手动触发持久化测试
redis-cli bgsave # 后台保存RDB
redis-cli bgrewriteaof # 重写AOF文件
第四步:检查key过期和淘汰策略
bash
# 检查内存淘汰策略
redis-cli config get maxmemory-policy
# 常见策略:
# noeviction: 不淘汰,内存满时报错
# allkeys-lru: 所有key中淘汰最近最少使用
# volatile-lru: 有过期时间的key中淘汰LRU
# allkeys-random: 随机淘汰key
# 检查key的过期情况
redis-cli ttl important_key # 检查重要key的过期时间
redis-cli pttl important_key # 以毫秒为单位检查过期时间
# 统计各数据库的key数量和过期key数量
redis-cli info keyspace
💡 数据一致性修复方案
主从同步问题修复
bash
# 1. 重新建立主从关系(在从库执行)
redis-cli slaveof no one # 取消主从关系
redis-cli flushall # 清空从库数据(谨慎操作)
redis-cli slaveof 192.168.1.10 6379 # 重新设置主库
# 2. 调整复制缓冲区大小,减少全量同步概率
redis-cli config set repl-backlog-size 64mb # 增大积压缓冲区
redis-cli config set repl-backlog-ttl 7200 # 延长缓冲区保留时间
# 3. 优化网络和同步参数
redis-cli config set repl-timeout 60 # 复制超时时间
redis-cli config set repl-ping-slave-period 10 # 主库ping从库间隔
数据恢复操作
bash
# 1. 从RDB文件恢复数据
redis-cli shutdown nosave # 关闭服务但不保存
# 替换dump.rdb文件到数据目录
redis-server /path/to/redis.conf # 重启服务
# 2. 从AOF文件恢复数据
redis-cli config set appendonly yes
redis-cli debug reload # 重新加载持久化数据
# 3. 修复损坏的AOF文件
redis-check-aof --fix /path/to/appendonly.aof
防止数据丢失的预防措施
bash
# 1. 同时启用RDB和AOF双重保障
redis-cli config set save "900 1 300 10 60 1000" # RDB策略
redis-cli config set appendonly yes # 启用AOF
redis-cli config set appendfsync everysec # 每秒同步AOF
# 2. 配置最小写入成功数量(集群环境)
redis-cli config set min-slaves-to-write 1 # 至少1个从库写入成功
redis-cli config set min-slaves-max-lag 10 # 从库延迟不超过10秒
# 3. 设置关键业务数据不过期
redis-cli persist critical_business_key # 移除key的过期时间
🔧 五、集群架构问题排查
🔍 Redis集群常见问题
Redis集群在大规模部署中面临诸多挑战:
- 节点故障:服务器宕机、网络中断导致节点不可用
- 槽位迁移失败:数据重分布过程中的异常
- 脑裂问题:网络分区导致集群分裂
- 选举问题:主节点选举失败或选举时间过长
- 数据倾斜:某些节点数据量过大,负载不均衡
🔧 集群状态检查
集群整体状态诊断
bash
# 1. 检查集群基本信息
redis-cli cluster info
# 重点关注:
# cluster_state:ok # 集群状态是否正常
# cluster_slots_assigned:16384 # 已分配的槽位数量
# cluster_slots_ok:16384 # 正常的槽位数量
# cluster_slots_pfail:0 # 可能故障的槽位
# cluster_slots_fail:0 # 确认故障的槽位
# cluster_known_nodes:6 # 已知节点数量
# 2. 查看所有节点信息
redis-cli cluster nodes
# 输出格式:节点ID 地址:端口 角色 主节点ID 连接状态 槽位范围
# 3. 检查槽位分配情况
redis-cli cluster slots
# 显示每个槽位范围对应的主从节点信息
节点健康状态检查
bash
# 1. 检查特定节点的连接状态
redis-cli -h 192.168.1.10 -p 7001 ping
# 2. 批量检查所有节点状态
for port in 7001 7002 7003 7004 7005 7006; do
echo "检查节点 192.168.1.10:$port"
redis-cli -h 192.168.1.10 -p $port ping
done
# 3. 检查节点间的网络连通性
redis-cli cluster meet 192.168.1.11 7001 # 添加新节点到集群
集群数据一致性验证
bash
# 1. 验证集群数据分布
redis-cli --cluster check 192.168.1.10:7001
# 自动检查集群状态和数据分布
# 2. 检查特定key在哪个节点
redis-cli cluster keyslot mykey # 获取key对应的槽位
redis-cli cluster nodes | grep "0-5460" # 查找负责该槽位的节点
# 3. 验证集群中的数据一致性
redis-cli --cluster call 192.168.1.10:7001 info replication
# 在所有节点执行相同命令,比较结果
💡 集群问题解决方案
故障节点恢复
bash
# 1. 移除完全故障的节点
redis-cli cluster forget <node-id> # 从集群中移除节点
# 2. 重新加入修复后的节点
redis-cli cluster meet <ip> <port> # 重新加入集群
redis-cli cluster replicate <master-node-id> # 设置为从节点
# 3. 替换故障的主节点
redis-cli cluster failover # 在从节点执行,强制故障转移
redis-cli cluster failover force # 强制故障转移(即使主节点正常)
槽位重新分配
bash
# 1. 手动迁移槽位(需要redis-cli --cluster)
redis-cli --cluster reshard 192.168.1.10:7001
# 交互式界面,指定迁移的槽位数量和目标节点
# 2. 修复槽位分配异常
redis-cli --cluster fix 192.168.1.10:7001
# 自动修复集群中的常见问题
# 3. 重新平衡集群
redis-cli --cluster rebalance 192.168.1.10:7001
# 自动调整各节点的槽位分配,使负载更均衡
# 4. 手动分配特定槽位
redis-cli cluster addslots {0..1000} # 分配槽位0-1000给当前节点
redis-cli cluster delslots {0..1000} # 从当前节点删除槽位0-1000
集群扩容和缩容
bash
# 集群扩容:添加新节点
# 1. 启动新的Redis节点
redis-server --port 7007 --cluster-enabled yes --cluster-config-file nodes-7007.conf
# 2. 将新节点加入集群
redis-cli --cluster add-node 192.168.1.10:7007 192.168.1.10:7001
# 3. 为新节点分配槽位
redis-cli --cluster reshard 192.168.1.10:7001
# 集群缩容:移除节点
# 1. 迁移节点上的槽位
redis-cli --cluster reshard --cluster-from <node-id> --cluster-to <target-node-id> --cluster-slots 1000 192.168.1.10:7001
# 2. 移除空节点
redis-cli --cluster del-node 192.168.1.10:7001 <node-id>
📋 六、专业运维监控脚本
🔍 全方位健康检查脚本
bash
#!/bin/bash
# Redis生产环境健康检查脚本
# 使用方法: ./redis_health_check.sh [redis-host] [redis-port]
REDIS_HOST=${1:-127.0.0.1}
REDIS_PORT=${2:-6379}
REDIS_CLI="redis-cli -h $REDIS_HOST -p $REDIS_PORT"
echo "========================================"
echo "Redis健康检查报告 - $(date)"
echo "目标服务器: $REDIS_HOST:$REDIS_PORT"
echo "========================================"
# 1. 基础连接测试
echo "🔍 1. 基础连接检查"
if $REDIS_CLI ping > /dev/null 2>&1; then
echo "✅ Redis服务正常响应"
# 获取基本信息
VERSION=$($REDIS_CLI info server | grep redis_version | cut -d: -f2 | tr -d '\r')
UPTIME=$($REDIS_CLI info server | grep uptime_in_seconds | cut -d: -f2 | tr -d '\r')
echo " 版本: $VERSION"
echo " 运行时间: $((UPTIME/86400))天 $((UPTIME%86400/3600))小时"
else
echo "❌ Redis服务无响应,请检查服务状态和网络连接"
exit 1
fi
# 2. 内存使用情况
echo -e "\n🧠 2. 内存使用分析"
USED_MEMORY=$($REDIS_CLI info memory | grep "used_memory_human" | head -1 | cut -d: -f2 | tr -d '\r')
RSS_MEMORY=$($REDIS_CLI info memory | grep "used_memory_rss_human" | cut -d: -f2 | tr -d '\r')
FRAG_RATIO=$($REDIS_CLI info memory | grep "mem_fragmentation_ratio" | cut -d: -f2 | tr -d '\r')
MAX_MEMORY=$($REDIS_CLI config get maxmemory | tail -1)
echo " 使用内存: $USED_MEMORY"
echo " 物理内存: $RSS_MEMORY"
echo " 碎片率: $FRAG_RATIO"
echo " 内存限制: $(if [ "$MAX_MEMORY" = "0" ]; then echo "无限制"; else echo "${MAX_MEMORY}字节"; fi)"
# 判断内存状况
if (( $(echo "$FRAG_RATIO > 2.0" | bc -l) )); then
echo "⚠️ 警告: 内存碎片率过高($FRAG_RATIO),建议进行内存整理"
fi
# 3. 连接状态检查
echo -e "\n🔗 3. 连接状态分析"
CONNECTED_CLIENTS=$($REDIS_CLI info clients | grep "connected_clients" | cut -d: -f2 | tr -d '\r')
MAX_CLIENTS=$($REDIS_CLI config get maxclients | tail -1)
BLOCKED_CLIENTS=$($REDIS_CLI info clients | grep "blocked_clients" | cut -d: -f2 | tr -d '\r')
echo " 当前连接数: $CONNECTED_CLIENTS"
echo " 最大连接数: $MAX_CLIENTS"
echo " 阻塞连接数: $BLOCKED_CLIENTS"
# 连接数使用率检查
CONNECTION_USAGE=$((CONNECTED_CLIENTS * 100 / MAX_CLIENTS))
if [ $CONNECTION_USAGE -gt 80 ]; then
echo "⚠️ 警告: 连接数使用率 ${CONNECTION_USAGE}%,接近上限"
fi
# 4. 性能指标检查
echo -e "\n⚡ 4. 性能指标分析"
OPS_PER_SEC=$($REDIS_CLI info stats | grep "instantaneous_ops_per_sec" | cut -d: -f2 | tr -d '\r')
TOTAL_COMMANDS=$($REDIS_CLI info stats | grep "total_commands_processed" | cut -d: -f2 | tr -d '\r')
SLOWLOG_LEN=$($REDIS_CLI slowlog len)
echo " 当前QPS: $OPS_PER_SEC"
echo " 总命令数: $TOTAL_COMMANDS"
echo " 慢查询数: $SLOWLOG_LEN"
if [ $SLOWLOG_LEN -gt 100 ]; then
echo "⚠️ 警告: 慢查询数量较多($SLOWLOG_LEN),建议检查慢查询日志"
echo " 最近3条慢查询:"
$REDIS_CLI slowlog get 3 | grep -E "^\d+\)" -A 3
fi
# 5. 持久化状态
echo -e "\n💾 5. 持久化状态检查"
RDB_LAST_SAVE=$($REDIS_CLI info persistence | grep "rdb_last_save_time" | cut -d: -f2 | tr -d '\r')
AOF_ENABLED=$($REDIS_CLI info persistence | grep "aof_enabled" | cut -d: -f2 | tr -d '\r')
RDB_STATUS=$($REDIS_CLI info persistence | grep "rdb_last_bgsave_status" | cut -d: -f2 | tr -d '\r')
CURRENT_TIME=$(date +%s)
LAST_SAVE_AGO=$((CURRENT_TIME - RDB_LAST_SAVE))
echo " RDB状态: $RDB_STATUS"
echo " 上次保存: $((LAST_SAVE_AGO/3600))小时前"
echo " AOF启用: $(if [ "$AOF_ENABLED" = "1" ]; then echo "是"; else echo "否"; fi)"
if [ $LAST_SAVE_AGO -gt 21600 ]; then # 6小时
echo "⚠️ 警告: RDB备份时间过久,建议检查持久化配置"
fi
# 6. 主从复制状态(如果适用)
echo -e "\n🔄 6. 主从复制检查"
ROLE=$($REDIS_CLI info replication | grep "role" | cut -d: -f2 | tr -d '\r')
echo " 当前角色: $ROLE"
if [ "$ROLE" = "master" ]; then
CONNECTED_SLAVES=$($REDIS_CLI info replication | grep "connected_slaves" | cut -d: -f2 | tr -d '\r')
echo " 连接的从库: $CONNECTED_SLAVES"
elif [ "$ROLE" = "slave" ]; then
MASTER_LINK_STATUS=$($REDIS_CLI info replication | grep "master_link_status" | cut -d: -f2 | tr -d '\r')
MASTER_LAST_IO=$($REDIS_CLI info replication | grep "master_last_io_seconds_ago" | cut -d: -f2 | tr -d '\r')
echo " 主库连接状态: $MASTER_LINK_STATUS"
echo " 上次同步: ${MASTER_LAST_IO}秒前"
if [ "$MASTER_LINK_STATUS" != "up" ]; then
echo "❌ 错误: 与主库连接异常"
fi
fi
# 7. 集群状态检查(如果启用)
if $REDIS_CLI cluster info > /dev/null 2>&1; then
echo -e "\n🔧 7. 集群状态检查"
CLUSTER_STATE=$($REDIS_CLI cluster info | grep "cluster_state" | cut -d: -f2 | tr -d '\r')
CLUSTER_NODES=$($REDIS_CLI cluster info | grep "cluster_known_nodes" | cut -d: -f2 | tr -d '\r')
echo " 集群状态: $CLUSTER_STATE"
echo " 节点数量: $CLUSTER_NODES"
if [ "$CLUSTER_STATE" != "ok" ]; then
echo "❌ 错误: 集群状态异常"
fi
fi
# 8. 总结建议
echo -e "\n📋 8. 健康检查总结"
echo "✅ 基础功能: 正常"
echo "$(if (( $(echo "$FRAG_RATIO > 2.0" | bc -l) )); then echo "⚠️ 内存碎片: 需要关注"; else echo "✅ 内存状态: 良好"; fi)"
echo "$(if [ $CONNECTION_USAGE -gt 80 ]; then echo "⚠️ 连接使用: 需要关注"; else echo "✅ 连接状态: 正常"; fi)"
echo "$(if [ $SLOWLOG_LEN -gt 100 ]; then echo "⚠️ 性能状态: 需要优化"; else echo "✅ 性能状态: 良好"; fi)"
echo "$(if [ $LAST_SAVE_AGO -gt 21600 ]; then echo "⚠️ 持久化: 需要检查"; else echo "✅ 持久化: 正常"; fi)"
echo -e "\n========================================"
echo "检查完成时间: $(date)"
echo "========================================"
🚨 性能监控脚本
bash
#!/bin/bash
# Redis性能实时监控脚本
# 使用方法: ./redis_performance_monitor.sh [interval]
REDIS_CLI="redis-cli"
INTERVAL=${1:-5} # 监控间隔,默认5秒
echo "Redis性能监控 - 间隔${INTERVAL}秒,按Ctrl+C停止"
echo "时间 QPS 连接数 内存使用 慢查询 延迟(ms) 键空间"
echo "=============================================================="
while true; do
TIMESTAMP=$(date +"%H:%M:%S")
# 获取QPS
QPS=$($REDIS_CLI info stats | grep instantaneous_ops_per_sec | cut -d: -f2 | tr -d '\r')
# 获取连接数
CLIENTS=$($REDIS_CLI info clients | grep connected_clients | cut -d: -f2 | tr -d '\r')
# 获取内存使用
MEMORY=$($REDIS_CLI info memory | grep used_memory_human | head -1 | cut -d: -f2 | tr -d '\r')
# 获取慢查询数量
SLOWLOG=$($REDIS_CLI slowlog len)
# 测试延迟(简化版本)
START_TIME=$(date +%s%N)
$REDIS_CLI ping > /dev/null
END_TIME=$(date +%s%N)
LATENCY=$(((END_TIME - START_TIME) / 1000000))
# 获取键空间信息
KEYSPACE=$($REDIS_CLI info keyspace | grep "db0:" | cut -d: -f2 | cut -d, -f1 | cut -d= -f2)
KEYSPACE=${KEYSPACE:-0}
printf "%-8s %6s %8s %10s %8s %8s %8s\n" "$TIMESTAMP" "$QPS" "$CLIENTS" "$MEMORY" "$SLOWLOG" "$LATENCY" "$KEYSPACE"
sleep $INTERVAL
done
📊 集群监控脚本
bash
#!/bin/bash
# Redis集群状态监控脚本
# 使用方法: ./redis_cluster_monitor.sh <cluster-node-ip:port>
CLUSTER_NODE=${1:-127.0.0.1:7001}
REDIS_CLI="redis-cli -c -h $(echo $CLUSTER_NODE | cut -d: -f1) -p $(echo $CLUSTER_NODE | cut -d: -f2)"
echo "Redis集群监控 - 节点: $CLUSTER_NODE"
echo "========================================"
# 检查集群基本状态
echo "🔧 集群基本状态:"
CLUSTER_STATE=$($REDIS_CLI cluster info | grep cluster_state | cut -d: -f2)
CLUSTER_NODES_COUNT=$($REDIS_CLI cluster info | grep cluster_known_nodes | cut -d: -f2)
CLUSTER_SIZE=$($REDIS_CLI cluster info | grep cluster_size | cut -d: -f2)
echo " 集群状态: $CLUSTER_STATE"
echo " 节点总数: $CLUSTER_NODES_COUNT"
echo " 集群大小: $CLUSTER_SIZE"
# 检查各节点状态
echo -e "\n📊 节点详细状态:"
echo "节点ID 地址:端口 角色 状态 槽位数量"
echo "================================================================================="
$REDIS_CLI cluster nodes | while read line; do
NODE_ID=$(echo $line | awk '{print $1}' | head -c 8)
ADDRESS=$(echo $line | awk '{print $2}')
FLAGS=$(echo $line | awk '{print $3}')
SLOTS=$(echo $line | grep -o '\[.*\]' | wc -l)
# 解析角色
if [[ $FLAGS == *"master"* ]]; then
ROLE="主节点"
elif [[ $FLAGS == *"slave"* ]]; then
ROLE="从节点"
else
ROLE="未知"
fi
# 解析状态
if [[ $FLAGS == *"fail"* ]]; then
STATUS="故障"
elif [[ $FLAGS == *"handshake"* ]]; then
STATUS="握手中"
else
STATUS="正常"
fi
printf "%-8s... %-18s %-8s %-8s %8s\n" "$NODE_ID" "$ADDRESS" "$ROLE" "$STATUS" "$SLOTS"
done
# 检查槽位分配
echo -e "\n🎯 槽位分配统计:"
ASSIGNED_SLOTS=$($REDIS_CLI cluster info | grep cluster_slots_assigned | cut -d: -f2)
OK_SLOTS=$($REDIS_CLI cluster info | grep cluster_slots_ok | cut -d: -f2)
FAIL_SLOTS=$($REDIS_CLI cluster info | grep cluster_slots_fail | cut -d: -f2)
echo " 已分配槽位: $ASSIGNED_SLOTS / 16384"
echo " 正常槽位: $OK_SLOTS"
echo " 故障槽位: $FAIL_SLOTS"
if [ "$FAIL_SLOTS" -gt 0 ]; then
echo "⚠️ 警告: 存在故障槽位,需要立即处理"
fi
# 检查各节点性能
echo -e "\n⚡ 节点性能统计:"
echo "地址:端口 内存使用 QPS 连接数 角色"
echo "=================================================="
$REDIS_CLI cluster nodes | grep -v fail | while read line; do
ADDRESS=$(echo $line | awk '{print $2}' | cut -d@ -f1)
HOST=$(echo $ADDRESS | cut -d: -f1)
PORT=$(echo $ADDRESS | cut -d: -f2)
FLAGS=$(echo $line | awk '{print $3}')
if [[ $FLAGS == *"master"* ]]; then
ROLE="主节点"
else
ROLE="从节点"
fi
# 获取节点性能数据
MEMORY=$(redis-cli -h $HOST -p $PORT info memory 2>/dev/null | grep used_memory_human | head -1 | cut -d: -f2 | tr -d '\r')
QPS=$(redis-cli -h $HOST -p $PORT info stats 2>/dev/null | grep instantaneous_ops_per_sec | cut -d: -f2 | tr -d '\r')
CLIENTS=$(redis-cli -h $HOST -p $PORT info clients 2>/dev/null | grep connected_clients | cut -d: -f2 | tr -d '\r')
if [ -n "$MEMORY" ]; then
printf "%-18s %-10s %6s %8s %s\n" "$ADDRESS" "$MEMORY" "$QPS" "$CLIENTS" "$ROLE"
else
printf "%-18s %-10s %6s %8s %s (连接失败)\n" "$ADDRESS" "N/A" "N/A" "N/A" "$ROLE"
fi
done
echo -e "\n========================================"
echo "监控完成时间: $(date)"
🆘 七、紧急故障处理手册
🚨 Redis完全无响应处理流程
当Redis完全无法响应时,按以下步骤排查:
bash
#!/bin/bash
# Redis紧急故障处理脚本
echo "🆘 Redis紧急故障处理开始..."
# 第一步:确认进程状态
echo "🔍 第一步:检查Redis进程状态"
REDIS_PID=$(pgrep -f redis-server)
if [ -n "$REDIS_PID" ]; then
echo "✅ Redis进程存在 (PID: $REDIS_PID)"
# 检查进程资源使用
echo " CPU使用率: $(ps -p $REDIS_PID -o %cpu --no-headers)%"
echo " 内存使用: $(ps -p $REDIS_PID -o %mem --no-headers)%"
echo " 进程状态: $(ps -p $REDIS_PID -o stat --no-headers)"
# 检查文件描述符使用
FD_COUNT=$(ls -la /proc/$REDIS_PID/fd 2>/dev/null | wc -l)
echo " 打开的文件描述符: $FD_COUNT"
else
echo "❌ Redis进程不存在,可能已崩溃"
# 检查最近的系统日志
echo "📋 检查系统日志中的Redis相关信息:"
journalctl -u redis --since "1 hour ago" --no-pager | tail -20
fi
# 第二步:检查网络端口
echo -e "\n🔍 第二步:检查网络端口状态"
PORT_STATUS=$(ss -tlnp | grep :6379)
if [ -n "$PORT_STATUS" ]; then
echo "✅ Redis端口6379正在监听"
echo " 详细信息: $PORT_STATUS"
else
echo "❌ Redis端口6379未监听"
fi
# 第三步:尝试连接测试
echo -e "\n🔍 第三步:连接测试"
PING_RESULT=$(timeout 10 redis-cli ping 2>&1)
if [ "$PING_RESULT" = "PONG" ]; then
echo "✅ Redis响应正常"
else
echo "❌ Redis连接失败: $PING_RESULT"
# 尝试使用不同方式连接
echo " 尝试TCP连接测试..."
if timeout 5 bash -c "</dev/tcp/127.0.0.1/6379"; then
echo " ✅ TCP端口可达,可能是Redis协议问题"
else
echo " ❌ TCP端口不可达,Redis服务异常"
fi
fi
# 第四步:检查系统资源
echo -e "\n🔍 第四步:检查系统资源"
echo " 内存使用情况:"
free -h | head -2
echo " 磁盘使用情况:"
df -h | grep -E "(/$|/var|/tmp)"
echo " 系统负载:"
uptime
# 第五步:检查Redis日志
echo -e "\n🔍 第五步:检查Redis日志"
REDIS_LOG="/var/log/redis/redis-server.log"
if [ -f "$REDIS_LOG" ]; then
echo " 最近的Redis日志:"
tail -20 "$REDIS_LOG"
else
echo " 未找到标准Redis日志文件,检查其他可能位置..."
find /var/log -name "*redis*" -type f 2>/dev/null | head -5
fi
# 第六步:生成诊断报告
echo -e "\n📊 第六步:生成诊断总结"
echo "=========================================="
echo "Redis故障诊断报告 - $(date)"
echo "=========================================="
if [ -n "$REDIS_PID" ]; then
if [ "$PING_RESULT" = "PONG" ]; then
echo "🟢 状态: Redis运行正常"
echo "🔧 建议: 检查应用层面的连接配置"
else
echo "🟡 状态: Redis进程存在但无响应"
echo "🔧 建议: 检查Redis配置、系统资源、网络设置"
fi
else
echo "🔴 状态: Redis进程不存在"
echo "🔧 建议: 重启Redis服务,检查配置文件"
fi
echo -e "\n💡 下一步建议操作:"
if [ -z "$REDIS_PID" ]; then
echo "1. systemctl start redis-server"
echo "2. 检查Redis配置文件语法"
echo "3. 查看详细的系统日志"
elif [ "$PING_RESULT" != "PONG" ]; then
echo "1. 检查Redis内存使用是否超限"
echo "2. 检查是否有长时间运行的慢查询"
echo "3. 考虑重启Redis服务"
fi
echo "=========================================="
⚡ 内存溢出紧急处理
bash
#!/bin/bash
# Redis内存溢出紧急处理脚本
echo "⚠️ Redis内存溢出紧急处理开始..."
# 检查当前内存状态
echo "🔍 检查当前内存状态:"
USED_MEMORY=$(redis-cli info memory | grep "used_memory:" | cut -d: -f2 | tr -d '\r')
MAX_MEMORY=$(redis-cli config get maxmemory | tail -1)
FRAG_RATIO=$(redis-cli info memory | grep "mem_fragmentation_ratio" | cut -d: -f2 | tr -d '\r')
echo " 当前内存使用: $((USED_MEMORY / 1024 / 1024))MB"
echo " 内存限制: $(if [ "$MAX_MEMORY" = "0" ]; then echo "无限制"; else echo "$((MAX_MEMORY / 1024 / 1024))MB"; fi)"
echo " 内存碎片率: $FRAG_RATIO"
# 1. 立即设置内存限制和淘汰策略
echo -e "\n🔧 1. 设置紧急内存保护措施..."
if [ "$MAX_MEMORY" = "0" ]; then
# 如果没有设置内存限制,设置为当前使用量的120%
NEW_LIMIT=$((USED_MEMORY * 120 / 100))
echo " 设置内存限制为: $((NEW_LIMIT / 1024 / 1024))MB"
redis-cli config set maxmemory $NEW_LIMIT
fi
# 设置激进的淘汰策略
redis-cli config set maxmemory-policy allkeys-lru
echo " ✅ 已设置LRU淘汰策略"
# 2. 清理过期键
echo -e "\n🗑️ 2. 清理过期键..."
EXPIRED_CLEANED=$(redis-cli eval "
local cursor = 0
local count = 0
repeat
local result = redis.call('SCAN', cursor, 'COUNT', 1000)
cursor = tonumber(result[1])
local keys = result[2]
for i=1, #keys do
if redis.call('TTL', keys[i]) == -2 then
redis.call('DEL', keys[i])
count = count + 1
end
end
until cursor == 0
return count
" 0)
echo " ✅ 清理了 $EXPIRED_CLEANED 个过期键"
# 3. 清理临时数据(根据业务模式调整)
echo -e "\n🧹 3. 清理临时数据..."
TEMP_PATTERNS=("temp:*" "cache:*" "session:*" "tmp:*")
for pattern in "${TEMP_PATTERNS[@]}"; do
TEMP_CLEANED=$(redis-cli eval "
local keys = redis.call('KEYS', ARGV[1])
local count = 0
for i=1,#keys do
-- 只删除有TTL或者已过期的临时数据
local ttl = redis.call('TTL', keys[i])
if ttl > 0 and ttl < 3600 then -- 1小时内过期的
redis.call('DEL', keys[i])
count = count + 1
end
end
return count
" 0 "$pattern")
if [ "$TEMP_CLEANED" -gt 0 ]; then
echo " ✅ 清理了 $TEMP_CLEANED 个临时键 (模式: $pattern)"
fi
done
# 4. 内存碎片整理
echo -e "\n🔧 4. 内存碎片整理..."
REDIS_VERSION=$(redis-cli info server | grep redis_version | cut -d: -f2 | tr -d '\r')
if [[ $REDIS_VERSION == 4.* ]] || [[ $REDIS_VERSION == 5.* ]] || [[ $REDIS_VERSION == 6.* ]]; then
redis-cli memory purge
echo " ✅ 已触发内存碎片整理"
else
echo " ⚠️ 当前Redis版本不支持内存碎片整理命令"
fi
# 5. 检查大键
echo -e "\n🔍 5. 检查大键情况..."
echo " 正在扫描大键(可能需要一些时间)..."
redis-cli --bigkeys | head -20
# 6. 最终状态检查
echo -e "\n📊 6. 处理后状态检查..."
NEW_USED_MEMORY=$(redis-cli info memory | grep "used_memory:" | cut -d: -f2 | tr -d '\r')
NEW_FRAG_RATIO=$(redis-cli info memory | grep "mem_fragmentation_ratio" | cut -d: -f2 | tr -d '\r')
echo " 处理前内存: $((USED_MEMORY / 1024 / 1024))MB"
echo " 处理后内存: $((NEW_USED_MEMORY / 1024 / 1024))MB"
echo " 节省内存: $(((USED_MEMORY - NEW_USED_MEMORY) / 1024 / 1024))MB"
echo " 新碎片率: $NEW_FRAG_RATIO"
# 7. 生成处理报告
echo -e "\n📋 7. 紧急处理总结报告"
echo "=========================================="
echo "Redis内存溢出处理报告 - $(date)"
echo "=========================================="
echo "处理措施:"
echo "✅ 设置内存限制和LRU淘汰策略"
echo "✅ 清理过期键: $EXPIRED_CLEANED 个"
echo "✅ 清理临时数据"
echo "✅ 执行内存碎片整理"
echo ""
echo "内存变化:"
echo " 处理前: $((USED_MEMORY / 1024 / 1024))MB"
echo " 处理后: $((NEW_USED_MEMORY / 1024 / 1024))MB"
echo " 节省: $(((USED_MEMORY - NEW_USED_MEMORY) / 1024 / 1024))MB"
echo ""
echo "后续建议:"
echo "1. 持续监控内存使用情况"
echo "2. 检查应用代码,优化数据存储结构"
echo "3. 考虑增加服务器内存或启用集群"
echo "4. 设置更合理的过期时间策略"
echo "=========================================="
🔄 主从同步断开紧急修复
bash
#!/bin/bash
# Redis主从同步断开紧急修复脚本
echo "🔄 Redis主从同步紧急修复开始..."
# 检查当前角色
ROLE=$(redis-cli info replication | grep "role:" | cut -d: -f2 | tr -d '\r')
echo "📋 当前节点角色: $ROLE"
if [ "$ROLE" = "slave" ]; then
echo -e "\n🔧 执行从库修复流程..."
# 获取主库信息
MASTER_HOST=$(redis-cli info replication | grep "master_host:" | cut -d: -f2 | tr -d '\r')
MASTER_PORT=$(redis-cli info replication | grep "master_port:" | cut -d: -f2 | tr -d '\r')
MASTER_LINK_STATUS=$(redis-cli info replication | grep "master_link_status:" | cut -d: -f2 | tr -d '\r')
MASTER_LAST_IO=$(redis-cli info replication | grep "master_last_io_seconds_ago:" | cut -d: -f2 | tr -d '\r')
echo " 主库地址: $MASTER_HOST:$MASTER_PORT"
echo " 连接状态: $MASTER_LINK_STATUS"
echo " 上次IO: ${MASTER_LAST_IO}秒前"
# 测试主库连通性
echo -e "\n🔍 测试主库连通性..."
if timeout 5 redis-cli -h $MASTER_HOST -p $MASTER_PORT ping; then
echo "✅ 主库网络连通正常"
# 检查主库状态
MASTER_ROLE=$(redis-cli -h $MASTER_HOST -p $MASTER_PORT info replication | grep "role:" | cut -d: -f2 | tr -d '\r')
if [ "$MASTER_ROLE" = "master" ]; then
echo "✅ 主库角色正常"
# 重新建立主从关系
echo -e "\n🔄 重新建立主从关系..."
echo " 1. 断开当前主从关系..."
redis-cli slaveof no one
sleep 2
echo " 2. 重新连接主库..."
redis-cli slaveof $MASTER_HOST $MASTER_PORT
echo " 3. 等待同步开始..."
sleep 5
# 检查同步状态
NEW_LINK_STATUS=$(redis-cli info replication | grep "master_link_status:" | cut -d: -f2 | tr -d '\r')
echo " 新的同步状态: $NEW_LINK_STATUS"
if [ "$NEW_LINK_STATUS" = "up" ]; then
echo "✅ 主从同步已恢复"
# 检查同步进度
MASTER_OFFSET=$(redis-cli -h $MASTER_HOST -p $MASTER_PORT info replication | grep "master_repl_offset:" | cut -d: -f2 | tr -d '\r')
SLAVE_OFFSET=$(redis-cli info replication | grep "slave_repl_offset:" | cut -d: -f2 | tr -d '\r')
OFFSET_DIFF=$((MASTER_OFFSET - SLAVE_OFFSET))
echo " 主库偏移量: $MASTER_OFFSET"
echo " 从库偏移量: $SLAVE_OFFSET"
echo " 同步差距: $OFFSET_DIFF 字节"
else
echo "❌ 主从同步恢复失败,需要进一步排查"
fi
else
echo "❌ 主库角色异常 ($MASTER_ROLE),可能发生了主从切换"
fi
else
echo "❌ 主库网络不通,需要检查:"
echo " 1. 网络连接是否正常"
echo " 2. 主库服务是否运行"
echo " 3. 防火墙设置是否正确"
fi
elif [ "$ROLE" = "master" ]; then
echo -e "\n🔧 执行主库检查流程..."
# 检查从库连接状态
CONNECTED_SLAVES=$(redis-cli info replication | grep "connected_slaves:" | cut -d: -f2 | tr -d '\r')
echo " 连接的从库数量: $CONNECTED_SLAVES"
if [ "$CONNECTED_SLAVES" -gt 0 ]; then
echo " 从库连接详情:"
redis-cli info replication | grep -E "slave[0-9]+" | while read line; do
echo " $line"
done
else
echo "⚠️ 警告: 没有从库连接"
# 检查是否有配置文件中的从库信息需要重新连接
echo " 建议检查:"
echo " 1. 从库服务状态"
echo " 2. 网络连接"
echo " 3. 从库配置"
fi
else
echo "❌ 未知的Redis角色: $ROLE"
fi
# 生成修复报告
echo -e "\n📋 主从同步修复报告"
echo "=========================================="
echo "主从同步修复报告 - $(date)"
echo "=========================================="
FINAL_ROLE=$(redis-cli info replication | grep "role:" | cut -d: -f2 | tr -d '\r')
if [ "$FINAL_ROLE" = "slave" ]; then
FINAL_LINK_STATUS=$(redis-cli info replication | grep "master_link_status:" | cut -d: -f2 | tr -d '\r')
FINAL_LAST_IO=$(redis-cli info replication | grep "master_last_io_seconds_ago:" | cut -d: -f2 | tr -d '\r')
echo "节点角色: 从库"
echo "连接状态: $FINAL_LINK_STATUS"
echo "最后IO: ${FINAL_LAST_IO}秒前"
if [ "$FINAL_LINK_STATUS" = "up" ]; then
echo "✅ 修复状态: 成功"
else
echo "❌ 修复状态: 失败"
fi
else
FINAL_SLAVES=$(redis-cli info replication | grep "connected_slaves:" | cut -d: -f2 | tr -d '\r')
echo "节点角色: 主库"
echo "连接从库: $FINAL_SLAVES"
fi
echo "=========================================="
📝 八、生产环境配置优化模板
🔧 高性能生产配置
bash
#!/bin/bash
# Redis生产环境配置优化脚本
echo "🔧 Redis生产环境配置优化开始..."
# 1. 内存管理优化
echo "1. 内存管理配置..."
redis-cli config set maxmemory 8gb # 根据服务器内存调整
redis-cli config set maxmemory-policy allkeys-lru
redis-cli config set maxmemory-samples 10 # 提高LRU准确性
# 启用惰性删除,减少删除大key时的阻塞
redis-cli config set lazyfree-lazy-eviction yes
redis-cli config set lazyfree-lazy-expire yes
redis-cli config set lazyfree-lazy-server-del yes
redis-cli config set replica-lazy-flush yes
# 2. 网络连接优化
echo "2. 网络连接配置..."
redis-cli config set maxclients 10000 # 根据需求调整
redis-cli config set timeout 300 # 5分钟客户端超时
redis-cli config set tcp-keepalive 300 # TCP保活时间
redis-cli config set tcp-backlog 511 # TCP监听队列长度
# 客户端输出缓冲区限制
redis-cli config set client-output-buffer-limit "normal 0 0 0"
redis-cli config set client-output-buffer-limit "replica 256mb 64mb 60"
redis-cli config set client-output-buffer-limit "pubsub 32mb 8mb 60"
# 3. 持久化优化
echo "3. 持久化配置..."
# RDB配置 - 适中的频率,避免过于频繁
redis-cli config set save "1800 1 600 100 300 1000"
# AOF配置
redis-cli config set appendonly yes
redis-cli config set appendfsync everysec # 性能和安全的平衡
redis-cli config set no-appendfsync-on-rewrite no
redis-cli config set auto-aof-rewrite-percentage 100
redis-cli config set auto-aof-rewrite-min-size 128mb
# 4. 主从复制优化
echo "4. 主从复制配置..."
redis-cli config set repl-backlog-size 128mb # 增大复制缓冲区
redis-cli config set repl-backlog-ttl 7200 # 2小时缓冲区保留
redis-cli config set repl-timeout 60 # 复制超时时间
redis-cli config set repl-ping-slave-period 10 # ping从库间隔
# 从库配置
redis-cli config set slave-read-only yes # 从库只读
redis-cli config set slave-serve-stale-data yes # 连接断开时提供旧数据
# 5. 性能优化
echo "5. 性能优化配置..."
redis-cli config set hash-max-ziplist-entries 512
redis-cli config set hash-max-ziplist-value 64
redis-cli config set list-max-ziplist-size -2
redis-cli config set list-compress-depth 0
redis-cli config set set-max-intset-entries 512
redis-cli config set zset-max-ziplist-entries 128
redis-cli config set zset-max-ziplist-value 64
# 6. 安全配置
echo "6. 安全配置..."
redis-cli config set protected-mode yes
redis-cli config set bind "127.0.0.1 10.0.0.100" # 根据实际IP调整
# redis-cli config set requirepass "your_strong_password" # 取消注释并设置密码
# 重命名危险命令
redis-cli config set rename-command-flushdb "FLUSHDB_DANGEROUS_COMMAND"
redis-cli config set rename-command-flushall "FLUSHALL_DANGEROUS_COMMAND"
redis-cli config set rename-command-keys "KEYS_DANGEROUS_COMMAND"
redis-cli config set rename-command-config "CONFIG_DANGEROUS_COMMAND"
# 7. 慢查询优化
echo "7. 慢查询配置..."
redis-cli config set slowlog-log-slower-than 10000 # 10ms
redis-cli config set slowlog-max-len 1000
# 8. 其他优化
echo "8. 其他优化配置..."
redis-cli config set databases 16 # 数据库数量
redis-cli config set hz 100 # 后台任务频率
redis-cli config set dynamic-hz yes # 动态调整hz
echo "✅ 配置优化完成!"
# 保存配置到文件
echo "💾 保存配置到磁盘..."
redis-cli config rewrite
# 输出当前关键配置
echo -e "\n📋 当前关键配置总结:"
echo "内存限制: $(redis-cli config get maxmemory | tail -1)"
echo "最大连接: $(redis-cli config get maxclients | tail -1)"
echo "持久化: RDB+AOF"
echo "淘汰策略: $(redis-cli config get maxmemory-policy | tail -1)"
echo "慢查询阈值: $(redis-cli config get slowlog-log-slower-than | tail -1)微秒"
🛡️ 高可用集群配置
bash
#!/bin/bash
# Redis高可用集群配置脚本
echo "🛡️ Redis高可用集群配置开始..."
# 集群基本配置
CLUSTER_NODES=(
"192.168.1.10:7001"
"192.168.1.10:7002"
"192.168.1.10:7003"
"192.168.1.11:7001"
"192.168.1.11:7002"
"192.168.1.11:7003"
)
# 1. 集群基础配置
echo "1. 集群基础配置..."
for node in "${CLUSTER_NODES[@]}"; do
HOST=$(echo $node | cut -d: -f1)
PORT=$(echo $node | cut -d: -f2)
echo "配置节点: $node"
# 集群必要配置
redis-cli -h $HOST -p $PORT config set cluster-enabled yes
redis-cli -h $HOST -p $PORT config set cluster-config-file "nodes-${PORT}.conf"
redis-cli -h $HOST -p $PORT config set cluster-node-timeout 15000
redis-cli -h $HOST -p $PORT config set cluster-announce-ip $HOST
redis-cli -h $HOST -p $PORT config set cluster-announce-port $PORT
redis-cli -h $HOST -p $PORT config set cluster-announce-bus-port $((PORT + 10000))
# 故障检测和恢复
redis-cli -h $HOST -p $PORT config set cluster-require-full-coverage no
redis-cli -h $HOST -p $PORT config set cluster-slave-validity-factor 10
redis-cli -h $HOST -p $PORT config set cluster-migration-barrier 1
done
# 2. 数据安全配置
echo "2. 数据安全配置..."
for node in "${CLUSTER_NODES[@]}"; do
HOST=$(echo $node | cut -d: -f1)
PORT=$(echo $node | cut -d: -f2)
# 最小写入确认
redis-cli -h $HOST -p $PORT config set min-replicas-to-write 1
redis-cli -h $HOST -p $PORT config set min-replicas-max-lag 10
# 持久化配置
redis-cli -h $HOST -p $PORT config set save "1800 1 600 100 300 1000"
redis-cli -h $HOST -p $PORT config set appendonly yes
redis-cli -h $HOST -p $PORT config set appendfsync everysec
done
# 3. 性能优化配置
echo "3. 性能优化配置..."
for node in "${CLUSTER_NODES[@]}"; do
HOST=$(echo $node | cut -d: -f1)
PORT=$(echo $node | cut -d: -f2)
# 内存配置
redis-cli -h $HOST -p $PORT config set maxmemory 4gb
redis-cli -h $HOST -p $PORT config set maxmemory-policy allkeys-lru
# 网络配置
redis-cli -h $HOST -p $PORT config set tcp-keepalive 300
redis-cli -h $HOST -p $PORT config set timeout 300
# 客户端配置
redis-cli -h $HOST -p $PORT config set maxclients 5000
done
# 4. 初始化集群(如果尚未初始化)
echo "4. 检查集群状态..."
FIRST_NODE=${CLUSTER_NODES[0]}
CLUSTER_STATE=$(redis-cli -h $(echo $FIRST_NODE | cut -d: -f1) -p $(echo $FIRST_NODE | cut -d: -f2) cluster info 2>/dev/null | grep cluster_state | cut -d: -f2)
if [ "$CLUSTER_STATE" != "ok" ]; then
echo "初始化Redis集群..."
NODE_LIST=$(printf "%s " "${CLUSTER_NODES[@]}")
redis-cli --cluster create $NODE_LIST --cluster-replicas 1 --cluster-yes
else
echo "✅ 集群已经初始化"
fi
# 5. 验证集群配置
echo "5. 验证集群配置..."
for node in "${CLUSTER_NODES[@]}"; do
HOST=$(echo $node | cut -d: -f1)
PORT=$(echo $node | cut -d: -f2)
echo "验证节点: $node"
# 检查节点状态
PING_RESULT=$(redis-cli -h $HOST -p $PORT ping 2>/dev/null)
if [ "$PING_RESULT" = "PONG" ]; then
ROLE=$(redis-cli -h $HOST -p $PORT cluster nodes | grep myself | grep -o 'master\|slave')
echo " ✅ 节点响应正常 (角色: $ROLE)"
else
echo " ❌ 节点无响应"
fi
done
# 6. 生成集群状态报告
echo -e "\n📊 集群状态报告:"
echo "=================================="
FIRST_HOST=$(echo ${CLUSTER_NODES[0]} | cut -d: -f1)
FIRST_PORT=$(echo ${CLUSTER_NODES[0]} | cut -d: -f2)
CLUSTER_INFO=$(redis-cli -h $FIRST_HOST -p $FIRST_PORT cluster info)
CLUSTER_STATE=$(echo "$CLUSTER_INFO" | grep cluster_state | cut -d: -f2)
CLUSTER_NODES_COUNT=$(echo "$CLUSTER_INFO" | grep cluster_known_nodes | cut -d: -f2)
CLUSTER_SIZE=$(echo "$CLUSTER_INFO" | grep cluster_size | cut -d: -f2)
echo "集群状态: $CLUSTER_STATE"
echo "节点数量: $CLUSTER_NODES_COUNT"
echo "主节点数: $CLUSTER_SIZE"
if [ "$CLUSTER_STATE" = "ok" ]; then
echo "✅ 集群配置成功!"
else
echo "❌ 集群状态异常,需要检查配置"
fi
echo "=================================="
📊 监控告警配置模板
bash
#!/bin/bash
# Redis监控告警配置脚本
echo "📊 Redis监控告警配置开始..."
# 创建监控脚本目录
MONITOR_DIR="/opt/redis-monitor"
mkdir -p $MONITOR_DIR
# 1. 创建指标收集脚本
cat > $MONITOR_DIR/collect_metrics.sh << 'EOF'
#!/bin/bash
# Redis指标收集脚本
REDIS_HOST=${1:-127.0.0.1}
REDIS_PORT=${2:-6379}
TIMESTAMP=$(date +%s)
REDIS_CLI="redis-cli -h $REDIS_HOST -p $REDIS_PORT"
# 基础指标
USED_MEMORY=$($REDIS_CLI info memory | grep "^used_memory:" | cut -d: -f2)
USED_RSS=$($REDIS_CLI info memory | grep "^used_memory_rss:" | cut -d: -f2)
FRAGMENTATION_RATIO=$($REDIS_CLI info memory | grep "mem_fragmentation_ratio" | cut -d: -f2)
CONNECTED_CLIENTS=$($REDIS_CLI info clients | grep "connected_clients" | cut -d: -f2)
BLOCKED_CLIENTS=$($REDIS_CLI info clients | grep "blocked_clients" | cut -d: -f2)
INSTANTANEOUS_OPS=$($REDIS_CLI info stats | grep "instantaneous_ops_per_sec" | cut -d: -f2)
KEYSPACE_HITS=$($REDIS_CLI info stats | grep "keyspace_hits" | cut -d: -f2)
KEYSPACE_MISSES=$($REDIS_CLI info stats | grep "keyspace_misses" | cut -d: -f2)
# 计算命中率
if [ "$KEYSPACE_MISSES" -gt 0 ]; then
HIT_RATE=$(echo "scale=4; $KEYSPACE_HITS / ($KEYSPACE_HITS + $KEYSPACE_MISSES)" | bc)
else
HIT_RATE=1.0000
fi
# 输出指标(InfluxDB格式)
echo "redis_metrics,host=$REDIS_HOST,port=$REDIS_PORT used_memory=${USED_MEMORY}i,used_rss=${USED_RSS}i,fragmentation_ratio=$FRAGMENTATION_RATIO,connected_clients=${CONNECTED_CLIENTS}i,blocked_clients=${BLOCKED_CLIENTS}i,ops_per_sec=${INSTANTANEOUS_OPS}i,hit_rate=$HIT_RATE $TIMESTAMP"
EOF
chmod +x $MONITOR_DIR/collect_metrics.sh
# 2. 创建告警检查脚本
cat > $MONITOR_DIR/check_alerts.sh << 'EOF'
#!/bin/bash
# Redis告警检查脚本
REDIS_HOST=${1:-127.0.0.1}
REDIS_PORT=${2:-6379}
REDIS_CLI="redis-cli -h $REDIS_HOST -p $REDIS_PORT"
ALERT_LOG="/var/log/redis-alerts.log"
# 告警阈值配置
MEMORY_WARNING_THRESHOLD=80 # 内存使用率警告阈值(%)
MEMORY_CRITICAL_THRESHOLD=95 # 内存使用率严重阈值(%)
CONNECTION_WARNING_THRESHOLD=80 # 连接数使用率警告阈值(%)
FRAGMENTATION_WARNING_THRESHOLD=2.0 # 内存碎片率警告阈值
HIT_RATE_WARNING_THRESHOLD=0.8 # 命中率警告阈值
SLOWLOG_WARNING_THRESHOLD=100 # 慢查询数量警告阈值
# 函数:发送告警
send_alert() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> $ALERT_LOG
# 这里可以集成邮件、短信、钉钉等告警方式
# 例如:curl -X POST ... 发送到告警系统
echo "ALERT [$level]: $message"
}
# 检查Redis连接
if ! $REDIS_CLI ping > /dev/null 2>&1; then
send_alert "CRITICAL" "Redis服务无响应 ($REDIS_HOST:$REDIS_PORT)"
exit 1
fi
# 检查内存使用率
USED_MEMORY=$($REDIS_CLI info memory | grep "^used_memory:" | cut -d: -f2 | tr -d '\r')
MAX_MEMORY=$($REDIS_CLI config get maxmemory | tail -1)
if [ "$MAX_MEMORY" != "0" ] && [ "$MAX_MEMORY" != "" ]; then
MEMORY_USAGE_PERCENT=$((USED_MEMORY * 100 / MAX_MEMORY))
if [ $MEMORY_USAGE_PERCENT -gt $MEMORY_CRITICAL_THRESHOLD ]; then
send_alert "CRITICAL" "内存使用严重超标: ${MEMORY_USAGE_PERCENT}% (阈值: ${MEMORY_CRITICAL_THRESHOLD}%)"
elif [ $MEMORY_USAGE_PERCENT -gt $MEMORY_WARNING_THRESHOLD ]; then
send_alert "WARNING" "内存使用率过高: ${MEMORY_USAGE_PERCENT}% (阈值: ${MEMORY_WARNING_THRESHOLD}%)"
fi
fi
# 检查连接数
CONNECTED_CLIENTS=$($REDIS_CLI info clients | grep "connected_clients" | cut -d: -f2 | tr -d '\r')
MAX_CLIENTS=$($REDIS_CLI config get maxclients | tail -1)
CONNECTION_USAGE_PERCENT=$((CONNECTED_CLIENTS * 100 / MAX_CLIENTS))
if [ $CONNECTION_USAGE_PERCENT -gt $CONNECTION_WARNING_THRESHOLD ]; then
send_alert "WARNING" "连接数使用率过高: ${CONNECTION_USAGE_PERCENT}% (阈值: ${CONNECTION_WARNING_THRESHOLD}%)"
fi
# 检查内存碎片率
FRAGMENTATION_RATIO=$($REDIS_CLI info memory | grep "mem_fragmentation_ratio" | cut -d: -f2 | tr -d '\r')
if (( $(echo "$FRAGMENTATION_RATIO > $FRAGMENTATION_WARNING_THRESHOLD" | bc -l) )); then
send_alert "WARNING" "内存碎片率过高: $FRAGMENTATION_RATIO (阈值: $FRAGMENTATION_WARNING_THRESHOLD)"
fi
# 检查命中率
KEYSPACE_HITS=$($REDIS_CLI info stats | grep "keyspace_hits" | cut -d: -f2 | tr -d '\r')
KEYSPACE_MISSES=$($REDIS_CLI info stats | grep "keyspace_misses" | cut -d: -f2 | tr -d '\r')
if [ "$KEYSPACE_HITS" -gt 0 ] && [ "$KEYSPACE_MISSES" -gt 0 ]; then
HIT_RATE=$(echo "scale=4; $KEYSPACE_HITS / ($KEYSPACE_HITS + $KEYSPACE_MISSES)" | bc)
if (( $(echo "$HIT_RATE < $HIT_RATE_WARNING_THRESHOLD" | bc -l) )); then
send_alert "WARNING" "缓存命中率过低: $(echo "$HIT_RATE * 100" | bc)% (阈值: $(echo "$HIT_RATE_WARNING_THRESHOLD * 100" | bc)%)"
fi
fi
# 检查慢查询
SLOWLOG_LEN=$($REDIS_CLI slowlog len)
if [ $SLOWLOG_LEN -gt $SLOWLOG_WARNING_THRESHOLD ]; then
send_alert "WARNING" "慢查询数量过多: $SLOWLOG_LEN (阈值: $SLOWLOG_WARNING_THRESHOLD)"
fi
# 检查主从同步状态
ROLE=$($REDIS_CLI info replication | grep "^role:" | cut -d: -f2 | tr -d '\r')
if [ "$ROLE" = "slave" ]; then
MASTER_LINK_STATUS=$($REDIS_CLI info replication | grep "master_link_status:" | cut -d: -f2 | tr -d '\r')
if [ "$MASTER_LINK_STATUS" != "up" ]; then
send_alert "CRITICAL" "主从同步连接断开"
fi
fi
EOF
chmod +x $MONITOR_DIR/check_alerts.sh
# 3. 创建定时任务
echo "📅 配置定时监控任务..."
# 添加crontab任务
CRON_JOBS="
# Redis指标收集 - 每分钟执行一次
* * * * * $MONITOR_DIR/collect_metrics.sh >> /var/log/redis-metrics.log 2>&1
# Redis告警检查 - 每5分钟执行一次
*/5 * * * * $MONITOR_DIR/check_alerts.sh
# Redis健康检查 - 每小时执行一次
0 * * * * /opt/redis-monitor/redis_health_check.sh > /var/log/redis-health-$(date +\%Y\%m\%d).log 2>&1
"
echo "$CRON_JOBS" | crontab -
# 4. 创建监控仪表板配置
echo "📊 创建监控仪表板配置..."
cat > $MONITOR_DIR/grafana-dashboard.json << 'EOF'
{
"dashboard": {
"title": "Redis监控仪表板",
"panels": [
{
"title": "内存使用情况",
"targets": [
{
"expr": "redis_used_memory_bytes",
"legendFormat": "已使用内存"
}
]
},
{
"title": "QPS",
"targets": [
{
"expr": "rate(redis_commands_total[1m])",
"legendFormat": "每秒操作数"
}
]
},
{
"title": "连接数",
"targets": [
{
"expr": "redis_connected_clients",
"legendFormat": "当前连接数"
}
]
},
{
"title": "命中率",
"targets": [
{
"expr": "rate(redis_keyspace_hits_total[5m]) / (rate(redis_keyspace_hits_total[5m]) + rate(redis_keyspace_misses_total[5m]))",
"legendFormat": "缓存命中率"
}
]
}
]
}
}
EOF
echo "✅ 监控告警配置完成!"
echo "📁 监控脚本位置: $MONITOR_DIR"
echo "📋 告警日志位置: /var/log/redis-alerts.log"
echo "📊 指标日志位置: /var/log/redis-metrics.log"
echo ""
echo "🔧 下一步操作:"
echo "1. 根据实际需求调整告警阈值"
echo "2. 配置告警通知方式(邮件、短信等)"
echo "3. 部署Grafana仪表板"
echo "4. 验证监控脚本运行正常"
🎯 九、故障排查最佳实践
📋 排查优先级清单
-
立即检查项(< 1分钟)
bash# 快速状态检查 redis-cli ping redis-cli info server | head -5 redis-cli info memory | grep used_memory_human redis-cli info clients | grep connected_clients
-
紧急问题排查(< 5分钟)
bash# 慢查询检查 redis-cli slowlog get 10 # 内存状况检查 redis-cli info memory | grep -E "(used_memory|fragmentation|maxmemory)" # 连接状态检查 redis-cli client list | wc -l redis-cli config get maxclients
-
深度排查(< 15分钟)
bash# 持久化状态 redis-cli info persistence # 主从复制状态 redis-cli info replication # 系统资源检查 top -p $(pgrep redis-server) iostat -x 1 3
🚨 告警响应流程
CRITICAL WARNING INFO 是 否 收到Redis告警 告警级别 立即响应
5分钟内 1小时内响应 24小时内处理 执行紧急检查清单 问题是否解决 发送恢复通知 升级处理 分析告警原因 制定处理计划 执行修复操作 联系高级工程师 制定紧急预案 执行恢复操作
📚 常见问题快速解决方案
问题类型 | 快速诊断 | 解决方案 |
---|---|---|
连接超时 | redis-cli ping |
检查网络/防火墙/Redis服务状态 |
内存不足 | info memory |
清理过期key/调整maxmemory |
响应变慢 | slowlog get |
优化慢查询/检查阻塞操作 |
主从断开 | info replication |
重建主从关系/检查网络 |
集群异常 | cluster info |
修复故障节点/重新分配槽位 |
📝 十、总结与建议
✅ 生产环境运维要点
-
预防为主
- 建立完善的监控告警体系
- 定期进行健康检查和性能测试
- 制定详细的运维操作规范
-
快速响应
- 熟练掌握常用诊断命令
- 建立故障处理标准流程
- 准备应急处理脚本
-
持续优化
- 定期分析性能指标趋势
- 根据业务增长调整配置
- 不断完善监控和告警规则
🔧 推荐的运维工具
- 监控: Prometheus + Grafana + Redis Exporter
- 告警: AlertManager + 企业通知系统
- 日志: ELK Stack (Elasticsearch + Logstash + Kibana)
- 自动化: Ansible + Shell脚本
- 备份: 定时RDB + AOF + 异地备份
📞 紧急联系清单
bash
# 生产环境紧急处理清单
echo "📞 Redis紧急故障联系清单"
echo "================================"
echo "1. 数据库团队: xxx-xxxx-xxxx"
echo "2. 运维团队: xxx-xxxx-xxxx"
echo "3. 架构师: xxx-xxxx-xxxx"
echo "4. 技术经理: xxx-xxxx-xxxx"
echo ""
echo "🔧 重要系统信息:"
echo "Redis版本: $(redis-cli info server | grep redis_version)"
echo "配置文件: /etc/redis/redis.conf"
echo "数据目录: $(redis-cli config get dir | tail -1)"
echo "日志文件: /var/log/redis/redis-server.log"
echo "================================"
📎 附录:命令速查表
🔍 诊断命令速查
bash
# 基础状态
redis-cli ping # 连接测试
redis-cli info server # 服务器信息
redis-cli info memory # 内存信息
redis-cli info stats # 统计信息
redis-cli info clients # 客户端信息
redis-cli info replication # 复制信息
redis-cli info persistence # 持久化信息
# 性能分析
redis-cli slowlog get 10 # 慢查询日志
redis-cli --latency # 延迟测试
redis-cli --latency-history # 延迟历史
redis-cli --bigkeys # 大key扫描
redis-cli monitor # 实时监控
redis-cli --stat # 实时统计
# 连接管理
redis-cli client list # 客户端列表
redis-cli client kill ip 192.168.1.100 # 杀死连接
redis-cli client kill idle 3600 # 杀死空闲连接
# 集群管理
redis-cli cluster info # 集群信息
redis-cli cluster nodes # 节点信息
redis-cli cluster slots # 槽位信息
redis-cli --cluster check host:port # 集群检查
redis-cli --cluster fix host:port # 集群修复
# 内存管理
redis-cli memory usage key # key内存使用
redis-cli memory purge # 内存整理
redis-cli memory stats # 内存统计
⚙️ 配置命令速查
bash
# 内存配置
redis-cli config set maxmemory 4gb
redis-cli config set maxmemory-policy allkeys-lru
redis-cli config set lazyfree-lazy-eviction yes
# 连接配置
redis-cli config set maxclients 1000
redis-cli config set timeout 300
redis-cli config set tcp-keepalive 300
# 持久化配置
redis-cli config set save "900 1 300 10 60 1000"
redis-cli config set appendonly yes
redis-cli config set appendfsync everysec
# 主从配置
redis-cli slaveof 192.168.1.10 6379 # 设置主库
redis-cli slaveof no one # 取消主从
# 查看配置
redis-cli config get "*" # 所有配置
redis-cli config get maxmemory # 特定配置
redis-cli config rewrite # 保存配置
🎉 手册编写完成!
本手册涵盖了Redis生产环境的完整故障排查流程,包含详细的中文说明和实用的脚本工具。建议收藏此手册,在遇到Redis问题时按照手册步骤进行排查,可以快速定位和解决大部分生产环境问题。
💡 使用建议:
- 将此手册保存为本地文件,方便紧急情况下快速查阅
- 根据实际环境调整脚本中的IP地址、端口、路径等参数
- 定期更新和完善手册内容,结合实际故障案例优化排查流程
- 团队成员应熟练掌握基础诊断命令,提高故障响应效率