共计 3475 个字符,预计需要花费 9 分钟才能阅读完成。
数据导入吞吐是 OLAP 零碎性能的重要衡量标准之一,高效的数据导入能力可能减速数据实时处理和剖析的效率。随着 Apache Doris 用户规模的不断扩大,越来越多用户对数据导入提出更高的要求,这也为 Apache Doris 的数据导入能力带来了更大的挑战。
为提供疾速的数据写入反对,Apache Doris 存储引擎采纳了相似 LSM Tree 构造。在进行数据导入时,数据会先写入 Tablet 对应的 MemTable 中,MemTable 采纳 SkipList 的数据结构。当 MemTable 写满之后,会将其中的数据刷写(Flush)到磁盘。数据从 MemTable 刷写到磁盘的过程分为两个阶段,第一阶段是将 MemTable 中的行存构造在内存中转换为列存构造,并为每一列生成对应的索引构造;第二阶段是将转换后的列存构造写入磁盘,生成 Segment 文件。
具体而言,Apache Doris 在导入流程中会把 BE 模块分为上游和上游,其中上游 BE 对数据的解决分为 Scan 和 Sink 两个步骤:首先 Scan 过程对原始数据进行解析,而后 Sink 过程将数据组织并通过 RPC 分发给上游 BE。当上游 BE 接收数据后,首先在内存构造 MemTable 中进行数据攒批,对数据排序、聚合,并最终下刷成数据文件(也称 Segment 文件)到硬盘上来进行长久化存储。
而咱们在理论的数据导入过程中,可能会呈现以下问题:
- 因上游 BE 跟上游 BE 之间的 RPC 采纳 Ping-Pong 的模式,即上游 BE 一个申请解决实现并回复到上游 BE 后,上游 BE 才会发送下一个申请。如果上游 BE 在 MemTable 的处理过程中耗费了较长的工夫,那么上游 BE 将会期待 RPC 返回的工夫也会变长,这就会影响到数据传输的效率。
- 当对多正本的表导入数据时,须要在每个正本上反复执行 MemTable 的处理过程。然而,这种形式使每个正本所在节点都会耗费肯定的内存和 CPU 资源,不仅如此,简短的解决流程也会影响执行效率。
为解决以上问题,咱们在刚刚公布不久 Apache Doris 2.0 版本中(https://github.com/apache/doris/tree/2.0.1-rc04),对导入过程中 MemTable 的攒批、排序和落盘等流程进行优化,进步了上下游之间数据传输的效率。此外咱们在新版本中还提供 “单正本导入” 的数据散发模式,当面对多正本数据导入时,无需在多个 BE 上反复进行 MemTable 工作,无效晋升集群计算和内存资源的利用率,进而晋升导入的总吞吐量。
MemTable 优化
01 写入优化
在 Aapche Doris 过来版本中,上游 BE 在写入 MemTable 时,为了保护 Key 的程序,会实时对 SkipList 进行更新。对于 Unique Key 表或者 Aggregate Key 表来说,遇到曾经存在的 Key 时,将会调用聚合函数并进行合并。然而这两个步骤可能会耗费较多的解决工夫,从而提早 RPC 响应工夫,影响数据写入的效率。
因而咱们在 2.0 版本中对这一过程进行了优化。当上游 BE 在写入 MemTable 时,不再实时保护 MemTable 中 Key 的程序,而是将程序的保障推延到 MemTable 行将被下刷成 Segment 之前。此外,咱们采纳更高效的 pdqsort 来代替 std::sort,实现了缓存敌对的列优先排序形式,并获得了更好的排序性能。通过上述两种伎俩来保障 RPC 可能被及时响应。
02 并行下刷
在导入过程中,当上游 BE 将一个 MemTable 写入肯定大小之后,会把 MemTable 下刷为 Segment 数据文件来长久化存储数据并开释内存。为了保障前文提到的 Ping-Pong RPC 性能不受影响,MemTable 的下刷操作会被提交到一个线程池中进行异步执行。
在 Apache Doris 过来版本中,对于 Unique Key 的表来说,MemTable 下刷工作是串行执行的,起因是不同 Segment 文件之间可能存在反复 Key,串行执行能够放弃它们的先后顺序,而 Segment 序号是在下刷工作被调度执行时调配的。同时,在 Tablet 数量较少无奈提供足够的并发时,串行下刷可能会导致系统的 IO 资源无奈反复被利用。而在 Apache Doris 2.0 版本中,因为咱们将 Key 的排序和聚合操作进行了后置,除了原有的 IO 负载以外,下刷工作中还减少了 CPU 负载(即后置的排序和聚合操作)。此时若仍应用串行下刷的形式,当没有足够多 Tablet 来保障并发数时,CPU 和 IO 会交替成为瓶颈,从而导致下刷工作的吞吐量大幅升高。
为解决这个问题,咱们在下刷工作提交时就为其调配 Segment 序号,确保并行下刷后生成的 Segment 文件程序是正确的。同时,咱们还对后续 Rowset 构建流程进行了优化,使其能够解决不间断的 Segment 序号。通过以上改良,使得所有类型的表都能够并行下刷 MemTable,从而进步整体资源利用率和导入吞吐量。
03 优化成果
通过对 MemTable 的优化,面对不同的导入场景,Stream Load 的吞吐量均有不同幅度的晋升(具体比照数据可见下文)。这项优化不仅实用于 Stream Load,还对 Apache Doris 反对的其余导入形式同样无效,例如 Insert Into、Broker Load、S3 Load 等,均在不同水平晋升了导入的效率及性能。
单正本导入
01 原理和实现
在过来版本中,当面对多正本数据写入时,Apache Doris 的每个数据正本均须要在各自节点上进行排序和压缩,这样会造成较大的资源占用。为了节约 CPU 和内存资源,咱们在 Apache Doris 在 2.0 版本中提供了单正本导入的能力,该能力会从多个正本中抉择一个正本作为主正本(其余正本为从正本),且只对主正本进行计算,当主正本的数据文件都写入胜利后,告诉从正本所在节点间接接拉取主正本的数据文件,实现正本间的数据同步,当所有从正本节点拉取完后进行返回或超时返回(大多数正本胜利即返回胜利)。该能力无需一一在节点上进行解决,缩小了节点的压力,而节约的算力和内存将会用于其它工作的解决,从而晋升整体零碎的并发吞吐能力。
02 如何开启
FE 配置:
enable_single_replica_load = true
BE 配置:
enable_single_replica_load = true
环境变量(insert into)
SET experimental_enable_single_replica_insert=true;
03 优化成果
- 对于单并发导入来说,单正本数据导入能够无效升高资源耗费。单正本导入所占的内存仅为三正本导入的 1/3(单正本导入时只须要写一份内存,三正本导入时须要写三份内存)。同时从理论测试可知,单正本导入的 CPU 耗费约为三正本导入的 1/2,可无效节约 CPU 资源。
- 对于多并发导入来说,在雷同的资源耗费下,单正本导入能够显著减少工作吞吐。同时在理论测试中,同样的并发导入工作,三正本导入形式耗时 67 分钟,而单正本导入形式仅耗时 27 分钟,导入效率晋升约 2.5 倍。具体数据请参考后文。
性能比照
测试环境及配置:
- 3 个 BE (16C 64G),每个 BE 配置 3 块盘(单盘读写约 150 MB/s)
- 1 个 FE,共享其中一个 BE 的机器
原始数据应用 TPC-H SF100 生成的 Lineitem 表,存储在 FE 所在机器的一个独立的盘上(读约 150 MB/s)。
01 Stream Load(单并发)
以上述列举的单并发场景来说,Apache Doris 2.0 版本整体的导入性能比 1.2.6 版本晋升了 2-7 倍;在多正本前提下,开启新个性单正本导入,导入性能晋升了 2-8 倍。
02 INSERT INTO(多并发)
以上述列举的多并发场景来说,Apache Doris 2.0 版本整体比 1.2.6 版本有小幅晋升;开启新个性单正本导入后,对在多正本提导入性能晋升成果显著,导入速度较 1.2.6 版 晋升约 50%。
结束语
社区始终致力于晋升 Apache Doris 导入性能这一外围能力,为用户提供更佳的高效剖析体验,通过在 2.0 版本对 Memtable、单正本导入等能力进行优化,导入性能相较于之前版本曾经出现数倍晋升。将来咱们还将在 2.1 版本中继续迭代,联合 MemTable 的优化办法、单正本优化资源能效理念,以及基于 Streaming RPC 优化后的 IO 模型和精简的 IO 门路对导入性能进一步优化,同时缩小导入对查问性能的影响,为用户提供更加卓越的数据导入体验。
# 作者介绍:
陈凯杰,SelectDB 高级研发工程师
张正宇,SelectDB 资深研发工程师