关于大数据:资源消耗降低-90速度提升-50解读-Apache-Doris-Compaction-最新优化与实现

48次阅读

共计 6374 个字符,预计需要花费 16 分钟才能阅读完成。

背景

LSM-Tree(Log Structured-Merge Tree)是数据库中最为常见的存储构造之一,其核心思想在于充分发挥磁盘间断读写的性能劣势、以短时间的内存与 IO 的开销换取最大的写入性能,数据以 Append-only 的形式写入 Memtable、达到阈值后解冻 Memtable 并 Flush 为磁盘文件、再联合 Compaction 机制将多个小文件进行多路归并排序造成新的文件,最终实现数据的高效写入。

Apache Doris 的存储模型也是采纳相似的 LSM-Tree 数据模型。用户不同批次导入的数据会先写入内存构造,随后在磁盘上造成一个个的 Rowset 文件,每个 Rowset 文件对应一次数据导入版本。而 Doris 的 Compaction 则是负责将这些 Rowset 文件进行合并,将多个 Rowset 小文件合并成一个 Rowset 大文件。

在此过程中 Compaction 施展着以下作用:

  • 每个 Rowset 内的数据是按主键有序的,但 Rowset 与 Rowset 之间数据是无序的,Compaction 会将多个 Rowset 的数据从无序变为有序,晋升数据在读取时的效率;
  • 数据以 Append-only 的形式进行写入,因而 Delete、Update 等操作都是标记写入,Compaction 会将标记的数据进行真正删除或更新,防止数据在读取时进行额定的扫描及过滤;
  • 在 Aggregate 模型上,Compaction 还能够将不同 Rowset 中雷同 Key 的数据进行预聚合,缩小数据读取时的聚合计算,进一步晋升读取效率。

问题与思考

只管 Compaction 在写入和查问性能方面施展着非常要害的作用,但 Compaction 工作执行期间的写放大问题以及随之而来的磁盘 I/O 和 CPU 资源开销,也为零碎稳定性和性能的充分发挥带来了新的挑战。

在用户实在场景中,往往面临着各式各样的数据写入需要,并行写入工作的多少、单次提交数据量的大小、提交频次的高下等,各种场景可能须要搭配不同的 Compaction 策略。而不合理的 Compaction 策略则会带来一系列问题:

  • Compaction 任务调度不及时导致大量版本沉积、Compaction Score 过高,最终导致写入失败(-235/-238);
  • Compaction 工作执行速度慢,CPU 耗费高;
  • Compaction 工作内存占用高,影响查问性能甚至导致 BE OOM;

与此同时,只管 Apache Doris 提供了多个参数供用户进行调整,但相干参数泛滥且语义简单,用户了解老本过高,也为人工调优减少了难度。

基于以上问题,从 Apache Doris 1.1.0 版本开始,咱们减少了被动触发式 QuickCompaction、引入了 Cumulative Compaction 工作的隔离调度并减少了小文件合并的梯度合并策略,对高并发写入和数据实时可见等场景都进行了针对性优化。

而在 Apache Doris 最新的 1.2.2 版本和行将公布的 2.0.0 版本中,咱们对系统 Compaction 能力进行了全方位加强,在触发策略、执行 形式 工程实现 以及参数配置上都进行了大幅优化, 在实时性、易用性与稳定性失去晋升的同时更是彻底解决了查问效率问题

Compaction 优化与实现

在设计和评估 Compaction 策略之时,咱们须要综合衡量 Compaction 的任务模型和用户实在应用场景,外围优化思路蕴含以下几点:

  • 实时性和高效性。Compaction 工作触发策略的实时性和工作执行形式的高效性间接影响到了查问执行的速度,版本沉积将导致 Compaction Score 过高且触发自我爱护机制,导致后续数据写入失败。
  • 稳定性。Compaction 工作对系统资源的耗费可控,不会因 Compaction 工作带来过多的内存与 CPU 开销造成零碎不稳固。
  • 易用性。因为 Compaction 工作波及调度、策略、执行多个逻辑单元,局部非凡场景须要对 Compaction 进行调优,因而须要 Compaction 波及的参数可能精简明了,领导用户疾速进行场景化的调优。

具体在实现过程中,蕴含了触发策略、执行形式、工程实现以及参数配置这四个方面的优化。

Compaction 触发策略

调度策略决定着 Compaction 工作的实时性。在 Apache Doris 2.0.0 版本中,咱们在被动触发和被动扫描这两种形式的根底之上引入了 Tablet 休眠机制,力求在各类场景均能以最低的耗费保障最高的实时性。

被动触发

被动触发是一种最为实时的形式,在数据导入的阶段就查看 Tablet 是否有待触发的 Compaction 工作,这样的形式保障了 Compaction 工作与数据导入工作同步进行,在新版本产生的同时就可能立刻触发数据合并,可能让 Tablet 版本数维持在一个十分稳固的状态。被动触发次要针对增量数据的 Compaction (Cumulative Compaction),存量数据则依赖被动扫描实现。

被动扫描

与被动触发不同,被动扫描次要负责触发大数据量的 Base Compaction 工作。Doris 通过启动一个后盾线程,对该节点上所有的 Tablet 元数据进行扫描,依据 Tablet Compaction 工作的紧迫水平进行打分,抉择得分最高的 Tablet 触发 Compaction 工作。这样的全局扫描模式可能选出最紧急的 Tablet 进行 Compaction,但个别其执行周期较长,所以须要配合被动触发策略施行。

休眠机制

频繁的元信息扫描会导致大量的 CPU 资源节约。因而在 Doris 2.0.0 版本中咱们引入了 Tablet 休眠机制,来升高元数据扫描带来的 CPU 开销。通过对长时间没有 Compaction 工作的 Tablet 设置休眠工夫,一段时间内不再对该 Tablet 进行扫描,可能大幅升高工作扫描的压力。同时如果休眠的 Tablet 有突发的导入,通过被动触发的形式也能顾唤醒 Compaction 工作,不会对工作的实时性有任何影响。

通过上述的被动扫描 + 被动触发 + 休眠机制,应用最小的资源耗费,保障了 Compaction 工作触发的实时性。

Compaction 执行形式

在 Doris 1.2.2 版本中中,咱们引入了两种全新的 Compaction 执行形式:

  • Vertical Compaction,用以彻底解决 Compaction 的内存问题以及大宽表场景下的数据合并;
  • Segment Compaction,用以彻底解决上传过程中的 Segment 文件过多问题;

而在行将公布的 Doris 2.0.0 版本,咱们引入了 Ordered Data Compaction 以晋升时序数据场景的数据合并能力。

Vertical Compaction

在之前的版本中,Compaction 通常采纳行的形式进行,每次合并的根本单元为整行数据。因为存储引擎采纳列式存储,行 Compaction 的形式对数据读取极其不敌对,每次 Compaction 都须要加载所有列的数据,内存耗费极大,而这样的形式在宽表场景下也将带来内存的极大耗费。

针对上述问题,咱们在 Doris 1.2.2 版本中实现了对列式存储更加敌对的 Vertical Compaction,具体执行流程如下图:

整体分为如下几个步骤:

  1. 切分列组。将输出 Rowset 依照列进行切分,所有的 Key 列一组、Value 列按 N 个一组,切分成多个 Column Group;
  2. Key 列合并。Key 列的程序就是最终数据的程序,多个 Rowset 的 Key 列采纳堆排序进行合并,产生最终有序的 Key 列数据。在产生 Key 列数据的同时,会同时产生用于标记全局序 RowSources。
  3. Value 列的合并。逐个合并 Column Group 中的 Value 列,以 Key 列合并时产生的 RowSources 为根据对数据进行排序。
  4. 数据写入。数据按列写入,造成最终的 Rowset 文件。

因为采纳了按列组的形式进行数据合并,Vertical Compaction 人造与列式存储更加贴合,应用列组的形式进行数据合并,单次合并只须要加载局部列的数据,因而可能极大缩小合并过程中的内存占用。在理论测试中,Vertical C ompaction 应用内存仅为原有 Compaction 算法的 1/10,同时 Compaction 速率晋升 15%。

Vertical Compaction 在 1.2.2 版本中默认敞开状态,须要在 BE 配置项中设置 enable_vertical_compaction=true 开启该性能。

相干 PR:https://github.com/apache/dor…

Segment Compaction

在数据导入阶段,Doris 会在内存中积攒数据,达到肯定大小时 Flush 到磁盘造成一个个的 Segment 文件。大批量数据导入时会造成大量的 Segment 文件进而影响后续查问性能,基于此 Doris 对一次导入的 Segment 文件数量做了限度。当用户导入大量数据时,可能会触发这个限度,此时零碎将反馈 -238 (TOO_MANY_SEGMENTS) 同时终止对应的导入工作。Segment compaction 容许咱们在导入数据的同时进行数据的实时合并,以无效管制 Segment 文件的数量,减少零碎所能承载的导入数据量,同时优化后续查问效率。具体流程如下所示:

在新增的 Segment 数量超过肯定阈值(例如 10)时即触发该工作执行,由专门的合并线程异步执行。通过将每组 10 个 Segment 合并成一个新的 Segment 并删除旧 Segment,导入实现后的理论 Segment 文件数量将降落 10 倍。Segment Compaction 会随同导入的过程并行执行,在大数据量导入的场景下,可能在不显著减少导入工夫的前提下大幅升高文件个数,晋升查问效率。

Segment Compaction 在 1.2.2 版本中默认敞开状态,须要在 BE 配置项中设置 enable_segcompaction = true 开启该性能。

相干 PR : https://github.com/apache/dor…

Ordered Data Compaction

随着越来越多用户在时序数据分析场景利用 Apache Doris,咱们在 Apache Doris 2.0.0 版本实现了全新的 Ordered Data Compaction。

时序数据分析场景个别具备如下特点:数据整体有序、写入速率恒定、单次导入文件大小绝对均匀。针对如上特点,Ordered Data Compaction 无需遍历数据,跳过了传统 Compaction 简单的读数据、排序、聚合、输入的流程,通过文件 Link 的形式间接操作底层文件生成 Compaction 的指标文件。

Ordered Data Compaction 执行流程蕴含如下几个要害阶段:

  1. 数据上传阶段。记录 Rowset 文件的 Min/Max Key,用于后续合并 Rowset 数据交叉性的判断;
  2. 数据查看阶段。查看参加 Compaction 的 Rowset 文件的有序性与参差度,次要通过数据上传阶段的 Min /Max Key 以及文件大小进行判断。
  3. 数据合并阶段。将输出 Rowset 的文件硬链接到新 Rowset,而后构建新 Rowset 的元数据(包含行数,Size,Min/Max Key 等)。

能够看到上述阶段与传统的 Compaction 流程齐全不一样,只须要文件的 Link 以及内存元信息的构建,极其简洁、轻量。针对时序场景设计的 Ordered Data Compaction 可能在毫秒级别实现大规模的 Compaction 工作,其内存耗费简直为 0,对用户极其敌对。**

Ordered Data Compaction 在 2.0.0 版本中默认开启状态,如需调整在 BE 配置项中批改 enable_segcompaction 即可。

应用形式:BE 配置 enable_ordered_data_compaction=true

Compaction 工程实现

除了上述在触发策略和 Compaction 算法上的优化之外,Apache Doris 2.0.0 版本还对 Compaction 的工程实现进行了大量细节上的优化,包含数据零拷贝、按需加载、Idle Schedule 等。

数据零拷贝

Doris 采纳分层的数据存储模型,数据在 BE 上能够分为如下几层:Tablet -> Rowset -> Segment -> Column -> Page,数据须要通过逐层解决。因为 Compaction 每次参加的数据量大,数据在各层之间的流转会带来大量的 CPU 耗费,在新版本中咱们设计并实现了全流程无拷贝的 Compaction 逻辑,Block 从文件加载到内存中后,后续无序再进行拷贝,各个组件的应用都通过一个 BlockView 的数据结构实现,这样彻底的解决了数据逐层拷贝的问题,将 Compaction 的效率再次晋升了 5%。

按需加载

Compaction 的逻辑实质上是要将多个无序的 Rowset 合并成一个有序的 Rowset,在大部分场景中,Rowset 内或者 Rowset 间的数据并不是齐全无序的,能够充分利用部分有序性进行数据合并,在同一时间仅需加载有序文件中的第一个,这样随着合并的进行再逐步加载。利用数据的部分有序性按需加载,可能极大缩小数据合并过程中的内存耗费。

Idle schedule

在理论运行过程中,因为局部 Compaction 工作占用资源多、耗时长,经常出现因为 Compaction 工作影响查问性能的 Case。这类 Compaction 工作个别存在于 Base compaction 中,具备数据量大、执行工夫长、版本合并少的特点,对工作执行的实时性要求不高。在新版本中,针对此类工作开启了线程 Idle Schedule 个性,升高此类工作的执行优先级,防止 Compaction 工作造成线上查问的性能稳定。

易用性

在 Compaction 的易用性方面,Doris 2.0.0 版本进行了系统性优化。联合长期以来 Compaction 调优的一些教训数据,默认配置了一套通用环境下体现最优的参数,同时大幅精简了 Compaction 相干参数及语义,不便用户在非凡场景下的 Compaction 调优。

总结布局

通过上述一系列的优化形式,全新版本在 Compaction 过程中获得了极为显著的改良成果。在 ClickBench 性能测试中,新版本 Compaction 执行速度 达到 30w row/s,相较于旧版本 晋升 50 % ;资源耗费降幅微小, 内存占用仅为原先的 10%。高并发数据导入场景下,Compaction Score 始终保持在 50 左右,且零碎体现极为安稳。同时在时序数据场景中,Compaction 写放大系数升高 90%,极大晋升了可承载的写入吞吐量。

后续咱们仍将进一步摸索迭代优化的空间,次要的工作方向将聚焦在自动化、可观测性以及执行效率等方向上:

  1. 自动化调优。针对不同的用户场景,无需人工干预,零碎反对进行自动化的 Compaction 调优;
  2. 可观测性加强。收集统计 Compaction 工作的各项指标,用于领导自动化以及手动调优;
  3. 并行 Vertical Compaction。通过 Value 列并发执行,进一步晋升 Vertical Compaction 效率。

以上方向的工作都已处于布局或开发中,如果有小伙伴对以上方向感兴趣,也欢送参加到社区中的开发来。期待有更多人参加到 Apache Doris 社区的建设中,欢送你的退出!

作者介绍:

一休,Apache Doris contributor,SelectDB 资深研发工程师

张正宇,Apache Doris contributor,SelectDB 资深研发工程师

# 相干链接:

SelectDB 官网

https://selectdb.com 

Apache Doris 官网

http://doris.apache.org

Apache Doris Github

https://github.com/apache/doris

正文完
 0