BE OOM分析

SinceVersion 1.2.0

理想情况下,在 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

  1. Memory Tracker Summary:
  2. Type=consistency, Used=0(0 B), Peak=0(0 B)
  3. Type=batch_load, Used=0(0 B), Peak=0(0 B)
  4. Type=clone, Used=0(0 B), Peak=0(0 B)
  5. Type=schema_change, Used=0(0 B), Peak=0(0 B)
  6. Type=compaction, Used=0(0 B), Peak=0(0 B)
  7. Type=load, Used=0(0 B), Peak=0(0 B)
  8. Type=query, Used=206.67 MB(216708729 B), Peak=565.26 MB(592723181 B)
  9. Type=global, Used=930.42 MB(975614571 B), Peak=1017.42 MB(1066840223 B)
  10. Type=tc/jemalloc_cache, Used=51.97 MB(54494616 B), Peak=-1.00 B(-1 B)
  11. Type=process, Used=1.16 GB(1246817916 B), Peak=-1.00 B(-1 B)
  12. MemTrackerLimiter Label=Orphan, Type=global, Limit=-1.00 B(-1 B), Used=474.20 MB(497233597 B), Peak=649.18 MB(680718208 B)
  13. MemTracker Label=BufferAllocator, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
  14. MemTracker Label=LoadChannelMgr, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
  15. MemTracker Label=StorageEngine, Parent Label=Orphan, Used=320.56 MB(336132488 B), Peak=322.56 MB(338229824 B)
  16. MemTracker Label=SegCompaction, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
  17. MemTracker Label=SegmentMeta, Parent Label=Orphan, Used=948.64 KB(971404 B), Peak=943.64 KB(966285 B)
  18. MemTracker Label=TabletManager, Parent Label=Orphan, Used=0(0 B), Peak=0(0 B)
  19. MemTrackerLimiter Label=DataPageCache, Type=global, Limit=-1.00 B(-1 B), Used=455.22 MB(477329882 B), Peak=454.18 MB(476244180 B)
  20. MemTrackerLimiter Label=IndexPageCache, Type=global, Limit=-1.00 B(-1 B), Used=1.00 MB(1051092 B), Peak=0(0 B)
  21. MemTrackerLimiter Label=SegmentCache, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)
  22. MemTrackerLimiter Label=DiskIO, Type=global, Limit=2.47 GB(2655423201 B), Used=0(0 B), Peak=0(0 B)
  23. MemTrackerLimiter Label=ChunkAllocator, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)
  24. MemTrackerLimiter Label=LastSuccessChannelCache, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)
  25. 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、LastSuccessChannelCache 等内存使用多时,参考 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分析;