Doris 架构与原理:从整体到细节

好,咱们正式开始聊 Doris 的架构。说实话,我第一次接触 Doris 时,最直观的感受就是——它把「简单」和「强大」平衡得特别好。你不需要理解一堆复杂的组件,就能搭起一套能用的数仓。但真要把它用好,底层那套机制还是得吃透。

这一章,我会从整体架构切入,然后拆开 FE 和 BE 这两个核心角色,再聊聊数据分片和副本机制,最后看一眼查询引擎是怎么跑起来的。嗯,咱们一步步来。

Doris 整体架构:一瞥全貌

Doris 的架构其实就两层:FE(Frontend) 和 BE(Backend)。没有复杂的中间件,没有额外的调度层。说白了,就是「一个大脑 + 一群工人」的模型。

  • FE:负责元数据管理、查询解析与规划、集群调度。它是整个集群的「大脑」。
  • BE:负责数据存储、计算执行、副本管理。它是干活的「工人」。

我习惯把 FE 比作「指挥官」,BE 比作「士兵」。指挥官不下场打仗,但每个士兵的行动都得听它指挥。这种分工让 Doris 的扩展性非常好——你可以加 BE 来提升计算和存储能力,也可以加 FE 来提升集群的元数据吞吐。

核心要点:FE 和 BE 之间通过 HTTP + Thrift 协议通信。FE 不参与实际数据读写,只负责「告诉 BE 该做什么」。

下面这张图,是我自己画的一个简化版架构。你看一眼,心里就有谱了。

Doris 整体架构图 Doris 整体架构 客户端(MySQL协议) FE(Frontend) 元数据管理 · 查询解析 · 集群调度 BE 1 数据存储 · 计算执行 副本管理 BE 2 数据存储 · 计算执行 副本管理 BE 3 数据存储 · 计算执行 副本管理 存储层(本地盘 / HDFS / S3) 数据持久化 · 冷热分层 说明:FE 负责调度,BE 负责执行。BE 之间可以互相通信,用于数据复制和负载均衡。 客户端只连接 FE,不直接操作 BE。

FE 与 BE 角色详解

FE:集群的大脑

FE 承担的工作其实挺杂的。我把它拆成三个核心职责:

  1. 元数据管理:所有库、表、分区、分片、副本的信息,都挂在 FE 的内存里。FE 挂了,集群就瞎了。所以生产环境一定要部署多个 FE,用 Paxos 协议做选主。
  2. 查询解析与规划:你发一条 SQL 过来,FE 先解析成语法树,然后生成执行计划,最后把任务分发给 BE。这个过程有点像「拆解任务」——把一个大查询拆成多个小任务,让 BE 并行干。
  3. 集群调度:哪个 BE 活着、哪个 BE 负载高、数据该往哪放,都是 FE 说了算。

我的经验:FE 的内存要管够。元数据全在内存里,表一多,内存就吃紧。我曾经遇到过 FE 因为元数据膨胀导致 GC 频繁,最后把 FE 堆内存从 8G 升到 16G 才稳住。

BE:干活的主力

BE 就简单多了——它只管两件事:存数据 和 算数据。

  • 存储:数据以分片(Tablet)为单位,存储在 BE 的本地盘上。每个 Tablet 对应一个目录,里面是列存文件。
  • 计算:收到 FE 下发的任务后,BE 在本地扫描数据、做聚合、做过滤,然后把结果返回给 FE 或直接返回给客户端。

你想想看,BE 其实是无状态的。它只负责「干活」,不关心「活是谁派的」。所以你可以随时加 BE 来扩展集群,FE 会自动把数据迁过去。

注意:BE 的磁盘配置要尽量一致。如果某个 BE 的磁盘特别慢,它会拖慢整个查询。我见过有人混用 SSD 和 HDD,结果查询延迟波动很大。

数据分片与副本机制

这部分是 Doris 的「地基」。理解清楚了,后面调优才能有的放矢。

分片(Tablet)

Doris 把一张表的数据,按某个列(比如时间、用户ID)分成多个 Tablet。每个 Tablet 是一个独立的存储单元,也是数据复制的最小单位。

举个例子:一张订单表有 1 亿行,我按「日期」分成 30 个 Tablet,每个 Tablet 存一天的数据。查询某一天的数据时,只需要扫描对应的 1 个 Tablet,而不是全表。

概念 说明 类比
Table 逻辑表,用户看到的结构 一本完整的书
Partition 按范围或列表划分的逻辑分区 书的章节
Tablet 物理存储单元,数据实际存放的地方 章节中的每一页
Replica Tablet 的副本,用于容错 每一页的复印件

副本机制

每个 Tablet 默认有 3 个副本,分布在不同的 BE 上。这样即使某个 BE 挂了,数据也不会丢。

副本的分布策略是 FE 控制的。它尽量把副本打散到不同的机器、不同的机架,甚至不同的机房。我习惯把副本数设为 3,既能保证高可用,又不会浪费太多存储。

避坑指南:我曾经把副本数设为 1,觉得「省点磁盘」。结果一台 BE 磁盘坏了,数据直接丢了。嗯,从那以后我再也不敢省副本了。

Doris 的查询引擎

查询引擎是 Doris 的「发动机」。它决定了你的 SQL 跑得快不快。

Doris 的查询引擎是 MPP(Massively Parallel Processing) 架构。说白了,就是把一个大查询拆成多个小任务,让所有 BE 一起干,最后汇总结果。

流程大概是这样的:

  1. SQL 解析:FE 把 SQL 解析成语法树。
  2. 逻辑计划生成:语法树转成逻辑执行计划,比如「先过滤、再聚合、最后排序」。
  3. 物理计划生成:逻辑计划转成物理执行计划,决定「哪个 BE 扫哪个 Tablet」。
  4. 任务分发:FE 把任务发给对应的 BE。
  5. 并行执行:每个 BE 在自己的 Tablet 上执行扫描、过滤、聚合等操作。
  6. 结果汇总:BE 把中间结果返回给 FE,FE 做最终的合并和排序,然后返回给客户端。

这里有个关键点:Doris 的查询引擎是 向量化 的。它一次处理一批数据(比如 1024 行),而不是一行一行处理。这样能充分利用 CPU 的缓存和 SIMD 指令,性能提升非常明显。

我的建议:如果你的查询涉及大量聚合(比如 count、sum、avg),尽量让 Doris 在 BE 层面完成预聚合,而不是把所有数据拉到 FE 再算。这样能大幅减少网络传输。