乐趣区

关于云原生:云原生数据仓库TPCH第一背后的Laser引擎大揭秘

简介: 作者 | 魏闯先阿里云数据库资深技术专家

一、ADB PG 和 Laser 计算引擎的介绍

(一)ADB PG 架构

ADB PG 是一款云原生数据仓库,在保障事务 ACID 能力的前提下,次要解决云上海

量数据的实时剖析问题。它的架构与传统的 MPP 数据仓库十分相似,次要分成两层,第一层是 master 节点;第二层是 work 节点。

master 节点次要承当实时写入和事务的解决,执行打算的生成。与其余的传统的

MPP 数据仓库不同的是 ADB PG 的 master 节点反对线性扩大,能够通过多个 master

晋升整体的事务能力、实时写入吞吐能力。

work 节点次要承当两个性能,第一个性能是执行,第二个性能是存储。执行引擎采纳

的是向量化执行引擎,通过向量列式 Batch 解决,codegen 技术,以及 Fusion Scan 减速列式计算效率,在一些剖析场景性能绝对于一般的火山模型有了 3~5 倍的晋升。

同时它的存储节点不仅反对传统的行表和列表,也能够通过表面形式反对一些开源的表

构造,例如 Parquet、ORC 等开源数据结构。ADB PG 能够间接剖析保留在相似于像

OSS/HDFS 等分布式存储上的数据,缩小数据的导入,能够大幅的升高用户的应用门槛和存储老本。

(二)为什么做 Laser 计算引擎

为什么不采纳 PG 原生的计算引擎?

第一,PG 是一个传统的事务型数据库,它次要的优化大多来自于 TP 的事务优化,并没有针对海量数据的剖析计算做定制化的优化。

第二,PG 计算引擎采纳解释执行的逻辑,简单表达式采纳函数执行树的递归的调用解

释执行。如图中的例子所示,每个表达式都被翻译成一个函数并组成一个执行树。每一条的数据都通过以上的函数递归调用去实现最终的计算。它带来的问题就是在海量千万以上的数据计算场景,虚函数调用大幅影响计算的性能。

第三,PG 默认只反对行存存储引擎,并不反对列存,所以它的整个计算执行过程是逐行解决数据,并没有对列存做定制化的优化。

第四,PG 代码具备十分好的扩展性、兼容性,然而在性能上思考不多。例如说在计算过程中会波及到内存的屡次拷贝,序列化的开销比拟高。

最初,PG 采纳的是单分区单过程执行模式,无奈充分发挥古代多核 CPU 的劣势。

(三)支流 OLAP 业界计划

在开始 ADB PG 计算引擎的选型过程,咱们重点调研了以后支流的 OLAP 业界支流

计划。

次要分成两大类,第一类:向量化执行;第二类:编译执行。

第一:向量化执行的根本做法,十分相似于火山模型,次要差异来自于它采纳的是批量计算,每一批里优先列式计算。

这种模式劣势在于能够充分发挥 CPU 的流水线执行和内存的程序拜访,缩小 cache

的 miss。毛病是第一实现逻辑比较复杂。第二,它须要批量的数据,并不适宜每次计算数量较小的 OLTP 场景。第三, 它须要缓存批量数据,缓存自身带来肯定的内存开销。

第二:编译执行根本做法是应用 Codegen 技术,将所有的算子编译成函数,通过 PUSH 的模型自下而上通过数据上推实现计算。

长处一:因为每次计算的都是一行数据,执行过程能够将这一行数据保留在寄存器外面,寄存器计算代替内存计算。长处二,它通过 Codegen 技术把简单的算子编译成一个函数,所以它非常适合计算复杂性十分高的计算减速。

毛病在于,PUSH 模型管制逻辑比较复杂,同时因为采纳单条计算,无奈做到内存的程序拜访,所以它整体的 Cache miss 率比拟高。典型的代表产品有 Spark 和 Peloton。

ADB PG 综合思考这两类计划的优缺点,最终应用了向量化的计划,次要思考到 ADB PG 原生 PG 火山模型与向量化模型架构上较为靠近,革新成向量计算引擎的逻辑顺畅,革新老本较编译执行小。

(四)业界支流计算引擎比照

咱们对业界支流开源计算引擎做了比照,包含 ClickHouse、PG11、Spark、ADBPG。在执行模型上,ClickHouse 和 ADB PG、PG11 都采纳的向量执行,Spark 采纳

的是编译执行。

在内存模型上,ClickHouse 采纳的是列存、PG11 采纳行存、Spark 采纳行存、ADB PG 采纳行列混存。行列混存次要利用在相似于 join、AGG 的场景,咱们能够将多列 group by、hashtable 数据拼成一列数据,能够充分发挥程序拜访的效率。

在即时编译上,ClickHouse 采纳表达式级 LLVM、PG11 采纳表达式级 LLVM,Spark 采纳 Stage Java 技术,ADB PG 采纳算子级 LLVM 技术。算子级 LLVM 技术能够晋升算子的计算性能。

在硬件加速上,ClickHouse 和 PG11 都不反对硬件加速,Spark 反对 FPGA 减速,ADB PG 采纳 IR 技术,能够通过将 IR 翻译成对应的机器执行代码, 从而反对 GPU 减速。

二、laser 计算引擎的核心技术

Laser 计算引擎的核心技术次要包含 5 大块:

  1. 向量计算引擎
  2. 行列式内存模型
  3. JIT 减速
  4. SIMD 指令减速
  5. FUSION SCAN

第一, 向量计算引擎,传统火山模型中算子之间数据逐条交互,向量化计算引擎之间的交互的是 BATCH 数据,而后在每个算子外部,采纳的列式多条数据并行计算,这种逻辑能够充沛的施展 CPU 流水线的作用。

在内存模型上,咱们采纳的是行列混存内存模型。在算子之间数据传递的是一个 mini batch,mini batch 外部采纳的行列混存的构造。因为每列数据在内存里都是间断摆放的,所以每次计算一列都是内存的程序拜访的过程。

第三,针对简单计算,采纳 JIT 技术减速。能够利用 LLVM CodeGen 技术将简单计算过程转换成 IR 代码,而后再通过 IR 代码翻译成机器码。它的益处是能够防止类型判断,缩小虚函数的调用,从而晋升计算性能。

第四,针对一些简略场景(如:聚合场景、固定场景),利用古代 CPU 的 SIMD 指令,实现单条指令多条数据的并行执行,大幅晋升这些简略场景的效率。

第五,针对列存场景,能够通过 FUSION SCAN 去缩小无用列读取,防止无用内存的两头拷贝,从而晋升列表的计算性能。

(一)向量计算引擎

下图是一个典型的火山模型下 SUM 算子的计算过程。对于火山模型,如果总共有 n 条数据,就会调用 n 次的函数调用。左边是向量化执行过程,sum 函数接管输出参数是一个数组,而不是两个变量。整个执行过程,数据按 2048 条分批解决,每 2048 条数据调用一次 sum 函数。

从这个例子中显著能够看出:

第一,Sum 函数调用从原来的 n 次变成 n÷2048,缩小了屡次。

第二,在函数外部解决中,因为计算的数据是一个 batch,就能够充分发挥 SIMD 指令减速成果,实现单条指令多条语句的并行计算。

第三,能够针对一些算子,如 AGG 和 JOIN,能够将 AGG 和 JOIN 算子函数合并一个函数,能够进一步的缩小虚函数调用,晋升零碎性能。

因为计算过程中全副采纳数组计算,能够将计算过程中的数组应用内存池化技术治理。通过 MemoryPool 能够实现定长数据的内存的复用,防止频繁内存调配和开释,缩小整个内存的碎片。在理论的 TPC-H 的测试中,应用向量化引擎后,Q1 晋升了 120%,Q18 晋升了 190%。

(二)SIMD 指令减速

针对简略的减速,能够利用古代 CPU 的 SSE、AVX 指令,一条指令能够实现 512bit 数据计算。

咱们对 TPCH 测试中的 Lineitem 表做性能的比照测试,在应用 SIMD 当前,整体的性能从原来的 1 秒多升高到了 200 多毫秒,有了 4 倍左右的晋升。

(三)Just-in-Time 编译优化

ADB PG 不仅反对表达式级的 CodeGen,也反对算子级的 CodeGen。每个 plan 的 node 对应一个 CodeGen 单元和一个 Executor,CodeGen 单元依据 plan node 生成 code(IR),Executor 依据硬件平台抉择不同的后端,将 IR 生成对应的执行文件,并申请资源执行,最终的后果通过 master 返回给客户端。

如图所示,对于这样一个简略的表达式,where a>10 and b<5,如果采纳解释执行,总共包含三次函数调用,1、a>10;2、b<5;3、and 函数。

如果应用 LLVM GIT 编译优化,下面的三个函数就编译成三条 LLVM 指令,防止了三次函数调用的开销。

在 TPCH 测试场景中,应用 JIT 减速后整体的性能晋升了 20%~30%,并且在测试中发现, 表达式越简单,性能晋升越显著。

(四)Fusion Scan 优化

Fusion Scan 次要优化是缩小无用列的读取,并且尽量的缩小无用数据的读取和内存的拷贝。

举个例子,如果要查问满足 a 大于 3 和 b 小于 6 的 a,c*d 的值,传统做法是对数据库中的每条数据数据,做 a 大于 3 和 b 小于 6 的条件过滤并且计算对应列的值。

Fusion Scan 的做法分成两阶段:

第一阶段是对过滤列做计算。把 a 列和 b 列的所有数据读出来,对每条数据进行判断。如图所示,满足条件的只有第一行第三行,咱们把第一行第三行号保留在一个 bitset 中,同时把第一行和第三行的 a 列值也保留在 mini batch 中;

第二阶段是计算 project 列,因为满足这个条件只有第一行和第三行,咱们只须要把 c 列和 d 列的第一行和第三行的值读取进去。同时为了防止两头后果的数据拷贝,咱们间接去将 c 列和 d 列的值后果相乘,把后果保留在 mini batch 的第二列中。

在计算过程中,咱们提前将表达式编译成 IR 代码,能够防止了屡次表达式函数的递归调用。

以上过程的次要优化点在于:

第一、防止无用列表 D、E、F、G 列读取;

第二、实现了按需读取,只有满足条件的 c 列和 d 列的外面内容才进行计算和 IO,不须要读那些不满足条件的数据。同时在 c 和 d 计算过程中,间接进行 c 和 d 的读取,无需内存两头后果的拷贝。

在理论执行过程中,Fusion Scan 联合列存块 block 索引做进一步的优化。block

索引中蕴含了数据块的 min 和 max,咱们能够将 min 和 max 值和 where 条件做交加,

只有这个交加非空的话,才会去真正读取 block 的值,否则能够间接跳过这个 block。

通过 Fusion Scan 的技术,在列存的场景 Scan 算子整体的性能有 3 倍以上的晋升。

(五)算子实现 -HashJoin

HashJoin 的向量化执行引擎,算法采纳 Hybrid Hash Join,HashTable 采纳凋谢链表数据结构。

HashJoin 的实现过程,次要包含:

  1. 把左表 probe 列的值取出来计算它的 Hash 值。
  2. Hashcode 的值去模 entry 个数,获取对应的行号。
  3. 对应行号里的所有的 entry 对象,比拟它的哈希值,如果哈希值雷同,再去比拟 join key。
  4. 如果 join key 雷同,则代表 probe 胜利,拼接左右表的对应列并生成最终的后果。

如何将这样的执行过程用向量化实现?

  1. 从左表外面读取批量数据。
  2. 应用 CodeGen 技术批量计算 hash code 值。
  3. 依据 hashcode 值,批量查找 hash table,失去可能的后果集。
  4. 批量比拟左右表的 join 列值,如果匹配的话,则拼接左右表的对应列并生成最终的后果。

与原来行式的火山模型比起来,向量化执行次要差一点在于:

  1. 按列计算;
  2. 批量计算。

(六)插件集成

计算引擎如何与 ADB PG 代码交融?

ADB PG 同时反对 PG 计算引擎和 Laser 向量化计算引擎。优化器会主动依据 SQL 的 pattern 和扫描的数据量来决定是否应用 Laser。如果扫描数据量太少,则应用原生的计算引擎。如果数据量足够多,并且这些 SQL pattern 比拟适宜应用向量化执行引擎的,就应用 laser 计算引擎。

Laser 引擎的所有代码采纳插件模式,代码独立。益处在于代码能够和原生代码之间齐全是松耦合关系,不会影响 PG 的原生代码,同时能够复用外面的一些函数和数据结构。插件模式还带来一个益处,就是能够实现热降级。因为采纳动静库形式,可能在不重启 PGdameon 过程的状况下,替换插件,实现降级 LASER 引擎。

惟一须要批改的是三个 stub 函数—ExecutorStart、ExecutorRun、ExecutorEnd。

(七)TPC-H 后果

2020 年 5 月 20 号,咱们实现了 TPC-H 30TB 场景测试,拿到了世界第一的问题。相比于第二名微软 SQL Server 2019,整体性能晋升了 290%,且老本只有 SQL

Server 的 1 /4。

通过性能指标统计,Laser 计算引擎对性能晋升起了至关重要的价值,绝对于 PG 计算引擎,性能晋升了两倍之多。细分计算引擎的各种优化,其中大半的性能晋升都是来自于向量化晋升。其次是是 JIT 减速,次要来源于表达式的计算。第三来自于是 Fusion Scan,针对列存场景下,咱们通过 Fusion Scan,缩小了内存的拷贝,缩小了无用的读取。最初还有小局部来自于 SIMD 指令的晋升。

三、计算引擎的将来瞻望

整体的将来转化(以将来一年为打算):

第一:2020 年 12 月,反对窗口函数,实现全算子的向量化革新。

第二:2020 年 3 月,实现网络 motion 重构。

第三:2020 年 6 月,实现算子并行执行优化,能够充分利用多核能力。

第四:2020 年 9 月,实现优化器适配。优化器不仅适配打算数据书,同时可能依据计算引擎来做动静辨认,可能感知到数据的动态变化,再去动静去调整执行打算。

原文链接
本文为阿里云原创内容,未经容许不得转载。

退出移动版