关于数据库:ByteHouse云数仓版查询性能优化和MySQL生态完善

3次阅读

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

ByteHouse 云数仓版是字节跳动数据平台团队在复用开源 ClickHouse runtime 的根底上,基于云原生架构重构设计,并新增和优化了大量性能。在字节外部,ByteHouse 被宽泛用于各类实时剖析畛域,最大的一个集群规模大于 2400 节点,治理的总数据量超过 700PB。本分享将介绍 ByteHouse 云原生版的整体架构,并重点介绍 ByteHouse 在查问上的优化(如优化器、MPP 执行模式、调度优化等)和对 MySQL 生态的欠缺(基于社区 MaterializedMySQL 性能),最初结合实际利用案例总结优化的成果。

在 2023 云数据库技术沙龙“MySQL x ClickHouse”专场上,火山引擎 ByteHouse 的研发工程师游致远,为大家分享一下《ByteHouse 云数仓版查问优化和 MySQL 生态欠缺》的一些工作。

本文内容依据演讲录音以及 PPT 整顿而成。

火山引擎 ByteHouse 的研发工程师游致远

游致远,火山引擎 ByteHouse 资深研发工程师,负责 ByteHouse 云数仓版引擎计算模块。之前先后就任于网易、菜鸟团体、蚂蚁团体,有多年大数据计算引擎、分布式系统相干研发经验。

ByteHouse 云数仓版查问优化和 MySQL 生态欠缺

明天我次要分享的内容纲要,分为上面这四个局部。首先次要是跟大家讲一下 ByteHouse 云数仓版的背景和整体架构、而后重点讲下查问引擎上做的优化和欠缺 MySQL 生态的一些工作,最初是总结。

内容纲要

Clickhouse 是基于 shared nothing 架构,这种架构也带来了比拟极致的性能。字节跳动的话,从 2018 年就开始在线上 应用 Clickhouse,而后到当初曾经是十分大的机器量和数据量。然而 Clickhouse 的 shared nothing 架构,也给咱们带来了很大的艰难,次要是数据的扩缩容比拟难,包含存储和计算资源的绑定,导致咱们想做一些弹性的伸缩也比拟难。而后读写不拆散带来的影响,以及在公共集群上中小业务的查问的影响。

为了彻底解决这个问题,而后咱们在 2020 年的时候,开始做一个基于云原生架构的 Clickhouse,过后外部的代号叫 CNCH,当初在火山上叫 ByteHouse 云数仓版。而后当初 CNSH 在外部也是有十分大的应用规模,到 2022 年的时候,咱们决定把这个回馈给社区,过后跟 Clickhouse 社区也进行了一些探讨,起初感觉架构差别太大,而后就独自以 ByConity 我的项目开源了,在往年 1 月份曾经在 GitHub 上开源了。欢送大家去关注和参加一下。

Clickhouse 基于 shared nothing 架构

下图就是 ByteHouse 云数仓版的整体架构,这是比拟经典的架构。服务层负责就是数据,事务查问打算的协调,资源的治理。两头这层是可伸缩的计算组,咱们叫做 virtual warehouse(VW),也叫虚构数仓,业务是能够按 virtual warehouse 进行隔离,互相不会影响,能够随便的扩缩容,是一个无状态的计算资源。最上面是数据存储,咱们是形象了虚构的文件层,能够反对 HDFS,以及还有对象存储 S3 等。当然在理论查问的时候,就是咱们也会做一些热数据的 local cache.

ByteHouse 云数仓版的整体架构

上面重点来讲咱们在查问引擎的优化。咱们晓得 ClickHouse 的单机执行十分强,而后这个是 2021 年的 ClickHouse 的单机执行逻辑,非常简单的 count(*) 的聚合运算。ClickHouse 首先会生成一个逻辑打算,叫 QueryPlan。这里能够通过 EXPLAIN 看到每一步,就 query plan step,就是读表,而后做聚合。

ClickHouse 的单机执行

而后再通过 QueryPlan 会生成一个 QueryPipeline。这个过程中能够看到,query plan step 被翻译成了 QueryPipeline 外面的一步,叫做 processor,或者叫做物理算子。

QueryPlan 会生成一个 QueryPipeline

ClickHouse 的单机模型其实是十分的强的,而后整体 Pipeline 驱动模式能够参考上面这个图,这里就不再具体开展。

ClickHouse 的单机模型

接下来咱们就看下另外一个场景,分布式执行。这是一个分布式表,而后有三个分片。做一个简略的 count,在 ClickHouse 这块的话,就是把它改写成三个本地执行的子查问,而后别离计算,生成两头的 Partial merge result,最初在 coordinator 节点上进行聚合,最初生成一个残缺的后果返回给用户。

ClickHouse 分布式执行

这个模型特点就是十分的简略,而后实现起来也是十分高效,然而在理论业务中也发现一些毛病。首先对于两阶段的话,第二个阶段的计算如果比较复杂,Coordinator 的计算压力会十分的大,很容易呈现瓶颈。在聚合运算的时候,比方 count distinct 的常常会呈现 OOM 或者算不进去,它整个架构是没有 Shuffle 的。如果有 Hash Join,右表的大小不能放到一个单机的内存外面,基本上就是跑不进去。整个打算层的话,下发 ast 或者 sql 的形式,表达能力是十分无限的,咱们之前是想基于这个做一些简单优化,也是不太好做,灵便度也比拟低。最初的它只有一个基于规定的优化,像一些比拟重要的 join reorder 的排序也是没法做。

ClickHouse 模型的优缺点

基于下面提到的问题,咱们是基本上重写了分布式执行的查问引擎。次要做了两点,一个是就是反对多阶段执行,这也是大部分支流的 MPP 数据库,以及一些数仓产品的做法。第二个咱们自研的整个优化器。上面是一个比拟残缺的执行图。能够看到,相比于方才二阶段执行,一个查问过去之后,他的第二阶段就是 Final agg 能够在两个节点上了。TableScan 做完之后,通过肯定的规定进行 shuffle。这个是通过 exchange。而后最初的后果再会集到 Coordinator。当然这里还有 ByteHouse 云数仓的一些其余组件,这里不再细讲。

ByteHouse 分布式执行的查问引擎

为了反对多阶段的执行模型,咱们就引入了 PlanSegment。简略说就是每一个 worker 上的一段逻辑的执行打算。从实现上来讲,它其实就是单机打算的 QueryPlan,再加上输入输出的一些形容。而后这边就是 PlanSegment 的介绍,输出的 PlanSegment 和输入要到输入到哪个 PlanSegment。

多阶段的执行模型概念 PlanSegment

理解 PlanSegment 之后,能够就会问这个 PlanSegment 是从哪里来的。其实方才介绍了,就是通过优化器进行打算生成和优化得来的。整体的一个流程就是从 Parser 把一个 SQL 变成了一个 AST(形象语法树),而后在优化器这个模块外面,在 interpreter 外面变成了一个 PlanSegmentTree,切分成一组 PlanSegment 再下发给各个 worker。

PlanSegment 整体流程

优化器,次要就是查问打算的变换。分为 rule based optimizer 和 cost based optimizer,就是基于规定和基于代价。基于规定的话,咱们是实现了一个种基于 visitor 的一个改写框架,次要做一些全局的改写,反对从上到下,从下到上的形式,包含一些 condition 的下推,还有 SQL 指纹,这种像须要正则化 SQL 的。咱们还反对基于部分的 pattern-match 改写,例如。发现两个 Filter 是相连的,那就会到合并到一起,Projection 也是相似的做法。

优化器 RBO

CBO,上面是一个通用的 CBO 的框架。当一个查问打算过去的时候,咱们会通过 optimizer Task 的规定,和 Property 来一直的裁减这个 grouping。两头这个是 memo,记录等价的 QueryPlan。而后把所有的 QueryPlan 生成之后,依据计算的代价,最初抉择代价比拟低的作为输入。当然在具体实现的时候,其实是有很多思考,会包含生成的时候怎么升高等价 plan 的数量,以及怎么在生成的同时抉择分布式打算最优计划。

优化器 CBO

当优化器生成了 PlanSegment 的时候,就波及到该如何下发。上面就是咱们的调度器模块。当查问生成完一组 PlanSegment 之后,咱们能够依据调度的类型,当初咱们次要是 MPP 的多阶段执行。就会把它生成一个子图一次下发,前面也会思考其余的一些调度形式,依据工作类型,包含相似于 Spark 的 BSP,或者是分阶段调度。生成完这个一个子图的调度之后,马上就要抉择 PlanSegment 到哪些 worker 执行?

这里的话。就是方才讲 service 层,congresource manager 拿各个 worker 层的负载信息,调度 source 的话,咱们是次要思考缓存的亲和度;而后调度计算 plansegment 的话是 worker 能够纯无状态,咱们是次要思考负载,就是尽量保障负载平衡来进行调度。这里也是尽量避开一些慢节点,以及一些曾经死掉的节点。当然咱们也在做其余的调度的形式,就是一些资源的预估和估算。这个具体解决问题能够前面再讲。咱们生成完 PlanSegment,而后发给 worker 之后,它的执行就是方才讲的 clickhouse 的单机执行了。

调度器模块

刚刚提到一点,就是数据的就是的传入和传出,这个是依赖于 Exchange 模块。Exchange 就是数据在 PlanSegment 的实例之间进行数据交换的逻辑概念,从具体实现上的话,咱们是把它分的数据传输层以及算子层。

Exchange 模块

数据传输层的话,其次要是基于定义 Receiver/ Sender 的接口,而后同过程传输基于队列,跨过程是基于基于 BRPC Stream,反对保序、状态码传输、压缩、连接池复用。连接池复用、简略来说,就是把大集群上的两个节点之间的只建设一个连贯,所有的查问都在这个连贯上通信,当然咱们是连接池,所以实际上是两个节点之间是固定数量的一个连贯,这样会比单连贯的稳固好更高。

Exchange 数据传输层

算子层的话,咱们是反对了四种场景。一个是一对多的 Broadcast。而后多对多的 Repartition,以及是多对一的 Gather,个别在本过程之间的 Round-Robin。这外面也做了一些优化,包含 Broadcast 怎么样防止反复的序列化,而后 Repartition 怎么晋升性能,以及 sink 怎么攒批。在大集群下,怎么通过一个 ExchangeSouce 读取多个 receiver 的数据,来升高线程数。

算子层

这里是比拟高阶的一些优化点,第一,RuntimeFilter 就是在执行期间生成的动静 filter,比方这是两张表的一个等值 join。咱们能够在右表构建哈希 table 的时候,会生成一个 bloom filter(或者其余类型的 filter)。而后把各个 worker 上的 bloom filter 的收集后 merge 成一个,而后再发给左表所在的 worker,这样在左表进行 table scan 的时候,能够过滤掉十分多不必要的数据,而后也能够节俭一些计算的资源。这个的话须要优化器整个参加决策,因为生成和传输过程也是有代价的,看哪个代价更低。或者他还会判断一下过滤能力。

高阶优化:RuntimeFilter

另外就是在执行层的话,咱们有一些压缩算法的优化,就比如说表级别的全局字典。咱们晓得社区有一个低级数类型,它的字典是 part 级别的,曾经能够在一些计算上做到不解压计算了,当咱们扩大成表级别的时候,大部分的计算都能够间接在编码值上或者在字典上进行,就齐全不须要去解压数据了,甚至传输也能够传输编码后数据的。函数计算,聚合运算也是,这块在 TPCDS 上应该有 20% 的晋升。

高阶优化:表级别的全局字典

其余的优化,这里能够简略的说一下,包含 Windows 算子的并行化,而后 Windows 外面 Partition 的 top 下推;公共表达式的复用;以及当初多阶段模型下,对社区为两阶段模型实现的 aggregation、join 的算子做了一些重构,为了更好的适应这个模型。咱们还反对 Bucket Join、简略查问上并发性能的优化。最初就是 ClickHouse 单机模型的毛病,就是它每个 Pipeline 是独立的线程池,当并发比拟高的时候线程会比拟多,上下文的切换的开销比拟大。咱们会把它做成协程化,防止过多的线程。

其余优化详情

这是整体的一个成果。而后在社区的两阶段,咱们通过改写,能跑完 26 个 SQL。咱们在多阶段执行和优化器实现之后,基本上是整个 TPC-DS 的 99 个 SQL 都是能够跑完的,性能也是失去了极大的晋升。

整体成果

而后上面讲一下过程碰到的挑战,以及没有解决的问题。第一个就是所有并行计算框架的老大难问题:数据歪斜。如果比拟有热点 key,或者聚合件外面的 key 过少的话,即便有再多的 worker,最初也只会在一个 worker 上进行计算。打算层,其实是能够做两阶段聚合的调整,而后把 key 过少的问题能够解决,然而热点 key 的问题还是很难解决,其实能够在执行层做一些自适应的执行,这个还是在摸索阶段,可能相似于 Spark 的 AQE,然而因为 MPP 的话有很多限度,做不到这么欠缺。

数据歪斜

第二个挑战,超大的 MPP 集群的问题。业内的话个别超过 200 个的 MPP 集群,就是会碰到一些比拟多的慢节点的问题,或短板效应导致线性度急剧下降,稳定性也会降落。咱们在外部曾经有大略将近 800 个节点的计算组,而后可能马上就会有超过上千个节点的一个计算组。是要怎么样保障这种大超大 MPP 集群的稳定性和性能,咱们做了一些自适应的管制,进步整体的稳定性。就我方才讲的自适应调度、资源的预估和预占是一个方面,另外就是限度每一个查问的复杂度和应用资源,防止大查问导致把某个 work 的资源就是占的过满,而后导致的慢节点。最初一个就是对用户无感的一个 VW 的一个主动划分,划分一些小的子集,这个子集的话是固定的,是为了保障 cache 的亲和度,咱们会依据查问的大小来主动的抉择,这个也算躲避了超大的问题。

超大的 MPP 集群

最难的还是怎么构建容错的能力,在这种大集群情景下,如果假如每一个节点的错误率为 e 的话,那节点数量为 N 的话,那运行失常概率就是 (1-e)^N。节点数量扩充,错误率就会指数级回升。咱们在摸索就是 query 的状态的 snapshot,相似于 flink 异步的 snapshot 的计划,能够构建肯定的恢复能力,另外一个咱们是有 bucket table,就是会有一些计算是在闭合在 bucket 外部的,某一个 bucket 失败可齐全不影响其余 bucket,是能够独自去重试的。这是咱们碰到的两个次要的挑战。

构建容错的能力构建容错的能力

这个专场是对于 MySQL 和 ClickHouse,咱们也讲一下 ByteHouse 在 MySQL 生态上做的一些事件。咱们晓得把从 MySQL 数据导入到 ClickHouse 的话,次要当初有三种计划。一种是 ClickHouse 的 MySQL 表引擎,你能够间接通过数据库引擎建一个 MySQL 的表面,而后用 insert select 的形式一次性的把数据导入,然而有数据量的限度不能太大,也不能继续的同步。其实在 GitHub 上有开源的工具,它是基于 binlog 同步的。但这个操作是比较复杂的,而后并且在曾经进行更新了。社区最近是开发了一个 materialized MySQL 的一个性能。这个我认为是将来的一个最佳实际。

MySQL 数据导入到 ClickHouse

Materialized MySQL 的话,它的原理也比较简单。用户的话就是创立一个 Materialized MySQL 的数据库引擎,这样 ClickHouse 会有后盾的一个线程,而后异步的去拉取 MySQL 的 Binlog。而后会写到一个 Replacing MergeTree 外面。这个为什么要用 replacing MergeTree,因为它是能够进行逐步的去重。它尽管是那种异步的,但也是能够近似的实现去重工作。而后 ClickHouse 是做了一些 trick,就是在这个 replacing MergeTree 外面能够给同步的 Binlog 加两个字段,一个是 sign,一个是 version,而后后续 replacing MergeTree,就依附这两个字段会进行一些去重,sign 示意的是。数据的是否删除,version 代表的是这次数据的版本,如果你加了 final 的话,它会就是在查问的时候,会用最高的版本笼罩低的版本。

Materialized MySQL 的原理

这个介绍大略的应用,用户从 Materialized MySQL 的数据库引擎。在 ClickHouse 外面创立,而后在 MySQL 外面通过 insert 语句去写入各种数据,你在 ClickHouse 外面能够查到,当然还有一些没有展现,就是你在 Materialized MySQL 外面去创立一些表。而后也会动静的在 ClickHouse 这边生成,就是 DDL 的也能够同步过去的。方才我为啥说这个是将来的最佳实际,因为这个还是实验性的性能,它会有很多不欠缺的中央。

Materialized MySQL 的数据库引擎

首先,它是不反对不兼容的 DDL,只有有一个报错,而后整个同步就进行了,而后进行又是悄无声息,你没有方法去手动的去触发它的再同步。第二点,就是社区的 Materialized MySQL 的 replacing MergeTree 其实是一个单机引擎,只能在单点上同步,如果呈现一个单节点的故障的话,就是高可用会成为问题,另外单节点也会有吞吐量的限度。第三个就是方才讲的运维的艰难,看不到同步的状态、当初同步的信息、以及没有同步重启的工作。

Materialized MySQL 的劣势和有余

而后 ClickHouse 的做了一个 CNCH 的 Materialized MySQL 的数据库引擎,也是把引擎给云化,修复了社区的一些缺点,真正做到的生产可用。它的原理次要就是通过咱们的 service 层,依照表的力度去在各个 worker 下来调度线程,写到咱们的惟一键引擎外面。

Materialized MySQL 的数据库引擎原理

当初讲一下解决的这些问题,第一个有十分具体的零碎表,能够看到当初运行的状态。而后也有进行启动重启的各种指令,就是这个整个运维是可用了。咱们反对按表多 worker 的并发生产。因为是基于原生的架构,存算拆散,如果单个 work 失败,能够马上主动的从新调度 Rebalance。最初咱们是基于惟一键引擎,它是为读优化的,就查问性能会更好。最初是反对配置跳过不兼容的 DDL。做了这些工作之后,咱们这个引擎基本上是能够说是生产可用了。

CnchMaterialized MySQL 解决的问题

总结一下,明天的一些次要的内容吧,就是次要给大家讲了一下,ByteHouse 云数仓版的背景以及整体架构。第二局部是重点讲了在查问引擎上的整体设计和优化点。最初讲了一下咱们生产可用的云数仓版的 Materialized MySQL 的表引擎,为了欠缺 MySQL 生态做的一些工作。

2023 首届云数据库技术沙龙 MySQL x ClickHouse 专场,在杭州市海智核心胜利举办。本次沙龙由玖章算术、菜根倒退、良仓太炎共创联结主办。围绕“技术进化,让数据更智能”为主题,汇聚字节跳动、阿里云、玖章算术、华为云、腾讯云、百度的 6 位数据库领域专家,深刻 MySQL x ClickHouse 的实践经验和技术趋势,联合企业级的实在场景落地案例,与宽广技术爱好者一起交换分享。

正文完
 0