Redis实例遭OOM Killer终止:如何排查内存溢出问题?
问题描述
使用bun-redis存储数百个WebSocket连接的实时数据,数据淘汰策略设为10天,近期遇到OOM Killer终止进程的问题:
A process of this unit has been killed by the OOM killer. Killing process 77506 (HeapHelper) with signal SIGKILL. Failed with result 'oom-kill'. Consumed 1d 22h 10min 6.378s CPU time.
系统内存状态(OOM发生后):
~ ❯ free -h total used free shared buff/cache available Mem: 27Gi 7.4Gi 18Gi 11Mi 1.1Gi 19Gi
Redis内存统计:
127.0.0.1:6379> MEMORY STATS 1) "peak.allocated" 2) (integer) 4547468208 3) "total.allocated" 4) (integer) 4547247816 5) "startup.allocated" 6) (integer) 1069176 7) "replication.backlog" 8) (integer) 0 9) "clients.slaves" 10) (integer) 0 11) "clients.normal" 12) (integer) 1928 13) "cluster.links" 14) (integer) 0 15) "aof.buffer" 16) (integer) 0 17) "lua.caches" 18) (integer) 0 19) "functions.caches" 20) (integer) 184 21) "db.0" 22) 1) "overhead.hashtable.main" 2) (integer) 241912 3) "overhead.hashtable.expires" 4) (integer) 88 23) "overhead.total" 24) (integer) 1313288 25) "keys.count" 26) (integer) 4408 27) "keys.bytes-per-key" 28) (integer) 1031347 29) "dataset.bytes" 30) (integer) 4545934528 31) "dataset.percentage" 32) "99.99462890625" 33) "peak.percentage" 34) "99.99514770507813" 35) "allocator.allocated" 36) (integer) 4547537240 37) "allocator.active" 38) (integer) 4547805184 39) "allocator.resident" 40) (integer) 4695977984 41) "allocator-fragmentation.ratio" 42) "1.000058889389038" 43) "allocator-fragmentation.bytes" 44) (integer) 267944 45) "allocator-rss.ratio" 46) "1.0325812101364136" 47) "allocator-rss.bytes" 48) (integer) 148172800 49) "rss-overhead.ratio" 50) "1.0022660493850708" 51) "rss-overhead.bytes" 52) (integer) 10641408 53) "fragmentation" 54) "1.0350526571273804" 55) "fragmentation.bytes" 56) (integer) 159392128
可见Redis峰值内存仅约4.5GB,系统仍有大量剩余内存。重启Redis时的加载信息显示,RDB文件创建时内存占用达23946.19 Mb(约23.4GB):
5:09:46.782 * <search> Loading event starts 5:09:46.782 * Loading RDB produced by version 255.255.255 5:09:46.782 * RDB age 53411 seconds 5:09:46.782 * RDB memory usage when created 23946.19 Mb 5:09:53.947 * Done loading RDB, keys loaded: 4408, keys expired: 0. 5:09:53.947 # <search> Skip background reindex scan, redis version contains loaded event. 5:09:53.947 * <search> Loading event ends 5:09:53.947 * DB loaded from disk: 7.166 seconds
排查方向
重点监控HeapHelper进程的内存变化
HeapHelper是bun runtime负责内存管理的子进程,OOM Killer终止的是它而非Redis主进程,需确认:- 用
top/htop或ps aux | grep HeapHelper实时追踪该进程的内存占用,看是否存在持续增长的泄漏情况。 - 检查当前使用的bun版本,是否存在已知的HeapHelper内存泄漏bug(比如WebSocket连接、Redis客户端操作相关的内存未释放问题)。
- 用
验证Redis数据淘汰策略的有效性
重启时RDB创建时内存达23.4GB,但运行时Redis仅用4.5GB,说明数据集曾远大于当前规模,需排查:- 执行
CONFIG GET maxmemory-policy确认淘汰策略是否正确配置为volatile-lru(对应带过期时间的key),同时检查maxmemory是否设置合理(若未设置,Redis会无限制占用内存)。 - 随机抽样key执行
TTL key,确认是否都正确设置了10天左右的过期时间,是否存在大量未设置过期的key导致数据堆积。
- 执行
排查WebSocket与bun-redis的内存泄漏
数百个WebSocket连接可能存在资源未释放的情况:- 检查WebSocket连接断开时的清理逻辑,是否正确释放了关联的Redis客户端、缓存数据及相关对象,避免全局容器(如数组、Map)持续持有无效连接或消息数据。
- 使用
bun --inspect启动服务,通过Chrome DevTools的内存快照功能,分析是否有大量未释放的WebSocket实例、Redis客户端或消息对象堆积。
分析OOM Killer的触发逻辑
OOM Killer杀进程并非只看总内存,需确认:- 查看HeapHelper进程的OOM得分:
cat /proc/[pid]/oom_score_adj,是否被设置为较高值导致优先被选中。 - 查看系统日志
dmesg | grep -i oom,获取OOM触发时的详细内存状态,确认是否有其他进程突发占用内存,或Redis开启了mlockall(执行CONFIG GET mlockall)锁定内存,导致系统可用内存被压缩。
- 查看HeapHelper进程的OOM得分:
优化bun-redis客户端的使用
Redis统计显示有1928个普通客户端,远超WebSocket连接数,需排查:- 检查bun-redis的连接池配置,是否复用了客户端连接,避免每个WebSocket连接创建新的Redis客户端导致连接泄漏。
- 尽量使用批量操作(如
MSET、HMSET)代替单个操作,减少客户端交互的内存开销。 - 检查是否有大量未处理的Redis响应堆积在客户端缓冲区,导致HeapHelper内存占用上升。
内容的提问来源于stack exchange,提问作者xtyy
相关产品推荐
相关产品推荐

