Clickhouse 计算引擎架构 —— Clickhouse 架构篇(三)

前言

相比较于存储引擎的精妙设计,ClickHouse的计算引擎一直是一个争议非常大的话题。对ClickHouse计算引擎的各种评价都有,两极分化很严重。有人认为ClickHouse计算引擎的向量化设计得巧夺天工,也有很多人认为ClickHouse的计算引擎缺乏优化和对分布式的支持,就是个半成品。这些对ClickHouse计算引擎的评价都在一定程度上反映了ClickHouse计算引擎的某些方面,如果从这些方面来看待ClickHouse的计算引擎,难免陷入盲人摸象的状态。

本文将介绍ClickHouse计算引擎的架构,以及ClickHouse的向量化计算引擎与传统事务数据库的火山引擎之间的区别。整体了解ClickHouse计算引擎后,我们将客观地得出自己对ClickHouse计算引擎的评价。

ClickHouse计算引擎的架构简介与设计思想

传统计算引擎会将 SQL 转换为物理计划,Clickhouse 也一样, Clickhouse 将物理计划叫做查询流水线(QueryPipeline)。

架构简介

整体架构
ClickHouse计算引擎整体架构如下图所示,由三部分组成:SQL解析器(Parser)、解释器(Interpreter)、执行器(PipelineExecutor)。
image.png
ClickHouse计算引擎整体架构是按照火山引擎的模式进行设计的,将SQL语句转化为可以被执行的处理单元(Processor)的集合,由执行器执行。向量化引擎和火山引擎最大的不同点在于ClickHouse的处理单元的设计是面向向量的,而传统事务数据库是面向行的。构成QueryPipeline的处理单元不同,导致ClickHouse计算引擎和传统的火山模型的不同。这也是ClickHouse向量化引擎的由来。

SQL解析器

  • Clickhouse 中的 SQL 解析器并没有使用传统的开源方案,而是自己手写的,但是 SQL 解析在整个查询中的耗时可以忽略不计。

解释器

  • Clickhouse 解释器会根据 AST 树生成查询流水线,该阶段会对SQL 进行逻辑优化,ClickHouse中实现的逻辑优化主要是基于规则进行优化,常用的手段有谓词下推、count优化、消除重复字段等。

执行器

  • ClickHouse通过执行器对查询流水线进行处理,最终获得结果即为用户提交的SQL语句的执行结果。
  • ClickHouse的高性能来自向量化引擎。向量化引擎的核心在于查询流水线的编排方式,火山模型和向量化模型的本质区别在于SQL语句的编排方式。

设计思想

Clickhouse 的所有架构设计都是为了一个目标:充分发挥单机能力的OLAP引擎

充分利用现代CPU特性

  • 向量化引擎利用了现代CPU提供的SIMD能力,提供的硬件加速能力。

充分发挥单机优势

  • Clickhouse 中的表都是对单机表的操作,Clickhouse 中的集群表并不是真正意义上类似于 Hadoopz 中的分布式表,而是单机表的映射。

    因此 Clickhouse 中的 SQL 对大表 JOIN 操作,经常由于内存不足导致失败,Clickhouse 的更多架构设计放在了向量化引擎上。

  • 我们在使用 Clickhouse 查询时应该尽量避免 JOIN 操作,充分发挥向量化引擎的特性。

火山模型

ClickHouse的向量化引擎是基于标准火山模型进行的调整。
火山模型执行示意图如下,一般经历三个过程,扫描,过滤,投影,每一个过程都会返回一个元组,执行完毕后调用 next() 方法,进入下一过程计算。
image.png

  • 扫描(Scan)节点负责从磁盘中读取所有member表的数据并交给过滤(Select)节点。
  • 过滤节点负责过滤出满足过滤条件的数据并交给投影(Project)节点。
  • 投影节点负责将表中birthday列的数据筛选出来,再按照用户提供的计算公式计算出Age并返回给用户。
  • 过滤指的是按行筛选,投影指的是按列筛选。

火山模型的核心是有很多独立的算子,每个算子计算出一个元组,然后每个算子又是一个迭代器,通过 next() 方法调用下一个算子。例如Join操作,在火山引擎中表现为一个Join迭代器,在其next方法中实现Join操作的各种算法,返回元组,供上层进一步操作。再如OrderBy操作,在火山引擎中也会表现为一个OrderBy迭代器,在其next方法中将输入的数据按照规则进行排序,并向上输出元组供上层使用。
优点

  • 通过堆叠不同节点的方式实现能力,因此在实现火山引擎时只需要实现有限数量的计算节点,且每个节点只需要实现单一的简单功能,即可完成模型的构建。

缺点

  • 可能导致堆叠的层数过多,甚至出现大量的递归操作,从而降低查询性能。

向量化引擎

向量化引擎是在火山引擎的基础上实现的,火山引擎每一个算子返回的是元组,由不同的列组成,而向量化引擎返回的是单独列组成的数组,也被称为列向量

向量化引擎的实现方式

火山引擎和向量化引擎的物理计划执行对比如下图:
image.png
向量化引擎列向量的设计,可以使投影操作将下推至扫描阶段,在第一步扫描阶段直接返回birthday列。最终,该SQL语句的执行顺序如下:

  1. 通过读取数据源(ReadFromSource)节点直接获得birthday列向量。
  2. 通过过滤转换(FilterTransform)节点筛选出满足isVip=1的数据。
  3. 通过表达式转换(ExpressionTransform)节点计算出Age。

将投影操作下推至底层阶段,可以在表中列的数量比较多的场景下获得很高的性能。
另外,向量化引擎可以使用向量化的算法进行计算,充分利用CPU并行计算的特性,实现计算加速。

向量化引擎的前提

既然向量化计算可以并行计算,提升查询性能,为何传统的事物数据库不使用向量化计算呢?
下边让我们看下向量化引擎的前提。
存储引擎支持

  • 向量化引擎产生效果的前提是存储引擎返回的数据是按列聚集的,而事物数据库一般是行存,对于行存的存储引擎来说,设计向量化的计算引擎没有必要。除非事务数据库能够抛弃传统的行存存储引擎,改用列存储引擎。
  • 即使改为列存,事物数据库的核心是事物性,列存的存储引擎在应对事务时会带来更多的额外工作,导致事务的性能急剧下降,得不偿失。

硬件支持

  • 需要 CPU 支持 SIMD 向量化计算,软件只是将组织好的数据交给硬件,真正执行向量化计算的还是 CPU。

软件支持

  • 这里的软件特指编译器和向量化算法。编译器会自动将符合向量化优化的操作编译为特殊的SIMD指令。

计算引擎如何影响查询速度

Clickhouse 的向量化引擎可以利用向量化计算大大加速查询速度,但是凡事有利有弊,Clickhouse 在解释器阶段生成物理计划的时候,并没有进行 CBO(代价优化器)优化物理计划,只有逻辑计划的优化,导致对于有些 SQL 场景反而查询速度很慢,甚至失败。
因此在使用 Clickhouse 进行查询时,我们也需要注意一些事项,充分发挥向量化计算的优势。

大量使用向量化运算

  • 尽可能使用ClickHouse提供的内置函数进行计算,而不是自己写SQL 计算语句。

查询语句中没有使用Join子句,或尽可能少地使用Join操作

  • 在使用ClickHouse时,应当尽可能避免Join操作。
  • ClickHouse在设计良好的DW层上运行向量化查询的性能最高,尽可能避免将ClickHouse用于ODS层的建模工作中。当数据量大时,这类建模工作还是尽可能下推到Spark上进行。

总结

作为用户,我们应该了解ClickHouse速度快的前提,有意识地避开ClickHouse的雷区,不要将ClickHouse用于其不擅长的场景。正如此时此刻,大家都意识到了MySQL无法解决大数据量的OLAP问题,这类问题要通过专业的OLAP引擎解决。
开源社区要的并不是什么能力都有、但都不强的平庸的软件,而是百花齐放、各自有着各自擅长的领域的产品,通过组合实现架构上的合力。

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一切如来心秘密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值