首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >彻底搞懂Doris内存管理:从结构、跟踪到控制

彻底搞懂Doris内存管理:从结构、跟踪到控制

作者头像
数据极客圈
发布2025-12-16 14:24:44
发布2025-12-16 14:24:44
2410
举报

在Doris集群运维中,内存问题永远是最让人头疼的“拦路虎”——查询突然OOM、内存占用居高不下、GC频繁触发导致查询卡顿等,这些问题不仅影响业务稳定性,排查起来也常常无从下手。

作为基于MPP架构的OLAP引擎,Doris的高性能依赖高效的内存管理——数据在内存中流式计算、中间结果缓存、算子并行执行,都离不开对内存的精准把控。今天,我们从“内存结构→跟踪监控→控制策略→实战排查”四个维度,把Doris内存管理扒透,让你既能看懂底层逻辑,又能落地解决实际问题。

一、Doris BE的内存结构到底是什么样?

要解决内存问题,首先得知道Doris的内存都用在了哪里。Doris BE的内存整体分为“被跟踪内存(tracked)”和“未被跟踪内存(untracked)”两大类,每类又包含多个细分模块,下面来看看整体的内存结构。

1. 整体内存结构拆解

代码语言:javascript
复制
服务器物理内存
├─ Linux内核+其他进程内存
└─ Doris BE进程内存
   ├─ 未被跟踪内存(untracked):无需手动管控,占比小
   │  ├─ RPC通信内存
   │  ├─ JVM内存(访问外表、Java UDF时使用)
   │  └─ 部分元数据(未完全统计)
   └─ 被跟踪内存(tracked):核心管控对象,支持监控和回收
      ├─ Jemalloc管理内存:内存分配的“中间枢纽”
      │  ├─ Jemalloc缓存(线程缓存、脏页)
      │  └─ Jemalloc元数据
      ├─ 全局共享内存(生命周期与进程一致)
      │  ├─ Doris缓存(数据页缓存、索引缓存、文件缓存等)
      │  └─ 全局元数据(表结构、Tablet元数据、RowSet元数据等)
      └─ 任务级内存(任务结束后释放)
         ├─ 查询内存(数据块、Hash表、序列化缓存等)
         ├─ 导入内存(数据块、MemTable、刷盘缓存等)
         ├─ Compaction内存(多版本合并时的中间数据)
         └─ 其他任务(Schema Change、副本克隆等)

2. 关键内存模块说明

  • Jemalloc:Doris 1.2.2后默认的内存分配器(替代TCMalloc),高并发下性能更优,负责管理线程缓存和内存块分配,避免频繁向系统申请内存;
  • 全局缓存:可通过参数控制大小,内存不足时会自动回收,比如过期的Segment Cache、数据页缓存;
  • 查询内存:动态变化最大的部分,Join/聚合/排序等算子会占用大量内存,比如Hash Join构建的哈希表、Sort算子的排序缓存;
  • 导入内存:数据导入时先写入MemTable(内存临时结构),达到阈值后刷盘,这部分内存可通过参数限制。

二、内存跟踪器(Memory Tracker)

Doris通过Memory Tracker实现对内存的精准跟踪,不管是整体内存占用,还是单个查询/导入的内存消耗,都能实时查看,是排查内存问题的核心工具。

1. 怎么做到“内存使用全记录”?

  • 统一分配入口:Doris核心数据结构(Arena、HashTable等)都继承自Allocator,所有内存申请和释放都通过Allocator统一处理,自动记录到对应的Memory Tracker;
  • 线程本地绑定:每个查询、导入等任务初始化时,会创建专属的Memory Tracker,并绑定到线程本地存储(Thread Local Storage / TLS),任务执行过程中产生的内存都会自动关联;
  • 算子级跟踪:Join、Agg、Sort等算子会创建独立的Memory Tracker,可精准定位哪个算子占用内存过多。

2. 两种核心Tracker类型

Tracker类型

作用

典型场景

Memory Tracker Limiter

内存限制+监控

单个查询、导入、全局缓存,支持设置内存上限

Memory Tracker

跟踪内存热点

算子级内存使用(如Hash Join的哈希表)用于导入数据下刷的内存控制

它们的关系是“软关联”:父子关系仅用于日志打印和快照展示,生命周期互不影响,避免复杂依赖。

3. 如何查看内存跟踪数据?

(1)实时内存统计(Web页面,最常用)
  • 访问地址:http://{BE_HOST}:{BE_WEB_PORT}/mem_tracker(默认端口8040)
  • 核心指标解读:
    • process resident memory:BE进程物理内存(取自系统/proc文件,最准确);
    • sum of all trackers:所有Tracker统计的内存总和(通常小于物理内存,存在统计缺失);
    • query/load/compaction:对应任务类型的总内存占用;
    • global:全局共享内存(缓存+元数据)。
  • 查看详情:在URL后加?type=xxx,比如?type=query查看所有查询的内存消耗,?type=global查看全局缓存详情。
(2)历史内存趋势(Bvar页面)
  • 访问地址:http://{BE_HOST}:{BRPC_PORT}/vars/*memory_*(默认端口8060)
  • 用途:查看某类内存的变化趋势,定位内存泄漏或突增问题。
(3)日志中的内存快照
  • 当报错进程内存超限或可用内存不足时,BE日志(be.INFO)会打印Memory Tracker Summary,包含所有核心Tracker的内存占用,方便事后排查。

4. 常见问题:Tracker统计缺失怎么办?

  • 现象process resident memory - sum of all trackers 差值过大(超过30%),或Orphan Tracker值过大;
  • 原因:部分内存未通过Allocator分配(如RPC、部分元数据),或存在内存泄漏;
  • 排查步骤
    • 将 be.conf 中 JEMALLOC_CONF 的 prof_active:false 修改为 prof_active:true 并重启 Doris BE。
    • 执行 curl http://be_host:8040/jeheap/dump 后会在 ${DORIS_HOME}/log 目录看到生成的 profile 文件。
    • 执行 jeprof --dot {DORIS_HOME}/lib/doris_be {DORIS_HOME}/log/profile_file 后将终端输出的文本贴到在线dot绘图网站,生成内存分配图。
    1. 2.1.5前版本先检查Segment Cache(可能统计不准),尝试关闭后测试;
    2. 查看doris_column_reader_num指标,若数值过大,则可能是 Segment Cache 的内存占用,如果又在 Heap Profile 内存占比大的调用栈中看到 Segment,ColumnReader 字段,则基本可以确认是 Segment Cache 占用了大量内存。;
    3. 用Jemalloc Heap Profile生成内存快照,分析未被跟踪的内存去向。

三、内存控制策略

Doris通过“统一分配+智能仲裁+自动回收”三大机制,确保内存使用可控,核心是“在性能和稳定性之间找平衡”。

1. 内存分配:三大核心数据结构

Allocator作为统一分配接口,底层依赖三个关键数据结构管理内存,优化分配效率:

  • Arena(内存池):维护多个Chunk(内存块),减少系统调用,用于序列化数据、Hash表Key存储等,Chunk大小动态增长(最大128M);
  • HashTable:用于Join、聚合、窗口函数,支持并行扩容,大内存场景(>2G)扩容因子从50%提升到75%,减少内存浪费;
  • PODArray(动态数组):存储字符串等列数据,不初始化元素,析构时直接释放整块内存,效率更高。

2. 内存复用:减少浪费的“关键技巧”

Doris在执行层设计了大量内存复用机制,避免重复申请释放:

  • 数据块(Block)复用:查询执行时预分配一批Free Block,扫描数据时循环使用,任务结束后统一释放;
  • Shuffle双Block交替:Sender端用两个Block交替接收和传输数据,避免频繁创建Block;
  • MemTable预聚合:导入聚合表时,MemTable达到阈值后预聚合收缩,继续接收新数据,减少内存占用。

3. 内存不足时的自动GC

Doris有专门的GC线程,定时监控内存状态,当内存超限或系统可用内存不足时,触发自动回收,分为两个级别:

(1)Minor GC
  • 触发条件:BE内存超过SoftMemLimit(默认系统内存81%),或系统可用内存低于Warning水位线(64G机器约6.4G);
  • 执行动作
    1. 暂停查询的内存分配;
    2. 导入强制刷盘(释放MemTable内存);
    3. 释放部分缓存(过期Segment Cache、数据页缓存);
    4. 若释放不足10%内存,取消内存超发比例大的查询;
    5. 恢复查询执行。
(2)Full GC
  • 触发条件:BE内存超过MemLimit(默认系统内存90%),或系统可用内存低于Low水位线(64G机器约3.2G);
  • 执行动作
    1. 暂停查询和导入;
    2. 导入强制刷盘并暂停;
    3. 释放全部数据页缓存和大部分全局缓存;
    4. 取消内存占用大的查询和导入,直到释放20%内存;
    5. 恢复任务执行。

4. 核心内存参数

参数

默认值

作用

mem_limit

90%

BE进程内存上限(占系统物理内存比例)

soft_mem_limit_frac

0.9

SoftMemLimit = mem_limit * 此值(默认81%)

max_sys_mem_available_low_water_mark_bytes

-1

低水位线(默认自动计算,64G机器约3.2G)

write_buffer_size

100M

单个MemTable的内存上限(导入刷盘阈值)

load_process_max_memory_limit_percent

50%

导入内存占BE总内存的比例上限

五、Doris内存管理的核心逻辑

Doris的内存管理本质是“精细化管控+智能化回收”:通过Memory Tracker实现全链路监控,用Allocator统一分配内存,靠GC机制在内存不足时自动自救,既保证查询性能(内存复用、缓存加速),又避免OOM风险。

对运维来说,关键是抓住三个核心:

  1. 会工具:MemTracker(实时监控)、Bvar(历史趋势)、日志快照(事后排查);
  2. 懂参数:mem_limit(进程上限)、exec_mem_limit(导入的内存限制)、write_buffer_size(刷写前缓冲区的大小);
  3. 明场景:不同任务(查询/导入/Compaction)的内存特点不同,针对性优化。

如果你的集群正面临内存问题,不妨按照上面的步骤一步步排查,大部分问题都能定位到根源。如果需要更精准的分析,也可以分享你的MemTracker截图和日志,一起探讨解决方案~

数据极客圈子介绍

圈子1

Apache Doris社区是目前国内最活跃的开源社区(之一)。Apache Doris(Apache 顶级项目) 聚集了世界全国各地的用户与开发人员,致力于打造一个内容完整、持续成长的互联网开发者学习生态圈!

如果您对Apache Doris感兴趣,可以通过以下入口访问官方网站、社区论坛、GitHub和dev邮件组:

💡官网文档:https://doris.apache.org

💡社区论坛:https://ask.selectdb.com

💡GitHub:https://github.com/apache/doris

💡dev邮件组:dev@doris.apache.org

可以加作者微信(Faith_xzc)直接进Doris官方社区群

圈子2

PowerData是由一群数据从业人员,因为热爱凝聚在一起,以开源精神为基础,组成的数据开源社区。

社区群内会定期组织模拟面试、线上分享、行业研讨、线下Meetup、城市聚会、求职内推等活动,同时在社区群内你可以进行技术讨论、问题请教,结识更多志同道合的数据朋友。

社区整理了一份每日一题汇总及社区分享PPT,内容涵盖大数据组件、编程语言、数据结构与算法、企业真实面试题等各个领域,帮助您提升自我,成功上岸。

可以加作者微信(Faith_xzc)直接进PowrData官方社区群

叮咚✨ “数据极客圈” 向你敞开大门,走对圈子跟对人,行业大咖 “唠” 数据,实用锦囊天天有,就缺你咯!快快关注数据极客圈,共同成长!

点击上方公众号关注我们

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据极客圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Doris BE的内存结构到底是什么样?
    • 1. 整体内存结构拆解
    • 2. 关键内存模块说明
  • 二、内存跟踪器(Memory Tracker)
    • 1. 怎么做到“内存使用全记录”?
    • 2. 两种核心Tracker类型
    • 3. 如何查看内存跟踪数据?
      • (1)实时内存统计(Web页面,最常用)
      • (2)历史内存趋势(Bvar页面)
      • (3)日志中的内存快照
    • 4. 常见问题:Tracker统计缺失怎么办?
  • 三、内存控制策略
    • 1. 内存分配:三大核心数据结构
    • 2. 内存复用:减少浪费的“关键技巧”
    • 3. 内存不足时的自动GC
      • (1)Minor GC
      • (2)Full GC
    • 4. 核心内存参数
  • 五、Doris内存管理的核心逻辑
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档