服务异常跟踪
1、业务表现
服务不可用,转圈圈
2、上日志
Redisson + Netty 堆内存溢出(OOM)问题完整解决方案
你遇到的核心错误是:Java 堆内存不足,且溢出发生在 Redisson 编码发送 Redis 命令 的阶段(Netty 编码器),这是典型的大对象 / 大批量命令 / 内存配置不足导致的 OOM。
先给你最关键的结论:
这个 OOM 不是普通的内存泄漏,90% 是因为你一次性往 Redis 发送了超大数据 / 批量命令,或者 JVM 堆内存配置太小,Redisson 编码时直接撑爆了堆。
一、快速定位根因(3 个最常见原因)
结合你的日志(CommandEncoder/CommandBatchEncoder),问题来源只有这几种:
- 批量操作过大(最常见)使用
RBatch批量执行几千 / 几万条 Redis 命令,Redisson 编码时会一次性加载所有命令到内存,直接溢出。 - 存储超大 Value往 Redis 塞超大对象 / 超大集合(比如 100MB + 的 JSON、List),序列化 + 编码时内存暴涨。
- JVM 堆内存默认配置太小生产环境 JVM 默认堆只有几百 MB,稍微大一点的操作就溢出。
二、立即生效的修复方案(按优先级执行)
1. 第一步:增大 JVM 堆内存(最快解决)
直接修改 Java 启动参数,这是最立竿见影的方案:
# 推荐配置(根据服务器内存调整,最小给 2G 堆) java -Xms2g -Xmx4g -jar your-app.jar
参数说明:
-Xms2g:初始堆内存 2GB-Xmx4g:最大堆内存 4GB
服务器内存≥8G → 推荐
-Xmx4g -Xms4g;服务器内存≥16G → 推荐-Xmx8g -Xms8g
2. 第二步:修复 Redisson 批量操作(核心问题)
如果你代码里用了 RBatch(批量命令),绝对不能一次性提交大量命令!
❌ 错误写法(会 OOM):
RBatch batch = redisson.createBatch();
// 循环10万条命令,直接撑爆内存
for (int i = 0; i < 100000; i++) {
batch.getMap("test").putAsync("key"+i, "value");
}
batch.execute();
✅ 正确写法(分批提交,每 1000 条执行一次):
// 每1000条命令提交一次,避免内存堆积
int batchSize = 1000;
RBatch batch = redisson.createBatch();
for (int i = 0; i < 100000; i++) {
batch.getMap("test").putAsync("key"+i, "value");
// 达到阈值立即执行,清空内存
if ((i + 1) % batchSize == 0) {
batch.execute();
batch = redisson.createBatch();
}
}
// 执行剩余命令
if (batch.isActive()) {
batch.execute();
}
3. 第三步:禁止存储超大 Value 到 Redis
❌ 不要存:
- 10MB 以上的单个对象
- 包含 10 万条数据的 List/Set
- 超大 JSON 字符串
✅ 优化方案:
- 大对象拆分(分多个 key 存储)
- 大集合分页存储
- 使用二进制压缩(Redisson 支持 snappy 压缩)
Redisson 开启数据压缩(降低内存占用)
在redisson.yml配置中添加:
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.SnappyCodec> {} # 开启压缩
4. 第四步:优化 Redisson 连接配置(防止堆积)
修改 Redisson 配置,限制命令队列大小,避免无限堆积撑爆内存:
singleServerConfig: address: "redis://127.0.0.1:6379" connectionMinimumIdleSize: 10 connectionPoolSize: 64 retryAttempts: 3 retryInterval: 1000 # 关键配置:限制每个连接的等待命令队列,防止无限堆积 pendingQueueSize: 2000
三、高级排查:确认到底是什么占了内存
如果上面方案还没解决,你需要抓堆 dump分析:
- 添加 JVM 参数,自动生成内存溢出快照:shell
- 用 JProfiler / Eclipse MAT 工具打开 dump 文件
- 直接查看:
org.redisson相关对象占用的内存大小
你会直接看到:
- 超大的
CommandBatch对象 - 超大的待发送 Redis 命令队列
四、总结:必做的 3 件事
- 加大 JVM 堆内存:
-Xms2g -Xmx4g起步 - 拆分批量操作:RBatch 每 1000 条命令执行一次,不要无限累加
- 禁止超大 Value:拆分大对象、开启数据压缩