Redis 性能优化与故障排查指南

Redis 跑起来快如闪电,但一旦出问题,轻则接口变慢,重则服务雪崩。
很多人以为 Redis 就是“开箱即用”,其实它像一辆跑车——油门踩到底爽,但不懂保养,随时抛锚。
下面分两块讲:怎么让它跑得更快(优化),挂了怎么救(排查)。
一、性能优化:别让 Redis 白白浪费
1. 内存优化:省下的都是钱!
Redis 是内存数据库,内存就是成本。你存 100GB 数据,就得买 128GB 机器(还得留 buffer)。所以,省内存 = 省钱。
技巧1:别用大 Key!
- 一个 Hash 存 100 万个字段?一个 List 存 50 万条日志?
- 后果:删除时卡主线程几秒,网络传输慢,备份慢,故障恢复慢。
怎么做?
- 拆!比如用户行为日志,按天拆:
log:uid:20241104 - 用
SCAN+HSCAN/LRANGE分批处理,别KEYS *(会卡死!)
技巧2:选对数据结构
很多人不管三七二十一全用 String,其实 Redis 有更省内存的结构:
| 场景 | 推荐结构 | 省多少? |
|---|---|---|
| 存对象(如用户信息) | Hash | 比多个 String 省 30%+ 内存 |
| 存布尔状态(如签到) | String("1"/"0") or Bitmap | 100 万人签到,Bitmap 只要 125KB |
| 存集合(如好友 ID) | Set or IntSet(整数自动优化) | 小集合用 IntSet,内存极小 |
| 存排行榜 | ZSET | 别用 List + 排序,那是在自虐 |
重点:Hash 在字段少、值小时,会用 ziplist 编码,超级省内存!
但字段多了会转成 hashtable,反而更占。所以别在一个 Hash 里塞几千个字段。
技巧3:开启内存压缩(Redis 6+)
如果你用的是 Redis 6 或 7,可以开启 Redis 原生内存压缩(基于 LZF):
use-exact-encoding no
# 配合合理的 hash-max-ziplist-entries 等参数
实测对字符串多的场景,能省 15%~25% 内存。
技巧4:设置 maxmemory + 淘汰策略
别让 Redis 无限制吃内存!一定要设:
maxmemory 8gb
maxmemory-policy allkeys-lru # 或 volatile-lru
allkeys-lru:所有 key 按最近最少用淘汰(适合纯缓存)volatile-lru:只淘汰带过期时间的 key(适合缓存+持久数据混合)
⚠️ 不设 maxmemory 的后果:系统 OOM,Linux 直接 kill 掉 Redis 进程!
2. 配置优化:别用默认配置跑生产!
Redis 默认配置是“玩具级”,生产环境必须调!
关键配置项(redis.conf)
| 配置项 | 推荐值 | 说明 |
|---|---|---|
timeout | 0 或 300 | 设 0 表示永不超时(长连接);设 300 表示 5 分钟无操作断开(防连接泄露) |
tcp-keepalive | 60 | 开启 TCP 心跳,及时发现死连接 |
save | 按需关闭或调整 | 如果只当缓存,关掉 RDB:save "" |
appendonly | yes(重要数据) | 开启 AOF,配合 appendfsync everysec(性能+安全平衡) |
repl-backlog-size | 256mb 或更大 | 防止主从断连后全量同步 |
maxclients | 10000+ | 默认 1 万,高并发要调大 |
vm.overcommit_memory | 1(系统级) | 避免 fork 时内存分配失败(Linux 系统设置) |
特别提醒:
- 不要开
appendfsync always!每次写都刷盘,性能暴跌 10 倍。- RDB + AOF 双开?没必要! AOF 足够,RDB 只用于备份。
3. 命令优化:别让一个命令拖垮整个服务
Redis 是单线程(网络 IO + 命令执行),一个慢命令 = 所有请求排队!
高危命令(线上禁用!)
KEYS *:遍历所有 key,数据量大直接卡死FLUSHALL/FLUSHDB:清空数据,手抖就完蛋SUNION/ZUNIONSTORE:大集合运算,CPU 爆表
解决方案:
- 用
SCAN替代KEYS - 用
UNLINK替代DEL(异步删除,不阻塞) - 业务层限制集合大小(比如好友最多 5000 人)
用 Pipeline 批量操作
比如要查 100 个用户信息:
// 错误:100 次网络往返
for (id : ids) redis.get("user:" + id);// 正确:1 次往返
Pipeline p = redis.pipelined();
for (id : ids) p.get("user:" + id);
List<Object> results = p.syncAndReturnAll();
性能提升 10~100 倍! 尤其在高延迟网络(跨机房)下效果惊人。
用 Lua 脚本保证原子性 + 减少网络
前面讲过库存扣减,用 Lua 一条命令搞定“查+判+改”,比客户端多次交互快得多,还避免竞态。
二、常见故障排查:别慌,按步骤来
故障1:Redis 突然变慢,接口超时
排查步骤:
看 CPU:
top看 redis-server 是否 100% CPU?- 是 → 有慢命令 or 大 key 操作
- 否 → 看网络 or 客户端问题
查慢查询:
redis-cli SLOWLOG GET 10默认记录执行时间 > 10ms 的命令。看是不是
KEYS、SMEMBERS、大ZREVRANGE。看是否在 fork:
- RDB 快照 or AOF 重写时会 fork 子进程
- 如果内存大(>10GB),fork 会卡主线程几百毫秒
- 日志里会有
Background saving started/fork took xxx ms
看网络延迟:
- 用
redis-cli --latency -h xxx测延迟 - 跨机房?带宽打满?
- 用
解决:
- 禁用慢命令
- 大 key 拆分
- RDB 改 AOF +
everysec - 升级到 Redis 6+,用多线程 IO(
io-threads)
故障2:内存暴涨,快 OOM 了
排查步骤:
看内存使用:
redis-cli INFO memory关注
used_memory、mem_fragmentation_ratio(>1.5 说明内存碎片严重)查大 key:
redis-cli --bigkeys自动扫描并报告最大的 String、List、Set、Hash、ZSET。
看是否内存泄漏:
- 是不是忘了设过期时间?
TTL key看一下 - 是不是业务 bug 导致 key 无限增长?(比如用用户 ID 当 key,但没清理)
- 是不是忘了设过期时间?
解决:
- 给 key 加 TTL
- 删除无用大 key(用
UNLINK) - 开启
activedefrag(Redis 4.0+)自动整理碎片:activedefrag yes
故障3:主从复制延迟高 or 断连
排查:
看主从状态:
redis-cli INFO replication关注
slave0: offset=..., lag=...,lag > 10 秒就有问题。看网络:主从之间带宽是否打满?丢包?
看主节点负载:主 CPU 高?写入量太大?
看 repl_backlog 是否够大:断连后是否触发全量同步?
解决:
- 调大
repl-backlog-size - 主从部署在同一内网,别跨公网
- 减少大 key 写入(大 value 会拖慢复制)
故障4:Cluster 节点频繁 fail?
原因:
cluster-node-timeout太小(默认 15 秒),网络抖动就被判挂- 节点 CPU 或 IO 高,心跳包没及时回
解决:
- 调大
cluster-node-timeout到 30~60 秒 - 监控节点负载,避免资源争抢
