Search before asking
Version
Doris FE OOM Heap Dump 分析报告
一、宕机概况
| 项目 |
详情 |
| FE版本 |
Doris 3.1.4 |
| JVM配置 |
-Xmx32768m -Xms32768m(32GB堆) |
| Java版本 |
OpenJDK 17.0.12 |
| 宕机时间 |
2026-08-17 ~10:54 |
| FE启动时间 |
2026-08-03 16:05(运行约14天) |
| 宕机原因 |
java.lang.OutOfMemoryError: Java heap space |
| Heap Dump |
30.46GB,545,178,838个对象 |
| 重启后堆配置 |
48GB(-Xmx49152m) |
fe.out 关键输出
java.lang.OutOfMemoryError: Java heap space
Dumping heap to /data01/doris/fe/log/java_pid72774.hprof ...
Heap dump file created [30463119875 bytes in 98.764 secs]
#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
# Executing /bin/sh -c "kill -9 72774"...
二、MAT分析结果
使用 Eclipse Memory Analyzer (MAT) 对 29GB Heap Dump 进行自动化分析,识别出两个泄漏嫌疑点,均指向同一线程 all-fe-session-mgr-pool-0。
2.1 Problem Suspect 1:String 对象堆积(17.3GB,57.64%)
- 180,268,901 个
java.lang.String 实例,占用 17,305,670,752 字节(17.3GB,57.64%)
- 被一个
Object[180,221,098] 数组引用(1.44GB)
- 该数组由线程
all-fe-session-mgr-pool-0 持有
2.2 Problem Suspect 2:ConcurrentHashMap 膨胀(10.8GB,35.97%)
- 一个
ConcurrentHashMap$Node[268,435,456](2^28 个桶)占用 10,800,711,176 字节(10.8GB,35.97%)
- 包含 180,239,068 个 Node 条目
- 同样由线程
all-fe-session-mgr-pool-0 持有
2.3 OOM 触发时的线程栈
at java.lang.OutOfMemoryError.<init>() (OutOfMemoryError.java:48)
at java.util.Arrays.copyOf() (Arrays.java:3481)
at java.util.concurrent.ConcurrentHashMap$CollectionView.toArray() (ConcurrentHashMap.java:4471)
at java.util.ArrayList.<init>() (ArrayList.java:181)
at org.apache.doris.catalog.Env.getAllAliveSessionIds() (Env.java:7031)
at org.apache.doris.catalog.FESessionMgr$FEAliveSessionHandler.run() (FESessionMgr.java:94)
at java.util.concurrent.Executors$RunnableAdapter.call() (Executors.java:539)
at java.util.concurrent.FutureTask.run() (FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker() (ThreadPoolExecutor.java:1136)
at java.util.concurrent.ThreadPoolExecutor$Worker.run() (ThreadPoolExecutor.java:635)
at java.lang.Thread.run() (Thread.java:842)
2.4 MAT Top Consumers(支配树最大对象)
| 对象类型 |
实例数 |
Shallow Heap |
Retained Heap |
占比 |
ConcurrentHashMap$Node[] |
5 |
2,147,483,672 |
10,806,532,600 |
35.99% |
java.lang.Thread (all-fe-session-mgr-pool-0) |
1 |
160 |
1,441,778,504 |
4.80% |
java.lang.String |
180,268,901 |
5,768,604,832 |
17,305,670,752 |
57.64% |
2.5 MAT Class Histogram(Top 10)
| 类名 |
对象数 |
Shallow Heap |
Retained Heap |
java.lang.String |
180,549,648 |
5,777,588,736 |
>=17,339,850,056 |
byte[] |
180,690,113 |
11,773,285,544 |
>=11,773,285,544 |
ConcurrentHashMap$Node[] |
25,884 |
2,151,264,016 |
>=10,849,355,368 |
ConcurrentHashMap$Node |
180,353,465 |
8,656,966,320 |
>=8,678,776,232 |
java.lang.Object[] |
96,712 |
1,471,594,280 |
>=1,568,369,392 |
java.lang.Thread |
448 |
71,680 |
>=1,447,339,640 |
com.sleepycat.je.tree.BIN |
1,054 |
278,256 |
>=106,519,560 |
com.sleepycat.je.tree.IN |
1,062 |
25,488 |
>=103,781,928 |
com.sleepycat.je.tree.Node[] |
1,075 |
1,113,704 |
>=103,757,984 |
com.sleepycat.je.tree.LN |
132,262 |
4,232,384 |
>=102,644,392 |
2.6 MAT 系统概览
| 项目 |
值 |
| Heap Dump 大小 |
28 GB |
| 对象总数 |
545,178,838 |
| 类总数 |
27,765 |
| 类加载器总数 |
309 |
| GC Roots |
4,316 |
| 不可达对象 |
170,284(仅21MB) |
关键发现:545M 对象中仅有 170,284 个不可达对象(21MB),几乎所有对象都是存活且无法回收的泄漏对象。
三、根因分析
3.1 根本原因:FE Session ID 泄漏
FESessionMgr 中的 aliveSessionIds ConcurrentHashMap 持续累积了约 1.8 亿个 Session ID,从未被有效清理。
3.2 泄漏机制详解
客户端高频创建连接
|
v
每次连接产生一个 Session ID,存入 aliveSessionIds (ConcurrentHashMap)
|
v
连接关闭后 Session ID 仍留在 map 中,等待定期清理
|
v
清理线程 all-fe-session-mgr-pool 队列满,清理任务被拒绝 (RejectedExecutionException)
|
v
FE 间同步也失败 (Socket is closed by peer / Connection refused)
|
v
Session ID 只增不减,14天累积 1.8 亿条目
|
v
FEAliveSessionHandler 定期调用 Env.getAllAliveSessionIds()
-> new ArrayList(sessionIds.keySet()) <-- 1.8亿条目全量拷贝
-> OOM
3.3 内存分布
| 对象类型 |
实例数 |
内存占用 |
占比 |
| String(Session ID) |
180,549,648 |
17.3GB |
57.64% |
| ConcurrentHashMap$Node[] |
5 |
10.8GB |
35.99% |
| ConcurrentHashMap$Node |
180,353,465 |
8.7GB |
(含在上面) |
| 合计 |
~545M |
~28GB |
93.6% |
3.4 清理机制失效时间线
| 日期 |
all-fe-session-mgr-pool 队列满次数 |
说明 |
| 8/12 |
0 |
正常 |
| 8/13 |
0 |
正常 |
| 8/14 |
8 |
首次出现清理任务被拒绝 |
| 8/15 |
6 |
持续恶化 |
| 8/16 |
4 |
持续恶化 |
| 8/17 |
27 |
密集爆发,最终OOM |
3.5 完整事件时间线
| 时间 |
事件 |
| 8/3 16:05 |
FE启动,32GB堆 |
| 8/14 |
首次出现 RejectedExecutionException: queue size is full: all-fe-session-mgr-pool(8次) |
| 8/15-16 |
队列满错误持续(6次、4次) |
| 8/17 09:09 |
队列满错误密集爆发 |
| 8/17 09:18 |
Full GC后残留内存已达24GB,无法回收 |
| 8/17 10:42-10:55 |
连续 Full GC,每次耗时20+秒,GC后残留25-27GB |
| 8/17 10:54:17 |
PUBLISH_VERSION_EXEC 写BDB耗时19305ms,锁持有18.4秒 |
| 8/17 ~10:54 |
Env.getAllAliveSessionIds() 触发 OOM |
| 8/17 10:55:29 |
最后一次 Full GC:27GB存活对象,GC耗时21秒 |
| 8/17 10:57 |
Heap Dump 生成完毕(30.46GB) |
| 8/17 10:57 |
kill -9 终止进程 |
3.6 GC 日志分析
8/17 10:42:45 Full GC: 32402M -> 24621M (2572ms) <- Full GC后仍残留24GB
8/17 10:43:37 Full GC: 31488M -> 25845M (3236ms)
8/17 10:44:27 Full GC: 27244M -> 25830M (3097ms)
...
8/17 10:54:48 Full GC前: 27134388088 bytes (~27GB)
8/17 10:54:56 Full GC后: 27145836592 bytes (~27GB) <- 几乎无法回收
8/17 10:55:07 Full GC后: 27134575736 bytes (~27GB)
8/17 10:55:21 Full GC后: 27134388088 bytes (~27GB) <- 最后一次,21秒
Full GC 后仅能回收几百MB,27GB为存活无法回收的泄漏对象。
四、业务负载分析
4.1 审计日志统计(8/17当天)
| 语句类型 |
数量 |
| TRANSACTION |
99,706 |
| SELECT |
80,998 |
| SET |
36,985 |
| INSERT |
8,290 |
| SHOW |
7,584 |
| CREATE |
1,817 |
| DELETE |
483 |
4.2 用户请求分布
| 用户 |
INSERT/TRANSACTION 数 |
占比 |
| prod_qd_ab_wxh_w |
101,911 |
95.5% |
| prod_cd_option_w |
3,353 |
3.1% |
| test_cd_option_w |
2,603 |
2.4% |
| admin |
121 |
0.1% |
| prod_cd_raven_w |
8 |
<0.1% |
4.3 prod_qd_ab_wxh_w 语句分布
| 语句类型 |
数量 |
| TRANSACTION |
99,655 |
| SELECT |
51,982 |
| SET |
2,340 |
| INSERT |
2,256 |
| CREATE |
1,817 |
| DELETE |
441 |
4.4 典型业务SQL
崩溃前的主要负载为每分钟执行复杂 CTE 的 INSERT 语句:
INSERT INTO position_by_minute
WITH current_minute_changes AS (
SELECT instrument_id, MAX(produce_time) as max_time
FROM position
WHERE produce_time > 1786934880000000000
AND produce_time <= 1786934940000000000
AND expiry_date >= date '20260817'
GROUP BY instrument_id
),
current_records AS (
SELECT base.*
FROM position base
JOIN current_minute_changes cmc
ON base.instrument_id = cmc.instrument_id
AND base.produce_time = cmc.max_time
),
previous_snapshot_max_time AS (
SELECT prev.instrument_id, MAX(prev.produce_time) as prev_max_time
FROM position_by_minute prev
WHERE prev.snapshot_minute = '2026-08-17 10:48:00'
AND prev.zs_trading_date = 20260817
AND NOT EXISTS (
SELECT 1 FROM current_minute_changes cmc
WHERE prev.instrument_id = cmc.instrument_id
)
GROUP BY prev.instrument_id
),
...
SELECT '2026-08-17 10:49:00' as snapshot_minute, curr.*, 20260817 as zs_trading_date
FROM current_records curr
UNION ALL
SELECT '2026-08-17 10:49:00' as snapshot_minute, prev.*, 20260817 as zs_trading_date
FROM previous_base_records prev
查询特征:扫描 57M 行 / 62GB,峰值内存 752MB,CpuTimeMS 高达 329,538。
4.5 连接模式
- 客户端:MySQL Connector/J 8.0.33
- 来源:全部来自 172.24.16.108
- 模式:高频创建/断开连接(每分钟INSERT + 连接验证 + SET操作)
4.6 group_commit 问题
日志中还发现 group_commit 相关的事务冲突:
AnalysisException: begin transaction failed.
Label [group_commit_0a474c8412a331d3_cedb28f79ff3758e] has already been used,
relate to txn [3116755], status [PREPARE]
五、客户端正常close能否避免OOM
结论:不能完全避免
5.1 原因一:aliveSessionIds 的清理与连接关闭是解耦的
MAT 堆栈显示泄漏发生在 FESessionMgr$FEAliveSessionHandler.run() -> Env.getAllAliveSessionIds()。这是一个定期守护线程,通过跨 FE 同步来清理过期 session ID,不是在连接 close 时触发的。
即使客户端正常 close 连接,session ID 仍然留在 aliveSessionIds map 中,等待下次定期清理。而清理机制本身已经失效了。
5.2 原因二:清理机制从8月14日就已失效
8/14 RejectedExecutionException: queue size is full: all-fe-session-mgr-pool (8次)
8/15 同上 (6次)
8/16 同上 (4次)
8/17 同上 (27次) <- 密集爆发
线程池队列满了,清理任务被拒绝执行。同时 FE 间同步也失败:
Error occurred when get alive session from 172.24.16.108, msg = Socket is closed by peer
Error occurred when get alive session from 172.24.16.109, msg = Socket is closed by peer
清理线程跑不起来 -> session ID 只增不减 -> 14天累积1.8亿条目 -> OOM
5.3 原因三:prod_qd_ab_wxh_w 是最大贡献者
该用户单日执行了近10万次 TRANSACTION + 2256次 INSERT,全部来自 172.24.16.108。按14天外推,产生了大量 session。
5.4 客户端正常close的效果
| 措施 |
效果 |
| 客户端正常close连接 |
减少session创建速率,延缓OOM发生 |
| 但无法阻止 |
清理机制失效后,即使close了,session ID仍在map中 |
| OOM触发点 |
与连接关闭无关,是定期清理任务自身在拷贝时OOM |
5.5 根本结论
这是 Doris 3.1.4 的服务端Bug,不是单纯的客户端问题:
FESessionMgr 的 aliveSessionIds 缺少有效的过期清理机制 — 只依赖跨 FE 定期同步,一旦同步失败就只增不减
all-fe-session-mgr-pool 线程池队列太小 — 高并发下队列满,清理任务被拒绝
Env.getAllAliveSessionIds() 实现有缺陷 — 直接 new ArrayList(keySet()) 全量拷贝,session 数量大时必然 OOM
即使3个用户全部正常close,只要清理机制失效,session ID仍会累积到OOM。 正常close只能减缓累积速度,不能根本解决问题。
我的问题是,目前Doris3.1.4 fe节点是否发现类似内存泄露反馈?
What's Wrong?
我的问题是,目前Doris3.1.4 fe节点是否发现类似内存泄露反馈?
What You Expected?
确认Doris3.1.4 fe节点是否存在内存泄露问题
How to Reproduce?
No response
Anything Else?
No response
Are you willing to submit PR?
Code of Conduct
Search before asking
Version
Doris FE OOM Heap Dump 分析报告
一、宕机概况
-Xmx32768m -Xms32768m(32GB堆)java.lang.OutOfMemoryError: Java heap space-Xmx49152m)fe.out 关键输出
二、MAT分析结果
使用 Eclipse Memory Analyzer (MAT) 对 29GB Heap Dump 进行自动化分析,识别出两个泄漏嫌疑点,均指向同一线程
all-fe-session-mgr-pool-0。2.1 Problem Suspect 1:String 对象堆积(17.3GB,57.64%)
java.lang.String实例,占用 17,305,670,752 字节(17.3GB,57.64%)Object[180,221,098]数组引用(1.44GB)all-fe-session-mgr-pool-0持有2.2 Problem Suspect 2:ConcurrentHashMap 膨胀(10.8GB,35.97%)
ConcurrentHashMap$Node[268,435,456](2^28 个桶)占用 10,800,711,176 字节(10.8GB,35.97%)all-fe-session-mgr-pool-0持有2.3 OOM 触发时的线程栈
2.4 MAT Top Consumers(支配树最大对象)
ConcurrentHashMap$Node[]java.lang.Thread(all-fe-session-mgr-pool-0)java.lang.String2.5 MAT Class Histogram(Top 10)
java.lang.Stringbyte[]ConcurrentHashMap$Node[]ConcurrentHashMap$Nodejava.lang.Object[]java.lang.Threadcom.sleepycat.je.tree.BINcom.sleepycat.je.tree.INcom.sleepycat.je.tree.Node[]com.sleepycat.je.tree.LN2.6 MAT 系统概览
三、根因分析
3.1 根本原因:FE Session ID 泄漏
FESessionMgr中的aliveSessionIdsConcurrentHashMap 持续累积了约 1.8 亿个 Session ID,从未被有效清理。3.2 泄漏机制详解
3.3 内存分布
3.4 清理机制失效时间线
3.5 完整事件时间线
RejectedExecutionException: queue size is full: all-fe-session-mgr-pool(8次)PUBLISH_VERSION_EXEC写BDB耗时19305ms,锁持有18.4秒Env.getAllAliveSessionIds()触发 OOMkill -9终止进程3.6 GC 日志分析
Full GC 后仅能回收几百MB,27GB为存活无法回收的泄漏对象。
四、业务负载分析
4.1 审计日志统计(8/17当天)
4.2 用户请求分布
4.3 prod_qd_ab_wxh_w 语句分布
4.4 典型业务SQL
崩溃前的主要负载为每分钟执行复杂 CTE 的 INSERT 语句:
查询特征:扫描 57M 行 / 62GB,峰值内存 752MB,CpuTimeMS 高达 329,538。
4.5 连接模式
4.6 group_commit 问题
日志中还发现 group_commit 相关的事务冲突:
五、客户端正常close能否避免OOM
结论:不能完全避免
5.1 原因一:aliveSessionIds 的清理与连接关闭是解耦的
MAT 堆栈显示泄漏发生在
FESessionMgr$FEAliveSessionHandler.run()->Env.getAllAliveSessionIds()。这是一个定期守护线程,通过跨 FE 同步来清理过期 session ID,不是在连接 close 时触发的。即使客户端正常 close 连接,session ID 仍然留在
aliveSessionIdsmap 中,等待下次定期清理。而清理机制本身已经失效了。5.2 原因二:清理机制从8月14日就已失效
线程池队列满了,清理任务被拒绝执行。同时 FE 间同步也失败:
清理线程跑不起来 -> session ID 只增不减 -> 14天累积1.8亿条目 -> OOM
5.3 原因三:prod_qd_ab_wxh_w 是最大贡献者
该用户单日执行了近10万次 TRANSACTION + 2256次 INSERT,全部来自 172.24.16.108。按14天外推,产生了大量 session。
5.4 客户端正常close的效果
5.5 根本结论
这是 Doris 3.1.4 的服务端Bug,不是单纯的客户端问题:
FESessionMgr的aliveSessionIds缺少有效的过期清理机制 — 只依赖跨 FE 定期同步,一旦同步失败就只增不减all-fe-session-mgr-pool线程池队列太小 — 高并发下队列满,清理任务被拒绝Env.getAllAliveSessionIds()实现有缺陷 — 直接new ArrayList(keySet())全量拷贝,session 数量大时必然 OOM即使3个用户全部正常close,只要清理机制失效,session ID仍会累积到OOM。 正常close只能减缓累积速度,不能根本解决问题。
我的问题是,目前Doris3.1.4 fe节点是否发现类似内存泄露反馈?
What's Wrong?
我的问题是,目前Doris3.1.4 fe节点是否发现类似内存泄露反馈?
What You Expected?
确认Doris3.1.4 fe节点是否存在内存泄露问题
How to Reproduce?
No response
Anything Else?
No response
Are you willing to submit PR?
Code of Conduct