当前位置: 首页 > news >正文

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


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

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

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

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

1. 整体内存结构拆解

服务器物理内存 ├─ 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、部分元数据),或存在内存泄漏;

  • 排查步骤

    1. 2.1.5前版本先检查Segment Cache(可能统计不准),尝试关闭后测试;

    2. 查看doris_column_reader_num指标,若数值过大,则可能是Segment Cache的内存占用,如果又在Heap Profile内存占比大的调用栈中看到 Segment,ColumnReader字段,则基本可以确认是Segment Cache占用了大量内存。;

    3. 用Jemalloc Heap Profile生成内存快照,分析未被跟踪的内存去向。

    • 将 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绘图网站,生成内存分配图。

三、内存控制策略

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_limit90%BE进程内存上限(占系统物理内存比例)
soft_mem_limit_frac0.9SoftMemLimit = mem_limit * 此值(默认81%)
max_sys_mem_available_low_water_mark_bytes-1低水位线(默认自动计算,64G机器约3.2G)
write_buffer_size100M单个MemTable的内存上限(导入刷盘阈值)
load_process_max_memory_limit_percent50%导入内存占BE总内存的比例上限

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

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

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

  1. 会用工具:MemTracker(实时监控)、Bvar(历史趋势)、日志快照(事后排查);

  2. 懂参数:mem_limit(进程上限)、exec_mem_limit(导入的内存限制)、write_buffer_size(刷写前缓冲区的大小);

  3. 明场景:不同任务(查询/导入/Compaction)的内存特点不同,针对性优化。

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

http://www.jsqmd.com/news/73948/

相关文章:

  • Wan2.2-T2V-A14B生成角色动作自然流畅的关键机制分析
  • 53、常见Shell工具资源与术语详解
  • TCR型SVC仿真实战手记
  • 从零构建RAG知识库系统:完整实现方案与优化技巧(建议收藏)
  • 口碑好的质量流量计供应商
  • Python高效实现Excel与TXT文本文件数据转换指南
  • 在数字画布上建立学习秩序:四川涂色教育科技有限公司的插画教学体系
  • 基于单片机打铃(3组上下课,LCD1602,24C02)系统Proteus仿真(含全部资料)
  • 【微实验】聚类还在用kmeans?来试试高斯混合模型(附MATLAB代码)
  • B站视频下载利器DownKyi:专业用户的终极操作指南
  • Redis 字符串类型完全指南:从原理到实战应用
  • 终极指南:如何用Universal x86 Tuning Utility释放Intel CPU电压调节潜力
  • Keye-VL-1.5:重新定义多模态视频理解的技术突破
  • DeepSeek + Tushare 王炸组合!我开源了一款 Fin-Agent,让 AI 帮你科学 “搞钱”!
  • 你还在用轮询?C#实时物联网通信的7种高级模式(含源码级示例)
  • 计算机Java毕设实战-基于springboot高校奖助学金系统课程成绩、体育成绩、加分申请、综合成绩、奖学金申请【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 计算机Java毕设实战-基于springboot高校教室资源管理系统的设计与实现基于java springboot+vue高校教室资源管理系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 2025年常州宠物医院权威推荐榜:专业诊疗与暖心服务口碑之选,常州宠物手术医院深度解析 - 品牌企业推荐师(官方)
  • B站视频转文字终极指南:一键提取视频内容神器
  • 2025 年 12 月智能升降家居系统厂家推荐榜:橱柜拉篮/化妆台/挂衣杆/柜门拉手,匠心智造与空间美学革新方案 - 品牌企业推荐师(官方)
  • 飞牛fnOS使用DNS验证方式,用acme自动签发SSL证书
  • 【2025最新】小白如何自学网络安全,零基础入门到精通,看这一篇就够了!
  • 传统SEO优化为何在技术层面需要3至6个月的较长周期?
  • 基于大数据的共享单车用户行为数据可视化分析系统
  • C语言的学习
  • [Error] Refinement limit exceeded for auto-refinement.
  • Wan2.2-T2V-A14B在AI营养师推荐食谱中的烹饪过程可视化
  • 原来让AI拥有记忆这么简单?手把手教你实现Agent长短期记忆,附实战案例
  • Bili2text视频转文字终极指南:解放你的双手与时间
  • 突破性MD-ML融合框架:引领离子液体基凝胶电解质设计新范式