OLAP架构分类详解:MPP、预计算Cube、弹性SQL与搜索分析

OLAP架构分类详解:MPP、预计算Cube、弹性SQL与搜索分析 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、HOLAPOLAP这个概念从上世纪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里它们的数据按分片存储计算时在每个节点本地并行执行然后汇总结果——这种架构叫MPPMassively 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类供查询。这条链路把数据从“T1才能看到”变成“秒级甚至毫秒级可见”。我见过不少团队从“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 先回答四个问题再选型聊完了架构类型最实际的还是落到选型。我的经验是不要一上来就问“哪个产品最好”而是先回答四个问题。第一数据规模有多大、增量有多快千万级和百亿级选型策略完全不同每天新增几万条和每天新增几亿条对写入链路的要求也不同。第二查询模式是什么样的是固定报表为主还是即席查询为主是几十个并发的高频看板还是每天几十次的深度分析第三数据新鲜度要求多高T1就够还是有实时大屏的要求需要分钟级还是秒级可见第四团队手里有什么技术栈能不能交付出这套系统的运维再好的架构团队没能力维护也是坑。这四个问题基本能把架构类型筛出来。比如固定BI看板、指标固定、数据量又特别大Kylin这类预计算架构就很有优势而如果团队要的是灵活即席分析、数据又要高时效那MPP型引擎几乎是必选项如果你只是想在日志暴涨的时候能快速检索聚合那Elasticsearch比专门上OLAP数据库更对症。4.2 一套可复用的POC对比路径选型光看资料不行必须做POC概念验证。我自己归纳了一套相对标准的流程你可以直接拿去用。先准备一份能够代表真实业务的数据集不要用那种只有几万行的测试数据那没有意义。数据量至少要达到真实数据的十分之一最好有典型的维度字段、时间字段和多个度量值字段。再准备一组标准查询集至少包含三类单表聚合查询按时间、维度分组求sum、avg、count、多表关联查询、明细过滤加排序分页查询。每个查询都要记录并发数、响应延迟、资源消耗。然后先用默认配置把各候选引擎跑一遍观察哪个引擎在默认配置下就表现良好。再针对每个引擎分别做优化比如调整分片数、开物化视图、优化表模型再跑一轮。比较的时候不要只看快慢还要看优化过程复不复杂、优化后稳定性如何。见过很多团队POC时只看ClickHouse大数据量Scan快忽略了它在高并发小查询上的短板上生产之后连接数一高就各种超时。这个坑很常见。最后一定要把运维成本算进去。这套系统装完以后谁来负责升级、监控、扩容、数据均衡出了问题团队要花多久定位有时候架构选型不是选“最强的”而是选“团队能稳定玩得转的”。4.3 一个综合架构的参考模板实际生产里我接触到的很多中大型团队并不追求用一套引擎解决所有问题而是走“组合架构”路线。可以参考这个模板数据源通过Canal监听业务库变更或者直接接入Kafka实时链路用Flink做清洗加工明细和汇总结果写入Doris或StarRocks离线T1链路用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方案定下来。这个时间投入非常值得——架构一旦定错后面所有表结构设计、同步链路、查询优化都要跟着返工那种代价比任何一次“多花一周讨论”都要大得多。如果你也在做类似的选型建议带上一份真实业务的查询集拿几个候选引擎分别跑一遍再做决定。纸上谈兵终归没有实测来得靠谱。