☰
OLAP架构分类详解:MPP、预计算Cube、弹性SQL与搜索分析
2026/10/28 4:50:26 网站建设 项目流程

1. 先搞清楚:OLAP架构分类到底在分什么

1.1 从一次选型争论说起

前阵子有个做电商中台的朋友跑来问我,说他们准备上一套报表分析系统,结果团队内部吵起来了。有人坚持用ClickHouse,理由是“大家都说快”;有人想上Doris,觉得“能支持实时场景”;还有人说干脆直接上Elasticsearch,因为“日志检索和聚合都能干”。吵到最后发现,大家连“OLAP架构”这个词都没对齐——ClickHouse和Doris都属于MPP架构,Elasticsearch是搜索式分析架构,和Kylin那种预计算Cube架构完全是两码事。架构类型没搞清楚,选型自然就变成了各说各话。

这个话题其实特别典型。我在做技术咨询的时候发现,很多团队对OLAP架构的理解停留在“某个开源产品”上,而不是从“架构类型”的维度去思考问题。但架构类型恰恰是最重要的那层决策——它决定了你的查询延迟天花板、并发能力、数据新鲜度、扩展方式,甚至决定了你的运维成本到底是多少。这篇文章我就把OLAP架构的类型完整梳理一遍,从最经典的MOLAP、ROLAP、HOLAP分类讲起,再讲现在主流的MPP、预计算Cube、弹性SQL引擎和搜索式分析架构,最后结合真实场景说说怎么选型、怎么排坑。

1.2 三种经典实现:MOLAP、ROLAP、HOLAP

OLAP这个概念从上世纪90年代提出以来,最经典的架构分类就是按照数据存储和处理方式分成三种:MOLAP、ROLAP和HOLAP。这个名字现在听的人少了,但底层思路到今天仍然在影响各种现代引擎的设计。

**MOLAP(多维OLAP)**的核心是“预计算”。它把数据预先按照多维模型做聚合,结果存成Cube(数据立方体)的形态。你查询的时候不需要去扫原始明细数据,而是直接查已经算好的聚合结果。典型代表是早期的Essbase、Microsoft Analysis Services,以及现在的Apache Kylin。MOLAP最大的优点是查询极快,秒级甚至毫秒级返回,特别适合固定维度的BI分析;缺点也明显——预计算需要时间,数据新鲜度差,而且维度一旦多起来,Cube可能膨胀得非常夸张,构建任务会失败。

**ROLAP(关系型OLAP)**的思路正好相反。它不强求预聚合,数据还是存在关系型数据库或者数据仓库里,查询的时候动态执行SQL去聚合计算。好处是灵活性极高,想怎么查就怎么查,数据实时性好;坏处是性能完全取决于底层数据库的处理能力,如果在海量数据上做复杂的多表关联聚合,响应时间会很感人。传统数仓里的报表查询,很多就是ROLAP的形态。

**HOLAP(混合OLAP)**是前两者的折中。常见做法是高频维度的聚合结果走预计算,低频或长尾维度的查询走明细动态聚合。这样既保证了大部分查询的响应速度,又不至于让所有组合都预计算导致爆炸。Kylin在2.x之后支持的“明细查询”和部分预聚合结合的方式,其实就有HOLAP的味道。

1.3 经典分类的局限在哪

经典分类在理论上很清晰,但放到今天的生产环境里,你会觉得这三个词有点“不够用”。原因在于它只回答了“数据怎么存、聚合怎么算”,却没有回答更关键的工程问题:数据分布在多少台机器上?查询是不是并行执行的?计算资源和存储资源是不是绑定的?所以你会发现,ClickHouse、Doris、Greenplum这些产品很难简单归类到MOLAP或ROLAP里,它们的数据按分片存储,计算时在每个节点本地并行执行,然后汇总结果——这种架构叫MPP(Massively Parallel Processing,大规模并行处理)。业界讨论OLAP架构的时候,现在更多是按计算引擎的分布式形态、存储模型、部署方式来划分。这也是我接下来重点要展开的部分。

我的建议是:经典的MOLAP/ROLAP/HOLAP不要丢掉,它仍然是理解预聚合、明细查询、混合策略这些核心概念的钥匙;但选型的时候,一定还要把分布式架构这个维度加进来,才不会被产品宣传带偏。

2. 按计算引擎和分布式形态划分的四种主流架构

2.1 MPP架构:ClickHouse、Doris这类“真分布式”引擎

MPP架构是当前OLAP领域最主流的一类,几乎所有你叫得上名字的新一代分析型数据库都属此类:ClickHouse、Doris、StarRocks、Greenplum、Impala……它们的基本设计逻辑是Shared-Nothing(无共享架构),每个节点拥有独立的CPU、内存和磁盘,数据按某种规则分片分布到各个节点上。查询下发到所有节点并行执行,最后汇总结果。大家常说的“分布式架构”在生产环境里指的大概率就是这种形态。

ClickHouse的分片加副本机制是理解MPP架构的好例子。分片解决的是“数据太多一台机器装不下”的问题,把数据按随机、哈希或者自定义规则拆到多个分片;副本解决的是“机器挂了怎么办”和“并发查询能力不够”的问题,每个分片的数据复制几份。但实际部署的时候你会发现,ClickHouse的分布式表更多是面向“数据本地化扫描”优化——尽量让每个节点只扫自己本地的那部分数据,避免跨节点传输。这也就解释了为什么ClickHouse的单表大宽表分析性能极强,但跨表Join能力相对弱,因为Join一旦涉及重分布数据,网络传输代价就上来了。

Doris和StarRocks在MPP基础上多做了一层优化:它们支持更灵活的分布式Join。查询执行器会把小表广播到所有节点,大表数据保持本地,这样避免了一部分数据Shuffle的开销。同时它们内置了Rollup表和多种数据模型(明细模型、聚合模型、唯一模型),某种程度上是把MOLAP的预聚合思路做成了“可选的物化视图”,让用户可以在“明细查询”和“预聚合加速”之间自己权衡。

2.2 预计算Cube架构:以Kylin为代表的“空间换时间”

预计算Cube架构和MPP完全是两种逻辑。MPP强调的是“算得快”,所有的聚合都发生在查询时;预计算Cube强调的是“尽量别算”,把要查的结果提前算好存起来,查询时就是查个结果。Apache Kylin是这类架构最知名的开源代表,它的整体思路是把Hive、Kafka里的数据按照维度建模,预先构建成Cube,存储在HBase或者对象存储上。

为什么Kylin能在百亿、千亿级数据上做到秒级查询?因为它把代价前置了。你知道业务要按哪些维度组合来分析,就提前把这些组合的聚合结果算出来。查询的时候,命中哪个Cuboid就取哪个Cuboid的结果,走的是点查或者小范围扫描,而不是把大量的明细数据读一遍再聚合。本质上就是拿存储空间换查询时间,拿构建时间换查询效率。

但预计算Cube有一个绕不开的老大难:维度爆炸。如果一张表有10个维度,理论上就会有2的10次方也就是1024种维度组合,每个组合都可能对应一份聚合结果。维度再增加,数据量再膨胀,Cube构建就可能跑几个小时甚至失败。这也是为什么Kylin适合“固定分析模型”的场景,却不太适合“任意维度即席查询”的场景。另外Cube构建有延迟,通常小时级甚至天级,数据新鲜度比不上MPP架构。

2.3 弹性SQL引擎架构:Presto/Trino这类“联邦查询”

还有一类架构在选型中经常被忽略,但实际出场率极高,就是Presto/Trino这类分布式SQL查询引擎。这类引擎有个显著特点:它自己基本不存数据,数据放在HDFS、对象存储、Hive表、Iceberg表或者各种外部数据源里,引擎负责把SQL拆解成分布式任务,并行去各个存储位置读取数据,然后把结果汇总返回。你可以把它理解成一个“计算层”,与底层的存储彻底解耦。

这种架构最大的价值是灵活。你想跨多个数据源做联邦查询?Presto可以一个SQL同时查MySQL、Hive和对象存储上的文件;你想分析数据湖里的数据?Trino是Lakehouse架构里最常用的一层。计算层可以独立扩缩容,查询高峰时多挂几个节点,低峰时缩回来,成本控制非常灵活。但它也有明确的短板——因为没有本地数据,每次查询都涉及大量的远程IO,尤其是从对象存储上扫描大量列时,延迟会明显高于把数据本地化的MPP引擎。所以它更适合Ad-hoc分析、数据探查、湖上分析,而不是高并发的固定报表场景。

2.4 搜索分析引擎架构:Elasticsearch怎么把OLAP做轻量

很多人一听到Elasticsearch就想到全文检索,不会把它和OLAP联系起来。但实际上,在你需要快速筛选大量数据并做聚合统计的场景里,Elasticsearch被广泛用作一种“轻量级OLAP”引擎,尤其在日志分析、可观测性、安全分析领域,它的出镜率非常高。这也是为什么热词里会有“elasticsearch实现olap”这样的搜索关键词。

Elasticsearch做OLAP的底层逻辑可以总结成两条:倒排索引负责快速过滤,列式存储的doc_values负责高效聚合。比如你在几十亿条Nginx访问日志里查“最近24小时某个接口的P99延迟趋势”,如果只是扫原始日志,可能要几分钟;但有了倒排索引先筛出这个接口的日志,再用doc_values按时间分桶做聚合,往往几秒钟甚至更短就能返回结果。它的分布式能力来自分片机制,数据被分成多个分片分散到不同节点,查询时各分片并行计算再合并。

不过要清楚它的边界:Elasticsearch处理的是“尽量扁平、字段明确的半结构化数据”,如果你需要做大宽表上的复杂多表关联、精确的跨表汇总,或者需要频繁的Update/Delete,那它就不合适了。它的定位是搜索式分析,而不是全能型分析数据库。

架构类型核心思路代表产品优势劣势典型场景
MPP数据分片、并行计算ClickHouse、Doris、StarRocks、Greenplum查询性能强、数据新鲜度高Join和并发有一定限制实时报表、用户行为分析、大宽表分析
预计算Cube空间换时间、提前聚合Kylin、早期Druid超大结果集秒级返回维度爆炸、构建延迟、灵活性差固定BI看板、千亿级核心指标分析
弹性SQL引擎计算与存储解耦Presto、Trino灵活、跨源联邦查询、存算分离远程IO开销大、不适合高并发Ad-hoc分析、数据湖查询
搜索分析倒排索引加列存聚合Elasticsearch、OpenSearch过滤和聚合结合好、适合日志复杂关联弱、更新代价大日志分析、可观测性

3. 部署形态与架构演进的另一条主线

3.1 传统数仓到实时数仓

除了引擎内部的架构差异,OLAP系统在整体部署形态上也在持续演进。最早的分析场景直接跑在传统的单机数据库上,Oracle、SQL Server扛大旗,报表都在上面跑。但随着数据量涨到TB、PB级别,单机数据库的容量和算力都扛不住了,于是有了第一代分布式数仓,比如Teradata、Greenplum,基本思路还是MPP,但部署形态从“一台大机器”变成了“一堆机器组成集群”。

到了大数据时代,Hadoop生态的Hive把分析能力建立在HDFS批量扫描之上,解决了海量数据存储的问题,但延迟也上来了,跑一个查询几分钟甚至几十分钟都很正常。此时实时性需求又在倒逼架构改造,于是出现了“实时数仓”的概念——典型架构是:业务数据通过Kafka等消息队列接入,Flink做实时计算,结果落到OLAP引擎(通常是MPP类)供查询。这条链路把数据从“T+1才能看到”变成“秒级甚至毫秒级可见”。我见过不少团队从“Hive背着跑报表”演进到“Flink加Doris支撑实时大屏”,体验上完全是两个时代。

3.2 Lambda与Kappa:实时链路的两套流派

实时数仓建设过程中,有两条经典的架构路线绕不开,就是Lambda和Kappa。很多刚接触的人会问,这不是流处理框架吗?为什么说是OLAP架构的一部分?原因是这两套架构决定了OLAP引擎里的数据是“只有离线批算出来的结果”,还是“流算出来的结果”,以及两套结果怎么合并、怎么保证一致性。

Lambda架构是“离线批处理加实时流处理”双链路。离线层负责全量数据和精确计算,产出准确的结果;实时层负责处理增量数据,尽快产出低延迟的结果;查询时把两边的结果合并。这套架构至今还有很多公司在用,原因是很稳、很成熟。但它的问题也众所周知:需要开发和维护两套代码,批量层和实时层的结果还可能对不上,排查问题的时候非常痛苦。

Kappa架构的出发点就是“不要搞两套”,所有数据统一走实时流处理,处理逻辑只有一套,需要重算历史数据时,就从Kafka等消息队列里重新消费一遍数据来重放。这样省掉了离线批处理链路,逻辑简单很多。但它的前提是消息队列能完整保存历史数据,而且重放海量数据本身耗时,所以实践中很多团队是“Kappa为主,辅以必要的历史快照”。现在Flink加Paimon这一类“流批一体”的方案,其实就是在解决Lambda和Kappa之间的取舍问题,让一套引擎既能跑流也能跑批,这套思路越来越受关注。

3.3 云原生OLAP与湖仓一体

再往新的方向看,云原生与湖仓一体是OLAP架构的两大趋势。云原生OLAP最核心的特征是存算分离。传统MPP架构里,计算节点和存储节点是绑定的,你扩容计算资源就得顺带扩容存储,成本不灵活;云原生架构则把数据放到对象存储(S3、OSS这类)上,计算层做成无状态集群,需要多少计算资源就拉起多少节点,用完缩回,按量计费。Snowflake是这套架构的标杆,BigQuery、RedShift Spectrum、各种云厂商的Serverless数仓也都遵循这个思路。

湖仓一体的提出,是因为“数据湖便宜、数仓好用”这个矛盾长期存在。数据湖(比如HDFS或者对象存储上加Iceberg/Hudi/Paimon表格式)可以以低成本存放海量任意格式的数据,但早期缺少数仓的ACID事务、索引、优化能力;数仓能力强,但存储和计算绑定,扩容成本高。湖仓一体就是要在湖的存储之上提供仓的管理能力——用表格式存储统一元数据和事务机制,再用Trino、Doris、Spark等引擎做分析。这样一份数据既能跑BI报表,又能被机器学习任务直接读取,少了复制和搬迁的过程。

4. 实际选型:面对业务需求怎么切到具体架构

4.1 先回答四个问题再选型

聊完了架构类型,最实际的还是落到选型。我的经验是不要一上来就问“哪个产品最好”,而是先回答四个问题。

第一,数据规模有多大、增量有多快?千万级和百亿级,选型策略完全不同;每天新增几万条和每天新增几亿条,对写入链路的要求也不同。第二,查询模式是什么样的?是固定报表为主,还是即席查询为主?是几十个并发的高频看板,还是每天几十次的深度分析?第三,数据新鲜度要求多高?T+1就够,还是有实时大屏的要求?需要分钟级还是秒级可见?第四,团队手里有什么技术栈,能不能交付出这套系统的运维?再好的架构,团队没能力维护也是坑。

这四个问题基本能把架构类型筛出来。比如固定BI看板、指标固定、数据量又特别大,Kylin这类预计算架构就很有优势;而如果团队要的是灵活即席分析、数据又要高时效,那MPP型引擎几乎是必选项;如果你只是想在日志暴涨的时候能快速检索聚合,那Elasticsearch比专门上OLAP数据库更对症。

4.2 一套可复用的POC对比路径

选型光看资料不行,必须做POC(概念验证)。我自己归纳了一套相对标准的流程,你可以直接拿去用。

先准备一份能够代表真实业务的数据集,不要用那种只有几万行的测试数据,那没有意义。数据量至少要达到真实数据的十分之一,最好有典型的维度字段、时间字段和多个度量值字段。再准备一组标准查询集,至少包含三类:单表聚合查询(按时间、维度分组求sum、avg、count)、多表关联查询、明细过滤加排序分页查询。每个查询都要记录并发数、响应延迟、资源消耗。

然后先用默认配置把各候选引擎跑一遍,观察哪个引擎在默认配置下就表现良好。再针对每个引擎分别做优化,比如调整分片数、开物化视图、优化表模型,再跑一轮。比较的时候不要只看快慢,还要看优化过程复不复杂、优化后稳定性如何。见过很多团队POC时只看ClickHouse大数据量Scan快,忽略了它在高并发小查询上的短板,上生产之后连接数一高就各种超时。这个坑很常见。

最后一定要把运维成本算进去。这套系统装完以后,谁来负责升级、监控、扩容、数据均衡?出了问题团队要花多久定位?有时候架构选型不是选“最强的”,而是选“团队能稳定玩得转的”。

4.3 一个综合架构的参考模板

实际生产里,我接触到的很多中大型团队并不追求用一套引擎解决所有问题,而是走“组合架构”路线。可以参考这个模板:数据源通过Canal监听业务库变更,或者直接接入Kafka;实时链路用Flink做清洗加工,明细和汇总结果写入Doris或StarRocks;离线T+1链路用Spark跑批,结果落到Hive表或者Iceberg表;同时在数据湖上挂一个Presto/Trino提供跨源联邦分析和Ad-hoc查询;另外日志类的数据全部进Elasticsearch,给监控和排障用。

这套组合虽然看上去“组件很多”,但每个组件都只干自己最擅长的事,整体可控。Doris负责高并发的线上报表,Presto负责灵活分析,ES负责日志检索,避免了一个引擎被塞进太多不同负载导致谁也不讨好。当然,数据一致性要靠数据同步任务来保证,这也是组合架构里运维上比较重的部分。少一点规模的团队可以砍掉一两个组件,比如直接用Doris做明细加汇总,把ES降级成可选项。

5. 架构落地中的常见问题和排查实录

5.1 数据倾斜:MPP架构的头号杀手

MPP架构里数据倾斜几乎是最常见的问题。表现是:某个查询明明有几十台节点在跑,但总是要等一个“慢节点”完成之后才返回,整个查询的时间等于那个节点的时间。原因通常是分桶键选择不当,比如按用户ID分桶,但少数大客户的数据量占了全表的30%以上,那有大量中小客户数据的节点早就跑完了,大客户所在的节点还在慢慢啃。

排查手法很直接:看查询计划里各节点的扫描行数和处理时间,如果某一个节点的行数明显高出平均好几倍,就是倾斜了。解决办法可以从几个方向试:一是改分桶键,换成基数更均匀的字段;二是把大KEY单独抽出处理,倾斜的那部分数据单独走一个查询路径;三是调整Join策略,把大表改成广播小表或者用随机分桶来避免某个节点堆积。我在实际项目里见过最严重的一次,一个查询从30秒优化到2秒,问题根源就是分桶键从用户ID换成了用户ID加时间字段。

5.2 Cube构建失败与膨胀

如果你用的是Kylin这类预计算架构,最容易遇到的问题就是Cube构建失败,或者构建出来的存储膨胀到不可控。之前有个客户,业务表有16个维度,构建的时候经常跑到一半就报错。后来一看,维度组合数已经是几百万级别,单个Cuboid的数据量又大,整体构建工作量超出集群能力。

建议在建Cube之前先做两个动作:一是精简维度,把业务上不可能的维度组合在Cuboid计划里排除掉;二是对高基数维度做裁剪,比如用户ID这种维度,除非必须下钻到单用户,否则优先按用户分组聚合来设计。另外可以设计多个不同覆盖范围的Cube,核心指标用一个高预聚合程度的Cube,长尾分析用另一个轻量Cube兜底。做了这两步之后,构建时间基本都能从几个钟头降到半小时以内。

5.3 高并发扛不住

高并发是OLAP架构里另一个绕不开的痛点。尤其是ClickHouse这类“单查询很快但并发一高就发飘”的引擎,明明延迟才几十毫秒,一千个并发一上来,直接CPU打满,查询排队,P99飙到几秒钟。原因在于底层向量化执行会尽量把CPU资源吃满,但查询线程的调度和连接管理没有为高并发做专门的优化。

解决思路一般有三层:第一层是在前面加一个查询网关或者缓冲层,对查询做排队、限流、超时控制;第二层是通过物化视图、预聚合或者结果缓存降低底层引擎的计算压力;第三层是调整引擎参数,比如限制一个查询的最大内存、最大线程数,让更多查询能并行跑起来。如果并发要求真的很高,再加副本数量分摊查询流量。需要注意的是,加副本对写入链路有压力,副本越多,写入同步的负载越高,这需要你根据写入和查询的比例做平衡。

5.4 实时链路延迟抖动

实时数仓链路最容易出问题的不是OLAP引擎本身,而是“数据进不来”。最常见的是Kafka消费堆积和Flink的反压。有一次排查一个报表数据延迟2小时的问题,最终定位到是上游业务库有一条慢SQL导致Canal同步产生了延迟,Kafka里的数据没进来,后面的OLAP引擎“无米下锅”。所以做实时链路,头部指标最好都要监控起来:Kafka的lag、Flink的checkpoint耗时、同步任务的延迟,任何一个环节出了瓶颈,都应该第一时间报警。

排除链路瓶颈之后,还要注意OLAP引擎的写入优化。比如Doris的实时导入如果小批量高频提交,会生成大量的小文件(Segment),影响后续查询性能。一般建议攒批写入,比如每5秒或者每攒了一定条数再批量提交,并且合理设置Compaction策略,让后台合并跑得及时。这个细节如果你不主动控制,等上线三个月后再处理小文件问题,就得花大量时间做数据整理。

5.5 存算分离下的小文件与IO开销

云原生和湖仓一体架构下,最被人忽略的问题是对象存储上的小文件。数据从Flink流式写入到Iceberg或者Hudi表时,如果不加控制,会不断产生大量的小数据文件,查询引擎每次扫描都要打开成百上千个文件,IO开销直接爆炸。我自己测过同样一个查询,小文件多的时候耗时可能是合并压缩后的5倍以上。

解决办法是依赖表格式自带的Compaction机制,比如Iceberg的Compaction任务定期把小文件合并成大文件;或者在下游写数据前做一轮攒批,减少写入次数。另外建表时的分区粒度也要控制好,分区太细(按小时甚至按分钟)也会制造大量小目录,扫描时多级目录遍历会拖慢整体性能。合理的方式是按天或按周分区,既有时间裁剪的好处,又不至于目录过碎。

关于排查,我最想强调的一点是:OLAP链路的性能问题很少能靠单一组件解决,一定要把“数据从哪里来、在哪里加工、最终存在哪里被查询”整条链路都拉出来看。建议一开始就在每个环节埋好指标,宁可多采集一些数据,也不要等出问题的时候像个没头苍蝇一样到处翻日志。我自己踩过太多这方面的亏了。

最后再分享一点经验

回到最开头那个选型争论,我想说的是:OLAP架构类型没有绝对的好坏,只有合不合适。经典的三分法(MOLAP、ROLAP、HOLAP)帮我们理解数据计算的基本手段,MPP、预计算Cube、弹性SQL引擎、搜索式分析帮我们理解分布式系统的工程取舍,云原生和湖仓一体则代表了存储与计算关系的变化方向。把这些维度都装进脑子里,再去面对“ClickHouse还是Doris”“要不要上Kylin”“ES能不能当数仓用”这类问题,你就能从底层逻辑出发判断,而不是被别人的经验或者厂商的宣传带着走。

我个人的习惯是,每次启动一个数据分析项目,第一周什么代码都不写,先把架构理解的讨论和POC方案定下来。这个时间投入非常值得——架构一旦定错,后面所有表结构设计、同步链路、查询优化都要跟着返工,那种代价比任何一次“多花一周讨论”都要大得多。如果你也在做类似的选型,建议带上一份真实业务的查询集,拿几个候选引擎分别跑一遍,再做决定。纸上谈兵终归没有实测来得靠谱。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询