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

深入理解 Doris Compaction:提升查询性能的幕后功臣

在这里插入图片描述
在 Doris 的数据存储与查询体系里,Compaction 是保障查询效率、优化存储结构的关键机制。如果你好奇 Doris 如何在高频写入后仍能高效响应查询,或是想解决数据版本膨胀带来的性能问题,这篇关于 Compaction 的深度解析值得收藏 👇

一、为什么需要 Compaction?

Doris 采用类 LSM - Tree 的存储结构,每次数据导入会生成新的 Rowset(可理解为数据版本片段 ),每个rowset由0到n个sgement组成。segment实际对应这个磁盘上的一个文件。单个sgement文件是有序的。

存储文件目录结构

随着导入操作增多,Rowset 数量不断累积,会引发两大核心问题:

(一)查询效率下降

查询时,Doris 需要对多个 Rowset 执行 “多路归并” 操作来整合结果。Rowset 数量越多,归并的路数就越多,查询耗时呈几何级增长。例如,若一个查询需要合并 10 个 Rowset,归并过程就像同时梳理 10 条杂乱的线,难度和耗时远大于合并 2 - 3 个 Rowset。

(二)存储成本上升

大量零散的 Rowset 会占用更多磁盘空间,还可能存储重叠和无效数据。比如多次导入同一范围的数据,会生成多个有重叠的 Rowset,不仅浪费存储,还会让查询时的归并逻辑更复杂。

Compaction 的核心目标

  • 减少查询归并成本:将多个小 Rowset 合并为大 Rowset,降低查询时的合并路数。
  • 消除无效数据:将标记删除(Delete)、更新(Update)的数据真正清理,避免查询时的无效扫描。
  • 优化存储:在 Aggregate 模型中预聚合相同 Key 的数据,在 Unique 模型中保留最新版本,进一步提升查询效率。

compaction的粒度是tablet,下图是一个tablet compaction过程的示意图

tablet 的 compaction过程

二、Compaction 关键概念解析

1. Compaction Score:优先级调度指标

Compaction Score 是 Doris 判断 Tablet 做Compaction优先级的核心指标,值越高,优先级越高

(一)本质

反映查询时 Rowset 参与 “多路归并” 的路数。路数越多,查询效率越低,越需要优先compaction。

(二)计算逻辑

遍历 Tablet 的 Rowset,根据其数据重叠情况统计归并路数:

若某 Tablet 的 Rowset 分布如下:

"rowsets": ["[0-100] 3 DATA NONOVERLAPPING ...", // 无重叠,归并占 1 路 "[101-101] 2 DATA OVERLAPPING ...",  // 有重叠,归并占 2 路 "[102-102] 1 DATA NONOVERLAPPING ..." // 无重叠,归并占 1 路 
]
  • 无重叠 Rowset:如 [0-100] 范围的 Rowset 由 3 个Segment 组成,但是没有但是没有overlap,查询归并时仅占 1 路;

  • 有重叠 Rowset:如 [101-101] 范围的 Rowset 由 2 个Segment 组成,但是有但是有overlap,查询归并时占 2 路。

则 Compaction Score = 1(第一行) + 2(第二行) + 1(第三行) = 4

2. Base & Cumulative Compaction:分层合并策略

为了平衡 “压缩效率” 和 “数据合并成本”,Doris 采用分层压缩思路:

(1)Cumulative Compaction
  • 作用:优先合并新写入的小 Rowset,避免直接与大 Rowset 合并导致效率低下。新导入的零散数据(如实时写入的小批次数据 ),先通过Cumulative Compaction逐步 “攒大”,减少后续 Base Compaction 的压力。
(2)Base Compaction
  • 作用:当Cumulative Rowset 合并到一定规模后,再与 ** 历史大 Rowset(Base Rowset)** 合并,最终形成更紧凑的大 Rowset,彻底优化查询路数。
(3)Cumulative Point:分层 “临界点”

用来划分 “Cumulative Rowset” 和 “Base Rowset” 的边界。比如某 Tablet 的 Cumulative Point 为 293,意味着:

compaction图

  • Rowset 范围 293+ 做的是 Cumulative Compaction;

  • Rowset 范围 0-292 做的是 Base Compaction。

三、Compaction 工作流程:生产者 - 消费者模式

Doris 的 Compaction 流程遵循生产者 - 消费者模型,可拆解为 4 大核心步骤,每个步骤都蕴含精细的设计逻辑:

1. 扫描与优先级计算(生产者线程)

BE 的 Compaction 生产者线程定时(可配置扫描间隔)扫描所有 Tablet,执行以下操作:

(一)计算 Compaction Score

遍历 Tablet 的 Rowset,统计每个 Rowset 在查询时的归并路数,累加得到 Compaction Score,确定compaction优先级。

(二)分层任务调度

Doris 通过轮询策略平衡 Base 和 Cumulative Compaction 的资源占用:

  • 默认每 10 轮扫描选 1 次 Base Compaction 任务(处理历史大 Rowset 合并 );

  • 其余 9 轮选 Cumulative Compaction 任务(快速合并新写入的小 Rowset )。

    这样设计的原因是:Base Compaction 通常涉及更大数据量,资源消耗更高,需控制执行频率;而 Cumulative Compaction 处理小数据,可高频执行以快速优化查询。

2. 并发控制:避免磁盘过载

磁盘的 IO 带宽和处理能力是有限的,若同时执行过多 Compaction 任务,会导致磁盘性能雪崩(比如磁盘 IO 利用率瞬间 100%,其他读写操作阻塞 )。因此,Doris 会:

(一)检查当前任务数

查询磁盘当前运行的 Compaction 任务数,与配置的compaction的线程数对比。

(二)动态跳过机制

若任务数已达阈值,跳过该 Tablet,等待下一轮扫描;若未超限,允许任务继续,确保磁盘资源合理利用。

3. Rowset 筛选策略

并非所有 Rowset 都会被选中压缩,筛选逻辑聚焦两点,这直接影响 Compaction 的效率和效果:

(一)连续性优先

优先选择连续的 Rowset(如按时间或数据范围连续 ),因为零散的 Rowset 合并后,能减少查询时归并的 “碎片问题”。例如,连续的 Rowset 合并后,查询时可一次性归并,而零散 Rowset 可能需要多次跳转磁盘读取。

(二)数据量均衡

避免合并 “大小差距极大” 的 Rowset。在多路归并排序中,若 Rowset 数据量差距过大,归并时小 Rowset 会快速处理完,大 Rowset 仍需大量时间,整体效率会断崖式下跌。因此,筛选时会优先选数据量相近的 Rowset,保证归并过程的高效性。

4. 任务分发:分线程池执行

为了隔离 Base Compaction ·和 Cumulative Compaction 的资源,Doris 设计了两个独立线程池。

Base compaction线程池和cumulative compaction线程池分别从队列中取出compaction task任务后,执行多路归并排序:将多个 Rowset 的数据按顺序合并,生成一个新的大 Rowset。

Compaction工作流程图

四、总结:Compaction 是效率与成本的平衡艺术

理解 Compaction 的逻辑后,再面对 “查询变慢”“存储膨胀” 等问题时,就能从 “数据版本管理” 的视角切入,精准定位与解决。下次遇到 Doris 性能瓶颈,不妨先看看 Compaction 是否在 “默默加班”,是否因配置或数据模式问题导致其 “有心无力”~

如果觉得内容有帮助,欢迎点赞、在看、分享,让更多人了解 Doris 性能优化的幕后逻辑~ 有疑问或补充,也可在评论区交流,一起深入了解 Doris 技术细节 🌱

http://www.dtcms.com/a/305713.html

相关文章:

  • 深入剖析 Spark Shuffle 机制:从原理到实战优化
  • 【CVPR2025】FlowRAM:用区域感知与流匹配加速高精度机器人操作策略学习
  • linux 执行sh脚本,提示$‘\r‘: command not found
  • (8)(8.6) H-流量(光学流量和距离传感器模块)
  • 自动化测试实战—petstore实战
  • SparkSQL_数组排序函数 array_sort用法详解
  • 快秀录屏记录高光时刻,分享游戏激情
  • 少林寺用什么数据库?
  • 传统ERP迁移SAP Cloud ERP现代化升级:Kyano Crossway一种更智能的迁移方案
  • 【C++详解】深入解析多态 虚函数、虚函数重写、纯虚函数和抽象类、多态原理、重载/重写/隐藏的对⽐
  • Python字典高级映射:键到多值映射的工程实践
  • 智能Agent场景实战指南 Day 26:Agent评估与性能优化
  • SAP ABAP锁机制程序锁
  • LeetCode热题100--148. 排序链表--中等
  • Linux730 tr:-d /-s;sort:-r,-n,-R,-o,-t,-k,-u;bash;cut:-d,-c;tee -a;uniq -c -i
  • AD域设计与管理-批量创建域用户
  • 大语言模型API付费?
  • 【Qt】QTime::toString(“hh:mm:ss.zzz“) 显示乱码的原因与解决方案
  • MySQL EXPLAIN详解与高效调优方法
  • Spring-rabbit使用实战四
  • ConcurrentHashMapRedis实现二级缓存
  • 力扣219:存在重复元素Ⅱ
  • Android Animation Transitions:打造流畅的用户体验
  • 打造高效、安全的期货资管交易平台:开发流程与关键要素解析
  • VS Code中如何关闭Github Copilot
  • 为什么网站需要高防IP?高防IP的优势是什么?
  • android-PMS-创建新用户流程
  • CSS3 圆角
  • 【鸿蒙应用开发中,`signingConfigs` 用于配置应用签名的关键信息说明】
  • Vue.js 与后端技术结合开发指南