跳到主要内容
跳到主要内容

BE OOM 分析

备注

自 Doris 1.2 版本开始支持 BE OOM 分析

理想情况下,在 Memory Limit Exceeded Analysis 中我们定时检测操作系统剩余可用内存,并在内存不足时及时响应,如触发内存 GC 释放缓存或 cancel 内存超限的查询,但因为刷新进程内存统计和内存 GC 都具有一定的滞后性,同时我们很难完全 catch 所有大内存申请,在集群压力过大时仍有 OOM 风险。

解决方法

参考 BE 配置项be.conf中调小mem_limit,调大max_sys_mem_available_low_water_mark_bytes

内存分析

若希望进一步了解 OOM 前 BE 进程的内存使用位置,减少进程内存使用,可参考如下步骤分析。

  1. dmesg -T确认 OOM 的时间和 OOM 时的进程内存。

  2. 查看 be/log/be.INFO 的最后是否有 Memory Tracker Summary 日志,如果有说明 BE 已经检测到内存超限,则继续步骤 3,否则继续步骤 8

Memory Tracker Summary:
Type=consistency, Used=0(0 B), Peak=0(0 B)
Type=batch_load, Used=0(0 B), Peak=0(0 B)
Type=clone, Used=0(0 B), Peak=0(0 B)
Type=schema_change, Used=0(0 B), Peak=0(0 B)
Type=compaction, Used=0(0 B), Peak=0(0 B)
Type=load, Used=0(0 B), Peak=0(0 B)
Type=query, Used=206.67 MB(216708729 B), Peak=565.26 MB(592723181 B)
Type=global, Used=930.42 MB(975614571 B), Peak=1017.42 MB(1066840223 B)
Type=tc/jemalloc_cache, Used=51.97 MB(54494616 B), Peak=-1.00 B(-1 B)
Type=process, Used=1.16 GB(1246817916 B), Peak=-1.00 B(-1 B)
MemTrackerLimiter Label=Orphan, Type=global, Limit=-1.00 B(-1 B), Used=474.20 MB(497233597 B), Peak=649.18 MB(680718208 B)
MemTracker Label=BufferAllocator, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
MemTracker Label=LoadChannelMgr, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
MemTracker Label=StorageEngine, Parent Label=Orphan, Used=320.56 MB(336132488 B), Peak=322.56 MB(338229824 B)
MemTracker Label=SegCompaction, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
MemTracker Label=SegmentMeta, Parent Label=Orphan, Used=948.64 KB(971404 B), Peak=943.64 KB(966285 B)
MemTracker Label=TabletManager, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
MemTrackerLimiter Label=DataPageCache, Type=global, Limit=-1.00 B(-1 B), Used=455.22 MB(477329882 B), Peak=454.18 MB(476244180 B)
MemTrackerLimiter Label=IndexPageCache, Type=global, Limit=-1.00 B(-1 B), Used=1.00 MB(1051092 B), Peak=0(0 B)
MemTrackerLimiter Label=SegmentCache, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)
MemTrackerLimiter Label=DiskIO, Type=global, Limit=2.47 GB(2655423201 B), Used=0(0 B), Peak=0(0 B)
MemTrackerLimiter Label=ChunkAllocator, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)
MemTrackerLimiter Label=LastestSuccessChannelCache, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)
MemTrackerLimiter Label=DeleteBitmap AggCache, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)
  1. 当 OOM 前 be/log/be.INFO 的最后包含系统内存超限的日志时,参考 Memory Limit Exceeded Analysis 中的日志分析方法,查看进程每个类别的内存使用情况。若当前是type=query内存使用较多,若已知 OOM 前的查询继续步骤 4,否则继续步骤 5;若当前是type=load内存使用多继续步骤 6,若当前是type=global内存使用多继续步骤 7。

  2. type=query查询内存使用多,且已知 OOM 前的查询时,比如测试集群或定时任务,重启 BE 节点,参考 Memory Tracker 查看实时 memory tracker 统计,set global enable_profile=true后重试查询,观察具体算子的内存使用位置,确认查询内存使用是否合理,进一步考虑优化 SQL 内存使用,比如调整 join 顺序。

  3. type=query查询内存使用多,且未知 OOM 前的查询时,比如位于线上集群,则在be/log/be.INFO从后向前搜Deregister query/load memory tracker, queryIdRegister query/load memory tracker, query/load id,同一个 query id 若同时打出上述两行日志则表示查询或导入成功,若只有 Register 没有 Deregister,则这个查询或导入在 OOM 前仍在运行,这样可以得到 OOM 前所有正在运行的查询和导入,按照步骤 4 的方法对可疑大内存查询分析其内存使用。

  4. type=load导入内存使用多时。

  5. type=global内存使用多时,继续查看Memory Tracker Summary日志后半部分已经打出得type=global详细统计。当 DataPageCache、IndexPageCache、SegmentCache、ChunkAllocator、LastestSuccessChannelCache 等内存使用多时,参考 BE 配置项 考虑修改 cache 的大小;当 Orphan 内存使用过多时,如下继续分析。

  • Parent Label=Orphan的 tracker 统计值相加只占 Orphan 内存的小部分,则说明当前有大量内存没有准确统计,比如 brpc 过程的内存,此时可以考虑借助 heap profile Memory Tracker 中的方法进一步分析内存位置。

  • Parent Label=Orphan的 tracker 统计值相加占 Orphan 内存的大部分,当Label=TabletManager内存使用多时,进一步查看集群 Tablet 数量,若 Tablet 数量过多则考虑删除过时不会被使用的表或数据;当Label=StorageEngine内存使用过多时,进一步查看集群 Segment 文件个数,若 Segment 文件个数过多则考虑手动触发 compaction;

  1. be/log/be.INFO没有在 OOM 前打印出Memory Tracker Summary日志,说明 BE 没有及时检测出内存超限,观察 Grafana 内存监控确认 BE 在 OOM 前的内存增长趋势,若 OOM 可复现,考虑在be.conf中增加memory_debug=true,重启集群后会每秒打印集群内存统计,观察 OOM 前的最后一次Memory Tracker Summary日志,继续步骤 3 分析