拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MPP架构核心解析:从并行原理到主流数据库选型实践

MPP架构核心解析:从并行原理到主流数据库选型实践

上个月帮朋友优化一个数据看板,后台那条跑了三个多小时没出结果的聚合SQL,换到一套MPP集群上,同样的数据量,两分多钟就回来了。那一刻我意识到,MPP这个概念虽然被圈内讲烂了,但绝大多数人其实对它只有一个模糊印象,真到选型、部署、排错的时候,很多细节还是要重新捋一遍。这篇是MPP系列的第一篇,先把地基打牢,说清楚MPP到底是什么、它的架构核心长什么样、以及目前市面上主流的MPP平台各自支持到什么程度。适合刚接触分布式数据仓库的开发者,也适合那些已经在单机数据库上被大查询折磨过、正在考虑要不要往MPP迁移的团队。

1. 从一次慢查询说起:MPP到底是什么

1.1 一个三小时变两分钟的直观对比

先复盘一下上面提到的那个案例。那套看板的底层是一个单机版的关系型数据库,配置不算差,32核CPU、256GB内存,SSD盘。业务表大概有4亿行,要按时间窗口做多维度聚合,还要关联三张维表。单机数据库在执行这种查询时,全表扫描加哈希关联,把CPU和磁盘IO全都打满,跑了三个小时也没出结果,看板直接超时。

后来把同样的表结构和数据迁到一套8节点的小型MPP集群(每个节点16核、64GB),建好分布键和分区之后,同一套SQL跑下来用了不到两分钟。快出来的原因说起来也不玄乎:4亿行数据被拆成8份,每个节点只扫自己手上的5000万行,几个维表做了复制分发,关联的时候不需要大量跨节点搬数据,所有节点同时干活,最终结果再汇总到协调节点返回。

这就是MPP的核心逻辑:大规模并行处理(Massively Parallel Processing),把一个大任务拆成多个小任务,分散到一堆独立的服务器上同时执行,最后把结果合并。它不是什么高深魔法,本质上跟装修请一支施工队一个道理——师傅一个人砌墙三个月,来十个师傅各管一段,时间自然就压下来了。

1.2 MPP的准确定位与边界

严格来说,MPP指的是一种并行计算架构,不是某一个具体的数据库产品。它描述的是一类系统的组织方式:由多个节点构成,每个节点有自己独立的CPU、内存和磁盘,节点之间通过网络互连和通信,数据和处理逻辑尽可能在本地完成。

这里就容易遇到第一个混淆点:MPP和普通分布式系统是一回事吗?答案是相关但不等同。分布式是一个更宽泛的概念,一个分布式文件系统如HDFS也是分布式的,但它本身不负责并行计算;一个微服务系统也是分布式的,但它的目标是解耦业务逻辑,不是为了把一个SQL查询拆碎了并行去跑。MPP则特指那种"数据分散存储在各节点、计算任务也分发到各节点、各节点并行执行、最终结果合并"的数据库或计算引擎。

还有一个边界需要说清楚:MPP不是OLTP的菜。一个典型的OTLP系统,比如电商下单,特点是大量短小的事务型SQL,每次读写的数据量很小但并发极高。MPP擅长的是OLAP场景,七八张大表join、几十亿行扫过去做聚合、按任意维度切片切块,这种"重活"才是它的主场。用我常打的比方,OLTP好比街边便利店,一个顾客买一盒牛奶很快就走,关键是要服务得快;OLAP好比大型仓储超市的周末大采购,一辆购物车装满各种东西,结账一批算一批,一次干大活。

1.3 为什么单机数据库会在某一天突然扛不住

聊MPP之前,先理解"为什么必须上MPP"比理解"MPP是什么"更重要。单机数据库的性能天花板受三个硬件因素限制:CPU的计算速度、内存的容量、磁盘的IO吞吐。单台服务器做到极致,比如64核、512GB内存、NVMe全闪阵列,它能支撑的数据量和计算复杂度有一个明确的上限。当一张表膨胀到几十亿行、一个聚合查询要扫描数百GB甚至上TB的数据时,单机的磁盘IO就成了绕不开的瓶颈,CPU再快也得等数据从盘上读出来。

同时,单机数据库还有个隐性痛点:缓存命中率。数据量大到内存装不下之后,频繁的磁盘换页会让整个系统进入一种"看起来CPU不高但查询就是慢"的瘫痪状态。这个阶段很多团队的第一反应是加内存、换更快的盘,但这只是延缓,不是解决。每加一轮硬件,成本都在涨,而查询复杂度和数据量还在涨,总有一天你会发现这台机器已经顶在配置表的最高档位上了,上面已经没有任何可以再加的硬件。

MPP解决的是这个结构性难题:不跟单机硬件较劲,而是用多台普通机器堆成一个逻辑集群,把数据和计算平摊出去。这也是很多公司从PostgreSQL或MySQL单机实例迁到Greenplum、ClickHouse这类系统最核心的驱动力。

2. MPP架构的核心组件与数据流转逻辑

2.1 三种并行架构对比:SMP、NUMA与MPP

想真正理解MPP的架构精华,最好先把它放进并行架构的谱系里看。并行计算领域大体有三种经典模型。

SMP对称多处理架构是最传统的一种,多个CPU核心共享同一块内存和同一组IO总线,操作系统把任务分配给各核心。它的优势是编程简单,数据在内存里共享起来非常方便,一台机器里所有核心看到的是同一个数据视图。但缺陷也很明显:所有核心抢同一条内存总线,核心数量一多,总线带宽就成了瓶颈。SMP架构撑死了也就几十个核心,再往上扩展收益急剧下降。

NUMA非一致内存访问架构是对SMP的改良,每个CPU核心组有自己的本地内存,访问本地内存快,访问别组的内存慢,内存访问不再一致。它把单机的扩展性往前推了一步,但还是受限于一台物理服务器能容纳的CPU和内存总量,本质上仍然是在跟硬件厂商的服务器规格表较劲。

MPP直接换了一套思路:每个节点本身就是一台完整的计算机,有自己的CPU、内存、磁盘,节点之间不共享任何物理资源,通过高速网络连接。这种设计叫Shared Nothing无共享架构。带来的最大好处是扩展性接近线性——存储不够了、算力不够了,加节点就行,不用动原有架构。代价是跨节点数据交换要走网络,比本地内存慢几个数量级,所以MPP系统对执行计划的优化极其敏感,最怕的就是没必要的跨节点数据搬运。

三者用一张表格看得更清楚:

架构类型资源组织方式扩展能力核心瓶颈典型场景
SMP多核共享内存总线弱,数十核封顶总线带宽、缓存一致性单机OLTP、小规模OLAP
NUMA内存分区,就近访问中,单机多路扩展跨区访问延迟、物理机上限高性能单机计算
MPP节点完全独立,网络互连强,近线性扩展网络带宽、数据分布策略大规模OLAP、数据仓库

2.2 两个关键角色:协调节点与计算节点

MPP集群里有两类逻辑角色,几乎所有MPP数据库框架都遵循这套分工。

协调节点也叫Master节点或Coordinator节点,是整个集群的"大脑",负责三件事:接收客户端发来的SQL,对SQL做解析、合法性检查,并生成全局的执行计划;把执行计划拆分成可以在各个计算节点上并行执行的子任务,分发给下面的节点;收集各计算节点返回的结果片段,合并成最终结果集返回给客户端。

计算节点,在Greenplum里叫Segment,Doris里叫BE,ClickHouse里叫分片节点,是真正存数据和跑计算的地方。每个计算节点只持有全量数据的一部分,查询时各自扫描自己手头的数据分片,完成局部的扫描、过滤、关联、聚合,再把局部结果向上汇报。数据量越大,计算节点越多的优势就越明显,因为每个节点要处理的数据量是集群整体规模在均摊。

需要注意的一个设计细节是:协调节点本身通常不存业务数据,它不参与底层的扫描聚合计算,只做调度和汇总。这个设计保证了集群的横向扩展不受协调节点性能拖累——计算节点增加了,整个系统算力就增加,协调节点只负责分发和合并,承担的负载增长相对有限。

2.3 数据分布策略决定了大半的性能

数据在各计算节点上怎么分布,是整个MPP架构里最讲究的部分。分布策略选错了,后续怎么调优都像在破洞的船上舀水。主流MPP数据库提供三类分布策略。

哈希分布是最常用的一种。建表时指定一个或多个列作为分布键,系统对该列的值做哈希运算,根据哈希结果把行分配到对应的计算节点上。同一分布键值的数据必然落在同一个节点,这个特性让基于分布键的等值关联可以在本地完成,不需要跨节点搬数据。选择分布键的原则是:尽量选择查询中最常作为关联条件和过滤条件的列,同时该列的值要有足够的区分度,避免大量数据扎堆到一两个节点。

随机分布也叫轮询分布,新来的数据行轮流放到各节点,保证数据量上是均匀的,但无法保证某列相同值的行落在同一节点。它的适用场景是那些没有明确关联键的临时表、中间结果表,或者分布键尚未想清楚时的一个过渡选择。代价是后续如果要对这张表做关联,大概率要发生跨节点数据重分布,性能损耗很大。

复制分布把小表完整复制到所有计算节点上,每个节点都持有一份全量副本。这个策略对维表非常友好,事实表与维表关联时,每个节点拿自己本地的维表副本就能完成关联,完全不产生网络传输。典型用法是星型模型里的日期维表、地区维表、产品维表这类几百MB以内的小表。

实际项目中我见过太多因为分布键没选好导致性能崩盘的案例。比如把分布键设成一个几乎所有行都相同的字段,那张表干脆就只有一两个节点在干活,MPP直接退化成了单机。所以建表之前,第一步永远是分析业务查询的特征,想清楚最频繁的关联条件是什么,然后把分布键交给那个字段。

2.4 一次查询在集群里的完整旅程

把前面几个概念串起来,看一条SQL在MPP集群里具体怎么走。以Greenplum为例,一个典型的带关联和聚合的查询大概分这么几步:

第一步,客户端把SQL提交给协调节点。协调节点对SQL做解析,生成语法树,然后经过查询优化器产生最优的物理执行计划。这一步的执行计划不是一个紧耦合的整体,而是被切分成多个"切片",每个切片分配给不同的计算节点并行执行。

第二步,各计算节点拿到自己的执行片段后,开始扫描本地存储的数据。每个节点并行执行过滤条件,比如按时间范围裁剪数据,只扫符合条件的数据块。这一步的并行度是MPP的优势所在,8个节点就是8路并行,64个节点就是64路并行。

第三步,如果查询涉及关联且关联键与分布键不一致,就得做数据重分布或广播:一种是按关联键重新计算哈希,把数据重新分配到对应节点;一种是小表广播,把维度表复制给所有节点。这一环节是整个查询链路里最容易拖慢速度的地方,也是优化器反复权衡的重中之重。

第四步,各节点完成局部聚合和关联后,向上传递中间结果。协调节点收到各个计算节点发来的结果片段,做最终的合并和排序,必要时做全局聚合,然后把结果集返回给客户端。

用快递分拣中心来类比这个流程再合适不过:每个城市的分拣中心(计算节点)各自负责处理本市件(本地数据),把包裹按目的地分好类(局部聚合),然后打包发往总中心(协调节点),总中心把来自各地的包裹合并整理成最终的路由清单返回。每一层各干各的,任务不交叉,顶层只管汇总。

3. 主流MPP平台与生态支持盘点

3.1 老牌商业代表:Teradata的江湖地位

提到MPP数据库,Teradata是绕不开的名字。它从上世纪80年代就开始做大规模并行处理数据库,最早也是最有名的一体机形态的MPP产品,长期统治金融、电信、零售这些对数据一致性要求极高的行业。Teradata的架构非常经典:主节点解析SQL、生成执行计划,存取节点AMPE并行存储和处理数据,底层使用无共享架构,配合专用网络连接,性能和稳定性在商用产品里属于标杆级别。

Teradata的问题是"贵"和"重"。一台入门级一体机动辄数百万元,扩容要加硬件模块,运维需要专业团队,不是一般公司能承受的。而且它的生态相对封闭,SQL方言与标准SQL有差异,人才也难招。这些年随着开源MPP的崛起,Teradata在市场上面临很大冲击,大量存量客户在往开源路线迁移。但了解它的架构依然有价值,因为很多后来者包括Greenplum在内,核心思想都继承了Teradata那一套:协调节点加计算节点,数据按分布键哈希分散,执行计划分片并行。

3.2 开源MPP主力:Greenplum的架构与能力边界

Greenplum是目前最知名的开源MPP数据仓库,基于PostgreSQL内核开发,可以说就是"PostgreSQL加了一副MPP骨架"。它的协调节点就是你熟悉的PostgreSQL实例,负责处理连接和SQL解析,执行时把任务推给多个Segment节点并行跑。每个Segment也是一个独立的PostgreSQL实例,存储一部分数据并执行本地的读写和计算。

Greenplum的生态继承自PostgreSQL,这意味着能用的工具链和扩展非常丰富,比如可以用标准JDBC/ODBC连接、支持丰富的SQL语法、支持窗口函数和复杂分析函数。它比较适合的场景是离线数仓、大规模BI报表、复杂查询分析,在几十TB到PB级别的数据规模下有不错的稳定性和性能。社区版免费,但部署调优的复杂度不低,尤其是分区策略、资源队列、并发负载这些都需要有经验的人去调。

Greenplum的能力边界也要心里有数:它不适合在线高并发场景,不适合单条查询延迟要求毫秒级的场景,也不适合做实时流式写入。它的定位很明确——批处理分析型数据仓库,完整跑一个复杂查询要几秒到几分钟,这是预期之内的表现。

3.3 新一代MPP与列式存储:ClickHouse的"非典型MPP"

ClickHouse这几年热度很高,但它并不是一个标准意义上的MPP数据库。它的核心卖点是列式存储加向量化执行引擎,单机性能极其强悍,经常能在一张表上做到每秒扫描数十亿行的速度,配合分布式表引擎ReplicatedMergeTree和分片机制,也可以在集群模式下并行处理。

但它和Greenplum那一类传统MPP有明显差异。ClickHouse的分布式能力更像是一种"手动管理的分片集群",建表时需要显式指定分片和副本,跨节点join和分布式事务的支持相对弱,适合做"按时间维度分片、单表大范围扫描聚合"这类日志分析、可观测性数据存储、在线分析服务等场景。如果业务需要大量多表复杂关联,ClickHouse会让你写得很别扭。

从选型角度看,ClickHouse适合的场景是"偏实时、偏单表扫描聚合、数据量极大"。Greenplum适合的场景是"离线数仓、复杂SQL关联分析、数据一致性要求高"。两者不冲突,不少团队的架构里甚至同时都有它们,各管一段,这一点后面选型部分再细说。

3.4 云原生MPP与湖仓一体:Doris和StarRocks的快速上位

如果说前几年是Greenplum和ClickHouse的天下,那这两年Doris和StarRocks这两个国产开源MPP数据库热度上升得非常快。它们的共同点是以MPP架构为基础,自带列式存储、向量化执行、物化视图,同时做了很多面向实时分析场景的优化,比如支持高并发点查询、明细查询秒级返回、高效的Rollup预聚合。

StarRocks的设计亮点在于CBO优化器和一套自研的向量化执行引擎,复杂join的性能相比传统的MPP系统有明显提升,加上支持外表联邦查询,可以直接查Hive表、Iceberg表等湖上数据,所以它在湖仓一体场景里非常受欢迎。Doris同样定位在"实时数仓加湖仓一体",社区活跃度高,很多互联网公司拿它做用户行为分析、BI加速引擎和实时报表的平台底座。

如果你的场景是"希望从数据产生到报表可见的延迟控制在秒级到分钟级,同时又要能支撑复杂多维分析",新一代MPP数据库大概率比传统MPP和ClickHouse更顺手。不过它们也各有取舍,比如对超大结果集的深度复杂关联、对事务的支持,还是要看具体版本和场景。

下面把几类平台的核心差异摆在一起,方便快速对照:

平台架构内核优势场景主要限制典型用户
Teradata传统MPP一体机金融、电信核心数仓成本极高、生态封闭大型政企
GreenplumPostgreSQL内核MPP离线数仓、复杂SQL分析不适合高并发、调优复杂中型以上数据团队
ClickHouse列式存储+分布式分片日志分析、单表聚合、实时分析多表join弱、事务弱互联网、可观测性平台
StarRocks/Doris新一代MPP+向量化实时数仓、湖仓一体、高并发查询生态还在成熟期互联网、新零售、BI平台

4. 选型决策与部署调优的实操要点

4.1 三个关键问题帮你快速做MPP选型

选型这件事,最怕的是盲目跟风,看别人上了MPP自己也上,结果做出来的架构和业务场景完全不匹配。我一般会建议团队先用三个问题筛一遍。

数据量到底有多大?全表扫描一次要扫多少GB?如果数据总量在几百GB以内,单机数据库加上合适的索引、分区和归档策略大概率够用,没必要上MPP,MPP的运维成本和复杂度对小型团队来说是负担。一旦过了TB级别,或者数据增长速度很快,3到6个月内就会突破单机处理能力边界,那时候就需要MPP打底。

查询的复杂度和时延要求是怎样的?每天最重的那几条查询要跑多久?如果重的是一条涉及四五个表关联、做十几个维度聚合的报表类SQL,MPP是合理选择;如果主要场景是按键查一行、要毫秒级返回的在线查询,MPP并不擅长,不如用单机数据库或键值存储。如果查询靠的是提前聚合好的预计算结果,而不是现场算,那可能物化视图和OLAP缓存才是正解。

团队有没有能力承接MPP的运维?开源MPP系统的部署、备份、调优、故障排查,都需要专门的技能积累。比如Greenplum的镜像配置、节点替换、资源队列设置,做不好就会成为一种负担。没有专职数仓工程师的团队,我更建议优先考虑云厂商的托管MPP服务,用云服务商替你把底层运维扛下来,把精力花在数据建模和业务分析上。

4.2 部署时几个最容易拍脑袋犯的配置错误

MPP部署的细节非常影响最终性能,这里分享几个实践中经常踩的坑。

节点数量不是越多越好。计算节点多了,并行度确实提升,但协调节点的合并开销、网络交换机带宽的争抢也会加剧。一个常见的经验是:节点的单核性能和内存容量先满足单节点查询的合理内存预算,再去考虑加节点。比如单条大查询涉及排序或哈希聚合,每个节点至少要能容纳2到4GB的算子工作内存,节点内存太小,就算加了节点也会频繁发生落盘。

分布键的选择绝不能不调研就拍板。建表时分布键一旦选错,后面改起来成本极高,因为要重建整张表。分布键的选择标准前面说过,要高频关联列、高基数列、避免热门值倾斜。我亲眼见过一张订单表用订单状态作分布键,结果某几个状态的订单量占了90%,那90%的数据全堆在少数几个节点上,查询速度惨不忍睹。

分区策略要和分布键配合起来。分布键解决的是数据在节点间的均匀分散,分区解决的是每个节点内部数据的裁剪能力。比如一张按日期分区的日志表,每天一个分区,查询只扫最近7天,那么每个节点都能借助分区裁剪把扫描量缩小到原来的一小部分。分区键和分布键是两个维度的优化,不要搞混。

表关联时要有意识地让小表广播或复制。某些MPP系统对大小表关联有自动优化,CBO在估算成本后会自动选择广播小表或重分布大表。但有些情况优化器会估错,这时候就要靠人工修改会话参数或给表添加复制分布来强制走最优路径。这类优化需要结合explain查看执行计划来逐一确认。

5. 常见故障排查实录与调优心得

5.1 数据倾斜的定位方法

数据倾斜是最典型也最让人头疼的MPP问题,表现为集群里有一个节点CPU打满、磁盘IO拉满,其他节点都在摸鱼,整个查询的耗时被拖到某个节点的处理能力上。排查思路很简单:先确认是不是分布不均匀。

在Greenplum里可以直接执行select gp_segment_id, count(*) from 表名 group by gp_segment_id查看数据分布情况。正常情况下每个段的行数应该大致接近,如果某几个段明显比其他段多出数倍,就是分布键选得不合适。这时候需要回看表定义和业务数据特征,换一个基数字段做分布键,或者考虑在分布键上再加一个盐值列做组合键来打散热点。

还有一种数据倾斜是运行时产生的。两个表join时,如果关联键的热门值在某个维度上特别集中,即使建表分布是均匀的,重分布阶段仍然会有部分节点承担更多数据。这种情况需要从SQL层面解决,比如把热门的那个key单独拆出来处理,或者对倾斜值做加盐改造,让计算能平均分摊到所有节点。

5.2 网络交换瓶颈与关联重分布优化

MPP查询慢的第二大原因是网络传输量太大。两个大表关联时,如果关联键不是两张表的分布键,系统必须在执行计划中插入一个重分布节点,把两边的数据都按关联键重新哈希,通过网络发送到目标节点。这一下就要传输两张表的数据量,网络很容易成为瓶颈。

排查方法是用explain看执行计划里的Motion节点数量。Motion是Greenplum这类MPP系统里做跨节点数据传输的算子,Motion越多、传输的数据量越大,查询越慢。优化手段通常有两个方向:一是从根上避免Motion,让两表的分布键与关联键保持一致,这样关联全部落在本地节点;二是无法避免时尽量把其中一个表做成复制表,用一次广播替代全量重分布,网络传输量能下降一个数量级。

实测中一个典型的优化案例:两张各几十亿行的大表按日期关联,两张表原本都用用户ID做分布键,每次关联都要重分布。后来把日期字段加进两表分布键的维度里重新设计分布策略,将关联键改为分布键之一,重分布Motion直接消失,查询从40多秒降到6秒。多数的MPP性能问题,追到底都是"不该搬的数据在搬"。

5.3 资源竞争与小查询拖垮大查询

随着集群上跑的查询越来越多,另一个高频问题是资源竞争。如果没做资源管控,大查询会把所有节点的内存和CPU全部占满,小查询只能在后面排队,整个集群的响应速度会变得非常不稳定。尤其是有夜间批量任务和白天报表查询混跑的场景,这个问题格外突出。

解决方案是把集群的资源分成多个资源队列。比如给ETL批处理队列分配70%的资源,给在线报表队列分配20%,给临时查询队列分配10%,并对每个队列设置并发限制。大查询在批处理的队列里跑,报表查询走自己的队列,各管各的,不再互相干扰。这个设计和操作系统的进程优先级管理思路其实是同一回事,把有限的计算资源按重要程度隔离开。

实际配置时注意队列的CPU使用权限和内存使用上限要同时设置,只限并发不限内存,照样会出现内存被大查询耗尽的情况。不同MPP厂商的资源管理接口不一样,Greenplum用resource queue和resource group,Doris用Workload Group,ClickHouse用自定义查询限流,原理都是同一套,找到对应文档做配置即可。

5.4 常见问题速查表

现象可能原因快速排查思路
某个节点CPU/磁盘异常高分布键倾斜,热点数据集中按节点ID统计行数分布,确认是否均匀
关联查询特别慢关联键与分布键不一致,触发重分布查看执行计划Motion节点数量,评估传输量
大查询频繁落盘算子内存不足,并行度设置过高调低statement内存并行度,或增加节点内存
集群整体响应不稳定大查询抢占全部资源配置资源队列,隔离批处理和在线查询
查询结果返回慢但各节点正常协调节点成为合并瓶颈检查结果集大小,增加协调节点资源或优化SQL减少返回量
数据写入后查询不到副本同步延迟或写入段失败查看集群状态和副本同步进度,必要时执行平衡操作

这一套排查下来,百分之八九十的性能问题都能定位到根源。做MPP运维最忌讳的是看见慢就盲目加节点,不动SQL不动分布策略,节点加得再多,倾斜问题还在,该慢照样慢。

我自己这一段实践下来最大的体会是:MPP不是拿来即用的银弹,它是一个需要理解和经营的系统。能不能发挥出它应有的性能,很大程度上取决于前期建模设计是否扎实、有没有把分布键和分区想透、有没有对执行计划保持敏感。更重要的是,要清楚它应该站在你技术体系里的哪个位置,解决哪一类问题,用什么标准去衡量它做得好不好。这篇先把概念和架构的底子打好了,接下来几篇我打算沿着真实项目里的建模、调优和迁移案例逐一展开,把那些文档里不会写得太细的经验拿出来拆开聊。

返回列表