订阅更新

面试官问OLAP引擎,你只说'查询快'就完了?——Doris架构和MPP原理

Doris手册 第 1 题 约 10 分钟读完

本文目录
  1. 先说结论
  2. FE和BE的角色分工
  3. MPP架构为什么快?——和MapReduce的本质区别
  4. 列式存储为什么适合分析查询?
  5. 实战经验:我在某元宇宙社交公司的Doris部署
  6. 面试高频追问
  7. 实战踩坑:BE内存不够导致大查询失败
  8. 总结

先说结论

Doris是一个基于MPP架构的实时分析型数据库。核心由FE(前端节点,负责SQL解析、查询规划、元数据管理)和BE(后端节点,负责数据存储和查询执行)组成。数据按列存储、分区分桶分布在多个BE节点上,查询时所有BE并行计算,汇总结果返回。

面试答架构要讲清楚三个层面:① 宏观架构(FE+BE的角色和协作);② MPP为什么快(和MapReduce的区别);③ 列式存储为什么适合分析查询。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

面试官问Doris架构,不是让你说'FE和BE两个组件'就完了。他想听的是:MPP架构为什么快?和Hadoop MapReduce有什么本质区别?FE和BE分别干什么、怎么配合?你们生产环境怎么部署的?我在某元宇宙社交公司从0搭建Flink+Doris实时数仓,从选型到部署到调优都亲手做过,今天把Doris架构讲透。

FE和BE的角色分工

Doris的架构非常简洁,只有两种节点,没有外部依赖(不需要HDFS、ZooKeeper),这也是它运维简单的核心原因之一:

# Doris集群架构
#
#  客户端(MySQL协议)
#      ↓
#  ┌──────────────────────────┐
#  │  FE 集群(Frontend)     │
#  │  ┌────┐ ┌────┐ ┌────┐  │
#  │  │ FE │ │ FE │ │ FE │  │  ← Master + Follower + Observer
#  │  │Lead│ │Fol │ │Obs │  │  ← 元数据管理、SQL解析、查询规划
#  │  └────┘ └────┘ └────┘  │
#  └──────────────────────────┘
#      ↓ 分发查询计划
#  ┌──────────────────────────┐
#  │  BE 集群(Backend)      │
#  │  ┌────┐ ┌────┐ ┌────┐  │
#  │  │ BE │ │ BE │ │ BE │  │  ← 数据存储 + 查询执行
#  │  └────┘ └────┘ └────┘  │
#  └──────────────────────────┘
组件角色核心职责部署建议
FE Master主节点元数据写入、查询规划、协调1个(高可用配3个FE)
FE Follower从节点元数据同步、可做查询入口2个(和Master组成3节点高可用)
FE Observer观察者只读元数据、分担查询压力按需添加
BE计算+存储节点存储数据、执行查询计划≥3个(和数据量成正比)

关键特点:① 兼容MySQL协议——用MySQL客户端就能连,DBA和业务同事零学习成本;② 没有外部依赖——不需要HDFS、ZooKeeper、YARN,部署和运维极其简单;③ FE的元数据用Raft协议同步(类似KRaft),保证高可用。

MPP架构为什么快?——和MapReduce的本质区别

MPP(Massively Parallel Processing,大规模并行处理)是Doris快的核心原因。面试官最喜欢问的追问就是:MPP和MapReduce有什么区别?

维度MPP(Doris)MapReduce(Hive/Spark)
执行模式所有节点同时计算,流水线式传输按Stage串行执行,Shuffle落盘
中间数据内存中流式传输,不落盘Shuffle必须写磁盘再读取
查询延迟秒级到亚秒级分钟级到小时级
适合场景交互式即时查询大规模批处理ETL
数据规模适合TB级别适合PB级别
容错性一个节点挂了整个查询失败Task失败可以重试

一句话总结:MPP是所有节点同时并行计算,数据在内存中流式传输;MapReduce是按Stage串行执行,中间数据要Shuffle落盘。MPP牺牲了一定的容错性和数据规模上限,换来了极致的查询速度。

# MPP查询执行过程(以Doris为例)
#
# SELECT country, SUM(amount) FROM orders GROUP BY country
#
# 1. FE收到SQL → 解析 → 生成分布式查询计划
# 2. FE把查询计划分发给所有BE节点
# 3. 每个BE并行扫描自己本地的数据分片
#    BE-0: 扫描Partition-0的数据,本地做GROUP BY聚合
#    BE-1: 扫描Partition-1的数据,本地做GROUP BY聚合
#    BE-2: 扫描Partition-2的数据,本地做GROUP BY聚合
# 4. 各BE的局部聚合结果通过网络汇总到一个BE
# 5. 汇总节点做最终聚合,返回结果给FE
#
# 全程数据在内存中流转,不落盘!
# 3个BE并行扫描,速度是单节点的约3倍

列式存储为什么适合分析查询?

Doris底层数据按列存储(Columnar Storage),这是OLAP引擎快的另一个关键原因。面试经常追问:列式存储为什么比行式存储快?

维度行式存储(MySQL)列式存储(Doris)
存储方式一行的所有列存在一起同一列的所有值存在一起
查询模式适合按主键查单行(OLTP)适合扫描某几列做聚合(OLAP)
IO效率查1列也要读整行所有列只读需要的列,IO大幅减少
压缩率不同列类型混在一起,压缩率低同类型数据压缩率极高(5-10倍)
写入模式单行插入快批量导入快,单行插入慢
-- 举个具体例子:一张有50个字段的订单表
-- 行式存储(MySQL):
--   SELECT SUM(amount) FROM orders WHERE dt = '2024-01-15'
--   需要读取整行50个字段的数据,即使只需要amount和dt两列
--   假设一行500字节,1亿行 = 50GB IO
 
-- 列式存储(Doris):
--   同样的查询,只读amount列(8字节)+ dt列(4字节)
--   1亿行 × 12字节 = 1.2GB IO
--   再加上列式压缩(通常5-10倍),实际IO约120-240MB
--   IO量是行式存储的1/200到1/400!
 
-- 这就是为什么同样的聚合查询
-- MySQL要跑30秒,Doris只需要0.5秒

实战经验:我在某元宇宙社交公司的Doris部署

在某元宇宙社交公司,我从0搭建了Doris集群,作为实时数仓的查询层。当时的部署方案:

集群规模:3个FE节点(1 Master + 2 Follower,保证高可用)+ 3个BE节点(每台32核128GB内存、2TB SSD)。

数据量:核心表约20张,最大的用户行为明细表日增5000万条,总数据量约2TB。

查询性能:实时大盘的聚合查询(UV/PV/GMV)平均响应时间800ms,复杂的多表JOIN查询在3秒内返回。相比之前用Hive查同样的数据需要几分钟,提升非常明显。

写入方式:Flink消费Kafka后通过Stream Load写入Doris,攒批1000条或5秒一批。写入吞吐稳定在5000条/秒以上。

面试高频追问

追问一:FE Master挂了怎么办?

如果部署了3个FE节点(1 Master + 2 Follower),Master挂了会自动通过Raft协议选举新Master,过程通常在秒级完成,客户端几乎无感知。如果只有1个FE就是单点故障,生产环境必须至少3个FE。Observer不参与选举,只分担查询压力。

追问二:Doris兼容MySQL协议是什么意思?

意味着你可以用MySQL客户端、JDBC驱动、Navicat等任何MySQL工具直接连接Doris。SQL语法也高度兼容MySQL。这对运维和业务同事非常友好——不用学新工具,用他们已经熟悉的MySQL客户端就能查数据。我们团队的产品经理和运营同事都是直接用Metabase连Doris看数据的。

追问三:MPP架构的最大缺点是什么?

两个主要缺点:① 容错性差——一个BE挂了整个查询就失败了(MapReduce的Task失败可以重试);② 并发瓶颈——MPP的查询会用到所有节点,高并发时每个查询都抢所有节点的资源,容易互相影响。一般Doris的并发能力在50-100 QPS左右(复杂查询),高并发场景需要配合缓存或物化视图。

实战踩坑:BE内存不够导致大查询失败

在某元宇宙社交公司刚上线Doris的第一个月,有一次运营同事跑了一个没加WHERE条件的全表扫描查询(SELECT * FROM user_events),3个BE节点的内存全部打满,不仅这个查询失败了,还把其他人的查询全部拖慢了。

这就是MPP架构的特点——一个查询的执行涉及所有BE节点。一个重查询可以拖垮整个集群。

-- 解决方案:给Doris设置查询资源限制
 
-- 1. 设置单个查询的内存上限
SET exec_mem_limit = 4294967296;  -- 4GB
 
-- 2. 设置查询超时时间
SET query_timeout = 60;  -- 60秒
 
-- 3. 更好的方案:使用Resource Group(Doris 2.0+)
-- 给不同用户分配不同的资源配额
CREATE WORKLOAD GROUP 'analyst' 
PROPERTIES (
    'cpu_share' = '10',
    'memory_limit' = '30%',
    'max_concurrency' = '10'
);
-- 分析师的查询最多用30%内存,避免影响实时大盘

教训:MPP引擎必须做资源隔离。不同优先级的查询(实时大盘 vs 临时分析)要分到不同的资源组,避免互相影响。这个经验我后来带到了每一个用OLAP引擎的项目。

总结

Doris架构面试要讲清楚三个层面:① FE+BE的分工(FE管元数据和SQL解析,BE管存储和计算);② MPP为什么快(全节点并行+内存流式传输,不像MapReduce要Shuffle落盘);③ 列式存储为什么适合分析(只读需要的列,IO减少几百倍)。能结合实际部署经验说出集群规模、查询性能数字和踩过的坑,面试官就知道你是真正用过Doris的人,而不是背八股文。

下一篇聊Doris的数据模型:同一张表该选Duplicate、Aggregate还是Unique?选错了性能差10倍。

你们生产环境用的什么OLAP引擎?集群多大?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器