导语:应用突然大量报错,日志里写着 oom command not allowed when used memory > 'maxmemory',或者 err max number of clients reached。登上去 redis-cli 敲什么都超时——这是 redis 运维最常见的两种"猝死"。别急着重启,按下面四步走,先定位再处置。
一、第 1 步:先分清是"内存满"还是"连接满"
两种故障的排查路径完全不同,第一步必须分开看。
redis-cli -h 10.0.0.10 -p 6379 # 内存视图 info memory # used_memory_human 已用内存(数据集+开销) # used_memory_rss_human 操作系统看到的常驻内存 # maxmemory_human 配置的上限 # maxmemory_policy 淘汰策略 # mem_fragmentation_ratio 碎片率
# 连接视图 info clients # connected_clients 当前连接数 # blocked_clients 阻塞在 blpop 等的连接 # client_recent_max_input_buffer / output_buffer info stats # rejected_connections 因超 maxclients 被拒的连接数 # evicted_keys 因内存淘汰被删的 key 数 # expired_keys 已过期删除的 key 数
判读口径:
used_memory顶到maxmemory且evicted_keys猛涨 → 内存问题。connected_clients逼近maxclients、rejected_connections不为 0 → 连接问题。mem_fragmentation_ratio> 1.5 → 碎片严重;< 1 → 已经在用 swap,性能会断崖式下跌。
避坑 1:maxmemory 设了但没设 maxmemory-policy,默认是 noeviction——写请求会直接报 oom,而不是淘汰旧数据。这是"内存没满却写不进去"的头号原因。
二、第 2 步:找出谁在吃内存(大 key / 热点 key)
内存问题 90% 出在少数几个大 key 上。
# 按数据类型采样,找出每种类型最大的 key(redis 自带,开销低) redis-cli --bigkeys # redis 6.0+ 还可以按内存排序 redis-cli --memkeys # 精确定位某个 key 的真实内存占用(含内部编码开销) redis-cli memory usage my:big:hash samples 0
找不到方向时,用 scan 分批采样统计,而不是 keys *:
# 抽样 1000 个 key,按前缀聚合数量,找"数量异常多"的业务前缀 redis-cli --scan --pattern 'order:*' --count 1000 | head -n 1000 # 找出大 hash / 大 zset 的元素个数 redis-cli hlen order:detail:20261009001 redis-cli zcard rank:hot:global
热点 key 用 lfu 策略统计(需 maxmemory-policy 为 allkeys-lfu / volatile-lfu):
redis-cli --hotkeys
避坑 2:keys *、flushall、monitor 在生产环境一律禁用。前两个会阻塞主线程导致秒级卡死,monitor 会把所有命令广播给慢客户端,几分钟就能把内存打爆。
避坑 3:--bigkeys 内部仍要遍历全库,请在业务低峰期执行;超大实例可先 --scan 估量。
三、第 3 步:看清内存到底花在哪
used_memory 不等于数据集,开销同样能吃人。
info memory # used_memory_dataset 纯数据占用 # used_memory_overhead 客户端缓冲区、复制积压等开销 # used_memory_peak_human 历史峰值 # used_memory_lua 脚本
排查三个常被忽略的"隐形内存":
# 1) 客户端输出缓冲区:慢客户端(订阅、monitor、大结果集)会积压 redis-cli client list # 关注 omem(输出缓冲区)、qbuf、idle 三列,omem 特别大的连接就是"慢客户端" # 2) 主从复制积压区 info replication # repl_backlog_size 配置过大 / 从库长时间断连都会撑大内存 # 3) 过期 key 没被及时回收 info keyspace # expires 与 keys 的差值异常,说明大量 key 无 ttl
四、第 4 步:常见根因与处置
排查到最后,逃不出这五类:
- 缓存不设 ttl:业务写入的 key 永不过期,只增不减。给所有缓存 key 加过期时间,或改用带容量的本地缓存 + redis 组合。
- 大 key:单个 hash/list/zset 存了几十万甚至上百万元素(如全量字典、排行榜、日志队列)。按业务维度拆分,或用 hash tag 分片。
- 客户端连接泄漏:应用没复用连接池、异常分支忘了
close(),connected_clients缓慢爬升。常见于短连接模式与定时任务。 - 输出缓冲区失控:慢客户端订阅大频道、执行
monitor、keys,omem飙到几百 mb。 - aof rewrite / fork 抖动:重写期间 cow 会额外占用内存,
maxmemory没留余量就会触发 oom。
应急止血:先降载,别急着删
# 1) 临时改为 lru 淘汰,先让写入活下来(注意会丢数据)
redis-cli config set maxmemory-policy allkeys-lru
# 2) 删大 key 用 unlink(异步回收,不阻塞主线程),别用 del
redis-cli unlink order:detail:20260101
# 3) 批次删除,别一次删一堆
redis-cli --scan --pattern 'temp:*' --count 100 | xargs -l 100 redis-cli unlink
# 4) 断开空闲连接,清理连接泄漏
redis-cli client list | awk -f'idle=' '{split($2,a," "); if (a[1] > 3600) print $1}' | head
redis-cli client kill id <id>
长期治理:为实例设定 maxmemory(物理内存的 60%–75%,留出 fork 与 os 空间)、显式配置淘汰策略、给所有缓存 key 加 ttl、把 used_memory、connected_clients、evicted_keys、rejected_connections 纳入监控告警(内存 > 80% 阈值、连接数 > 80% maxclients 提前预警)。
五、避坑清单
keys */flushall/monitor生产禁用,改用scan与info。- 删大 key 用
unlink而非del,del会阻塞主线程。 - 只设
maxmemory不设maxmemory-policy,默认noeviction会直接拒绝写入。 maxmemory不要设成物理内存全量:rdb 保存 / aof 重写需要 fork,cow 要有余量。- 主从实例的
maxmemory应保持一致,从库更小会导致主从数据不一致。 maxclients受 os 的ulimit -n限制,连接打满时先确认系统句柄数。- 上线前做一次容量基线:单 key 元素上限、平均 value 大小、日均 key 增量,出问题才能判断"现在算不算异常"。
小结:顺序记成一句话——info 分清内存/连接 → --bigkeys 揪大 key → info memory 看清开销构成 → 按五类根因处置,先 unlink 降载再治理。redis 排查的关键是"先看指标、再找 key、后动数据":不要一上来就重启或 flushall,把"内存涨了多少、是谁在涨、涨在数据集还是开销"三个问题回答清楚,元凶自然现形。
以上就是redis内存打满、连接数飙红的排查方法的详细内容,更多关于redis内存打满、连接数飙红的资料请关注代码网其它相关文章!
发表评论