The source notes for this track are currently maintained in Chinese.
预计阅读时间: 45 分钟 | 前置阅读: doc-00 §2 (FE拓扑), doc-06 (Tablet) 下一次阅读: doc-11 (FE HA)
1. 元数据模型总览

层级结构
Catalog (fe/fe-core/.../catalog/)
├── InternalCatalog (内表)
│ └── Database
│ └── OlapTable
│ ├── Partition 0
│ │ ├── Index (Rollup/MV) 0
│ │ │ ├── Tablet 0 → Replica(BE-1), Replica(BE-2), Replica(BE-3)
│ │ │ ├── Tablet 1 → ...
│ │ │ └── Tablet N
│ │ └── Index 1 (物化视图)
│ ├── Partition 1 → ...
│ └── ...
├── HmsExternalCatalog (Hive Metastore)
├── IcebergExternalCatalog
├── HudiExternalCatalog
├── EsExternalCatalog (Elasticsearch)
└── JdbcExternalCatalog (MySQL/PostgreSQL)
关键类
| 层级 | 类 | 源码位置 | 职责 |
|---|---|---|---|
| Catalog | Env | fe/fe-core/.../catalog/Env.java | 全局元数据容器(单例) |
| DB | Database | fe/fe-core/.../catalog/Database.java | 库级别元数据 + 事务管理 |
| Table | OlapTable | fe/fe-core/.../catalog/OlapTable.java | 表:分区/副本/索引/属性 |
| Partition | Partition | fe/fe-core/.../catalog/Partition.java | 分区: Tablets 集合 |
| Tablet | Tablet (FE) | fe/fe-core/.../catalog/Tablet.java | FE 侧 Tablet 元数据 |
| Replica | Replica | fe/fe-core/.../catalog/Replica.java | 副本: BE 位置/状态 |
源码导航
| 文件 | 关键类/方法 | 职责 |
|---|---|---|
fe/fe-core/.../catalog/Env.java | Env (单例) | 全局元数据容器 |
fe/fe-core/.../catalog/Database.java | Database | 库级元数据(Txn管理) |
fe/fe-core/.../catalog/OlapTable.java | OlapTable | 表:分区/副本/物化视图 |
fe/fe-core/.../catalog/Partition.java | Partition | 分区:Tablets 集合 |
fe/fe-core/.../catalog/Tablet.java | Tablet (FE) | FE 侧 Tablet 元数据 |
fe/fe-core/.../catalog/Replica.java | Replica | 副本:BE 位置/状态 |
fe/fe-core/.../persist/EditLog.java | EditLog, logJsonEdit() | Journal 写入 (persist 包) |
fe/fe-core/.../journal/bdbje/BDBJEJournal.java | BDBJEJournal | BDBJE 实现 (journal 包) |
2. Catalog 核心代码路径
初始化
FE 启动 → Env 初始化
→ 1. 回放 Journal (恢复上次 Checkpoint 后的操作)
→ 2. 加载 Image (最新的元数据快照)
→ 3. 回放增量 Journal → 恢复到最新状态
→ 4. 打开 BDBJE Replicated Environment
→ 5. 选举 Master/Follower (BDBJE)
DDL 执行路径
CREATE TABLE t (id BIGINT, name STRING)
→ StmtExecutor.execute()
→ CreateTableStmt
→ Env.createTable(db, tableName, ...)
→ 1. 写入 EditLog (Journal) ← 持久化 (故障恢复)
→ 2. 更新 FE 内存: Catalog.addTable()
→ 3. 通知 BE: CreateTabletTask ← BE 创建 Tablet 目录
→ 4. 写入 BDBJE (复制到 Follower)
3. EditLog 与 Journal 格式
日志类型
| 日志类型 | 操作 | 示例 |
|---|---|---|
OperationType.OP_CREATE_DB | 创建数据库 | CREATE DATABASE |
OperationType.OP_CREATE_TABLE | 创建表 | CREATE TABLE |
OperationType.OP_ADD_PARTITION | 添加分区 | ALTER TABLE ADD PARTITION |
OperationType.OP_FINISH_CONSISTENCY_CHECK | Tablet 修复完成 | Clone 完成 |
OperationType.OP_ALTER_JOB_V2 | Schema Change | ALTER TABLE MODIFY COLUMN |
Journal 持久化流程
编辑操作 → EditLog.logEdit(OperationType, Writable)
→ 1. 序列化为 byte[]
→ 2. BDBJE.put(key=logId, value=bytes) ← 同步写入 BDBJE
→ 3. BDBJE 复制: Master → Follower(s) (自动复制)
→ 4. Follower 回放: apply(OperationType, bytes) → 更新本地 Catalog
源码定位
| 文件 | 用途 |
|---|---|
fe/fe-core/.../journal/Journal.java | Journal 接口 |
fe/fe-core/.../journal/bdbje/BDBJEJournal.java | BDBJE 实现 |
fe/fe-core/.../journal/EditLog.java | EditLog 写入入口 |
4. 元数据持久化——Image + Journal
两层存储模型
Image: 元数据全量快照 (类似 Raft Snapshot)
每隔 N 个 Journal Entry 生成一次
所有 FE (含 Follower) 本地都有完整 Image
Journal: 增量变更记录
自上次 Image 后的所有修改操作
格式: {logId: OperationType + Payload}
启动恢复流程
FE 崩溃恢复:
1. 读取本地最新 Image → 加载到内存 (~分钟级)
2. 读取 Journal 自 Image.logId 后的增量 Entry → 回放 (~秒级)
3. Catalog 恢复到崩溃前的最新状态
4. 加入 BDBJE 集群 → 追赶 Master 的最新 Journal Entry
5. FE 变为 Follower → 可接受查询
5. 元数据 GC / Recycle Bin
删除表/分区 的多阶段
Drop Table t:
1. Logical Delete: Catalog 中移除 t → Table 进入 RecycleBin
→ 可见性: 用户看不到 t
→ RecycleBin: 保留 N 分钟 (默认 1天, `catalog_trash_expire_second`)
2. Physical Delete: RecycleBin 到期 → 清理所有 Tablet 和 Replica
→ FE → BE: DropTabletTask → BE 删除磁盘上的 Rowset 文件
6. External Catalog——联邦查询入口
架构
用户: SELECT * FROM hive_catalog.db.orders WHERE dt='2026-07';
│
FE Nereids ──► HmsExternalCatalog
│ 1. 连接 Hive Metastore
│ 2. 获取 orders 表的 Schema + 文件位置 (HDFS/S3)
│ 3. 生成 PhysicalFileScan (读 Parquet/ORC 文件)
│
BE Pipeline ──► FileReader (HdfsReader / S3Reader)
直接读外部文件的 Parquet/ORC → 解压 → Block
支持的 External Catalog
| Catalog | 存储位置 | 数据格式 |
|---|---|---|
| HMS (Hive) | HDFS / S3 | Parquet, ORC, Text |
| Iceberg | HDFS / S3 / GCS | Parquet, ORC, Avro |
| Hudi | HDFS / S3 | Parquet (MoR/CoW) |
| Elasticsearch | ES Cluster | JSON (索引) |
| JDBC | MySQL/PG/Oracle | Table (通过 JDBC 查询) |
7. 常见问题 / 面试题
Q1: BDBJE 为什么比 Raft 实现更合适? A: BDBJE 的 Journal 是"嵌入式 Java KV 存储 + 自带复制", 与 FE 代码深度集成(序列化/回放在同进程内), 比单独的 Raft 库(需额外的网络层+存储引擎)简单。代价: BDBJE 不是广为人知的组件, 社区维护压力大。
Q2: Image 文件过大会有什么问题? A: (1) FE 启动时加载 Image 慢; (2) 内存占用大 (所有元数据在 JVM heap); (3) Checkpoint 耗时增加。Doris 的生产建议: Tablet 数量控制在 100 万以内, 单 FE 堆内存 32-64GB。
Q3: 外部 Catalog 如何维护统计信息? A: FE 定期 (可配) 扫描外部表的文件元数据 (HMS 的 TableStats), 或触发计算任务采样。外部表的统计信息通常比内表粗糙 (只有 Row Count + File Size, 无 Histogram), 影响 CBO 准确度。

下一步
- FE HA: doc-11-fe-ha-replication.md——FE 的高可用设计