Apache Doris 元数据运维深度解析:从架构原理到故障实战

一、元数据运维的重要性

Apache Doris 的 FE(Frontend)节点负责集群元数据管理,包括库表 Schema、分区信息、副本分布、事务状态、导入作业、权限体系等。BE 节点可以扩缩容,数据可以迁移;但元数据一旦损坏且无可用备份,集群可能面临不可逆的元数据丢失或无法启动。

本文将从源码视角出发,结合生产环境中高频出现的故障场景,给出可操作的诊断与恢复方案。前半部分聚焦 FE 集群元数据(BDBJE Journal / Image),后半部分补充 BE Tablet 元数据工具(meta_tool)。二者不是同一套系统,排查时请区分处理。

二、元数据架构:Journal、Image 与 Checkpoint

Doris 使用 Oracle Berkeley DB Java Edition(BDBJE) 作为 FE 分布式元数据日志存储。理解下面三个核心概念是排查 FE 元数据问题的基础。

2.1 Journal(操作日志)

每一条元数据变更(CREATE TABLE、ALTER TABLE、COMMIT 等)都会被序列化为一条 Journal 写入 BDBJE。核心链路为:

复制代码
EditLog.logEdit()  →  BDBJEJournal.write()

源码位置:

  • fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java --- 日志写入的高层 API
  • fe/fe-core/src/main/java/org/apache/doris/journal/bdbje/BDBJEJournal.java --- BDBJE 后端实现

Journal 按 opCode 分类,回放时通过 EditLog.loadJournal() 中的 switch-case 分发到对应的 replay handler。目前 Doris 内部定义了 超过 200 种 opCode (定义在 fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java),涵盖 Catalog 操作、事务、Alter、备份恢复等。

关键点 :Journal 对 Follower 遵循多数写(Quorum Write)策略。例如 3 个 FOLLOWER 时,至少 2 个写入成功才认为操作完成。多 Follower 部署时,建议保持 奇数个 FOLLOWER,以便形成清晰多数派;单 Follower(仅 Master)也是ok的部署方式。

2.2 Image(镜像快照)

Journal 会不断增长,FE 每次重启都从头回放所有 Journal 不可行。因此 Master FE 会定期生成 Image------某一时刻元数据内存状态的完整序列化快照。

Image 生成由 Checkpoint 守护线程驱动:

复制代码
fe/fe-core/src/main/java/org/apache/doris/master/Checkpoint.java

核心流程:

  1. Checkpoint.runAfterCatalogReady() 定时触发(默认每 60 秒检查一次,见 FeConstants.checkpoint_interval_second
  2. 加载当前 Image + 回放后续 Journal,在内存中构建完整元数据副本(此时会占用额外堆内存
  3. 将副本写入新 Image 文件,先写为 image.ckpt,完成后原子重命名为 image.xxxxx
  4. 通过 HTTP 推送给所有非 Master FE 节点
  5. 确认推送成功后,清理 BDBJE 中的旧 Journal

2.3 元数据版本(FeMetaVersion)

元数据结构并非一成不变。每次新增功能涉及元数据结构变更时,都会在 FeMetaVersion.java 中新增一个 VERSION 常量:

复制代码
fe/fe-common/src/main/java/org/apache/doris/common/FeMetaVersion.java

元数据不向后兼容。如果新版本引入了新的 VERSION,升级后通常无法回滚到旧版本。升级前务必做好备份和兼容性测试。

三、元数据目录结构

FE 的 meta_dir(配置于 fe.conf)下有两个核心子目录:

复制代码
doris-meta/
├── bdb/                          # BDBJE 数据目录
│   ├── 00000000.jdb              # Journal 数据文件(会随写入增长)
│   ├── je.info.0                 # BDBJE 自身运行日志(时间为 UTC+0)
│   └── je.lck                    # 锁文件(防止多进程同时打开)
└── image/                        # 镜像目录
    ├── ROLE                      # 当前 FE 角色(FOLLOWER / OBSERVER)
    ├── VERSION                   # Cluster ID 和 Token
    ├── image.123456              # 已完成的镜像(数字 = journal id)
    └── image.ckpt                # 正在生成中的镜像

运维关注点

  • 如果 bdb/ 目录超过 约 10GB,优先怀疑 Image 生成失败或推送失败,导致历史 Journal 无法被清理
  • image.ckpt 文件存在说明 Image 正在生成中;如果长时间不消失,说明生成可能卡住或失败
  • ROLEVERSION 应同时存在或同时不存在;不要手动修改这两个文件

四、八大经典故障:从日志到根因

故障一:FE 启动卡在 "wait catalog to be ready"

日志特征

复制代码
wait catalog to be ready. fe type: FOLLOWER ...

根因排查

  1. IP 地址漂移 (多网卡环境常见):FE 自动探测到的本机 IP 与集群中注册的 IP 不一致。需在 fe.conf 中正确配置 priority_networks(例如 priority_networks=10.0.0.0/8)后重启相关 FE。
  2. Follower 节点数不足:集群无法选举出 Master。确保多数 Follower 已成功启动。
  3. BDBJE 数据复制中 :新加入的 FE 正在从 Master 同步数据(视数据量可能持续数分钟)。等待直到日志中出现 QE service startthrift server started。若长时间未出现,可重启该 FE 重试。

故障二:meta out of date

日志特征

复制代码
meta out of date. current time: xxx, synchronized time: xxx, has log: xxx, fe type: xxx

根因:FE 无法选举出 Master。典型场景:配置了 3 个 FOLLOWER 但只启动了 1 个。

解决:同时启动所有 FOLLOWER 节点,确保达到多数派。

故障三:时钟偏差超限

日志特征

复制代码
Clock delta: xxxx ms. between Feeder: xxxx and this Replica exceeds max permissible delta: xxxx ms.

根因 :节点间时钟偏差超过 BDBJE 容忍阈值(默认 5000ms,由 max_bdbje_clock_delta_ms 控制)。

解决

  • 优先 :所有 FE 节点配置 NTP 时钟同步
  • 临时 :调大 max_bdbje_clock_delta_ms(不建议长期依赖)

故障四:Image 长时间不更新(bdb 目录持续膨胀)

现象 :超过一周未生成新 Image,bdb/ 目录持续增长至数 GB 甚至数十 GB。

排查步骤

  1. 在 Master fe.log 中搜索内存不足相关日志(不同版本文案可能不同,建议都搜):

    复制代码
    memory used percent
    exceed the checkpoint memory threshold
    memory is not enough to do checkpoint

    → 说明 JVM 堆内存不足以完成 Image 生成。解决:增大 -Xmx,重启 FE(多 Follower 时建议同步调整所有 Follower 的 JVM)。

  2. 搜索:

    复制代码
    begin to generate new image: image.xxxx
    • 若后续出现 checkpoint finished save image.xxxx → Image 生成正常
    • 若后续出现 Exception when generate new image / Save image failed → 查看具体异常堆栈定位根因
  3. 搜索:

    复制代码
    push image.xxxx to other nodes. totally xx nodes, push succeeded yy nodes

    如果 yy < xx,说明部分 FE 未成功接收 Image。继续查找 Exception when pushing image file / Failed when pushing image,检查目标 FE 的 http_port、连通性与磁盘。

临时缓解 :在 checkpoint 本身能成功的前提下,可适当调小 edit_log_roll_num(默认 50000),让 Image 更频繁生成,加速旧 Journal 清理(可动态修改)。

故障五:FOLLOWER 节点级联退出

现象:3 个 FOLLOWER 部署,1 个宕机后,又 1 个宕机,剩余的 FOLLOWER 也随之退出。

根因:BDBJE 采用多数写策略。当存活的 FOLLOWER 数量不足多数(例如 3 节点只剩 1 个),无法满足写入仲裁,进程可能主动退出。

建议

如果不熟悉 Doris 元数据运维,建议 只部署 1 个 FOLLOWER 作为 Master,其余全部为 OBSERVER。OBSERVER 不参与选举和多数写,可降低元数据层运维复杂度。该拓扑下 Master 存在单点不可写风险,需通过 JVM / 磁盘 / 监控与备份策略降低影响。

故障六:FOLLOWER 添加失败后的清理

现象:新 FOLLOWER 已加入 BDBJE 选举组但添加过程失败,残留的选举组成员信息干扰后续操作。

清理步骤

sql 复制代码
-- 1. 从元数据中移除
ALTER SYSTEM DROP FOLLOWER "host:edit_log_port";
bash 复制代码
# 2. 杀掉进程
# 3. 清理该节点的 doris-meta 目录
# 4. 重新执行添加流程

OBSERVER 添加失败通常可直接杀进程、清空元数据目录后重做;FOLLOWER 必须先 DROP,再清目录。

故障七:Full GC 导致 Master 频繁切换

现象:堆内存呈锯齿状波动(升高 → 断崖下跌 → 周而复始),高频导入场景尤为突出,FE Master 无明显征兆地切换或退出。

根因:部分环境仍使用 CMS 等回收器时,长时间 Full GC(Stop-the-World)可能导致其他节点判定 Master 失联并发起新选举。

解决方案

  1. 降低内存压力 :在 fe.conf 中缩短已完成 label 的保留时间,减少内存驻留:

    复制代码
    label_keep_max_second = 21600
    streaming_label_keep_max_second = 21600
  2. 使用 G1 GC(较新版本 Doris 已默认):

    复制代码
    -XX:+UseG1GC
    -XX:MaxGCPauseMillis=200

故障八:OOM Killer 静默杀掉 FE 进程

现象 :FE 进程消失,fe.log 中无异常记录。

排查

bash 复制代码
dmesg -T | grep -i java | grep -i "out of memory\|kill"

如果看到 Out of memory: Kill process 日志,说明操作系统 OOM Killer 介入。

建议:避免 FE 与 BE 混合部署在同一机器;确保 FE 节点有充足物理内存(推荐 32GB~64GB 及以上,并预留 checkpoint 所需堆空间)。

五、灾难恢复

所有恢复操作前,必须先备份所有 FE 节点的 doris-meta 目录。

5.1 方案 A:从健康节点同步(首选方案)

前提:集群中至少还有一个健康的 FE。

bash 复制代码
# 1. 停止问题 FE
sh bin/stop_fe.sh

# 2. 备份旧元数据
mv doris-meta doris-meta_bak

# 3. 创建空目录,以 helper 模式启动
mkdir doris-meta
sh bin/start_fe.sh --helper <健康FE_IP>:<edit_log_port> --daemon

新 FE 会自动从 Master 拉取完整 Image 并回放后续 Journal。

5.2 方案 B:全部 FE 不可用时的元数据恢复

官方警告与操作边界(务必先读)

官方文档明确:除非绝对必要,否则请避免使用 metadata_failure_recovery。不当使用可能导致元数据截断、元数据丢失以及 Split-brain;社区也已弱化对该模式逐步操作的公开说明。

建议:在执行本节任何步骤前,先联系 Apache Doris 社区开发者确认当前集群状态与操作方案,再动手。以下步骤仅作技术参考,不构成可直接套用的生产操作承诺。

当所有 FE 都无法正常提供服务,需要从残存元数据中恢复时,可参考以下流程。

步骤 1:选择 journal id 最新的节点

对比所有 FE 的 doris-meta/image/ 目录:

bash 复制代码
ls doris-meta/image/image.* | sort -t. -k2 -n | tail -5

数字后缀最大的节点通常保存了更新的元数据快照。优先选择 FOLLOWER 节点(OBSERVER 恢复更复杂)。

步骤 2:启动恢复模式

当前实现中,metadata_failure_recovery 通过 启动参数 注入 JVM System Property(见 DorisFE / start_fe.sh--metadata_failure_recovery / -r),不是 Config 中的常规可配置项。请勿仅依赖在 fe.conf 中写同名配置而不确认版本行为。

较新版本推荐:

bash 复制代码
sh bin/start_fe.sh --metadata_failure_recovery --daemon

部分旧版本可能通过启动脚本或系统属性传递同名开关;操作前请对照所用版本的 start_fe.sh / 启动参数说明,并与社区确认。

步骤 3:验证

sql 复制代码
SHOW FRONTENDS \G

确认恢复节点为 Master 且元数据可正常访问。

步骤 4:清理旧节点

sql 复制代码
ALTER SYSTEM DROP FOLLOWER "old_host:edit_log_port";

步骤 5:退出恢复模式(关键)

停掉 FE → 确认后续启动命令中不再携带 --metadata_failure_recovery / -r → 正常重启。

如果启动时持续带有恢复开关,BDBJE 复制组可能被再次 reset,导致元数据再次被破坏、集群不可用。

步骤 6:重建集群

其余节点通过方案 A(--helper 模式)逐一重新加入。

5.3 极端情况:从 FE 内存导出 Image

当磁盘 Image 文件异常,但 Master FE 进程仍存活且内存元数据可用时:

bash 复制代码
# 1. 停止所有写入操作(Load / Create / Alter)
# 2. 从 Master FE 内存导出元数据
curl -u root: http://master_ip:8030/dump

# 3. 用 dump 出的 image 文件替换各节点 doris-meta/image/ 中的对应文件
# 4. 按 OBSERVER → FOLLOWER → Master 的顺序逐一重启

/dump 接口返回结果中包含 dumpFilePath。操作前同样建议联系社区确认适用性,并完整备份 doris-meta

六、BE 端 Tablet 元数据管理工具

BE 端的 Tablet 元数据存储在 RocksDB 中。当 BE 因 Tablet 元数据损坏无法启动时,可使用 meta_tool

meta_tool 必须在 BE 进程完全停止后使用。

工具位置:be/lib/meta_tool(源码:be/src/tools/meta_tool.cpp

6.1 在线查看(BE 运行时)

bash 复制代码
curl "http://be_host:8040/api/meta/header/{tablet_id}/{schema_hash}"

6.2 离线操作

查看 Tablet 元数据

bash 复制代码
./lib/meta_tool \
  --root_path=/data/be/storage \
  --operation=get_meta \
  --tablet_id=14156 \
  --schema_hash=2458238340

输出为 JSON 格式,可备份后用于后续修复。

手动加载元数据(常用于跨节点 Tablet 迁移):

bash 复制代码
./lib/meta_tool \
  --operation=load_meta \
  --root_path=/data/be/storage \
  --json_meta_path=/tmp/tablet_14156.json

删除损坏 Tablet 元数据(解决因个别 Tablet 导致 BE 启动失败):

bash 复制代码
# 单个删除
./lib/meta_tool \
  --operation=delete_meta \
  --root_path=/data/be/storage \
  --tablet_id=5103093 \
  --schema_hash=2458238340

# 批量删除
./lib/meta_tool \
  --operation=batch_delete_meta \
  --tablet_file=/tmp/bad_tablets.txt

bad_tablets.txt 格式(每行一个 Tablet):

复制代码
/data/be/storage,14217,352781111
/data/be/storage,14219,352781111
/data/be/storage,14223,352781111

原则 :删除前先 get_meta 备份。

七、调试:BDBJE Debug Mode

FE 因元数据异常无法正常启动时,可临时启用调试模式查看 BDBJE 中的数据:

properties 复制代码
# fe.conf
enable_bdbje_debug_mode=true
bash 复制代码
bash bin/start_fe.sh --daemon

此时仅启动 HTTP 与 MySQL 服务并打开 BDBJE,不加载完整元数据、不走正常启动后续流程。可通过 Web 或 MySQL 客户端执行:

sql 复制代码
SHOW PROC "/bdbje";
SHOW PROC "/bdbje/<DbName>";
SHOW PROC "/bdbje/<DbName>/<JournalId>";

用于查看 Journal 的 OpType 与内容摘要。这是排障只读手段,不是修复操作;用完后务必恢复配置并按正规流程处理。

八、总结

Doris FE 元数据体系围绕 Journal、Image 与 Checkpoint 运转,运维门槛不低。建议把握以下原则:

  1. Journal 记录增量变更,Image 是快照,Checkpoint 连接二者并负责推送与旧日志清理------理解生命周期是排障前提。
  2. 备份决定可恢复性 ------操作前备份全部 FE 的 doris-meta
  3. metadata_failure_recovery 仅用于极端场景------操作前联系社区确认;用完必须退出恢复模式,避免再次 reset。

实际运维中,多数元数据问题可通过 观察日志 → 定位根因 → 按文档恢复 解决。涉及复制组 reset 或全 FE 不可用的恢复,应先与社区确认再执行。

相关推荐
kdxiaojie1 小时前
Linux 驱动研究 —— V4L2 (3)
linux·运维·笔记·学习
facaixxx20241 小时前
雨云游戏服务器MCSM面板指南:低延迟BGP线路(一键开服)
运维·服务器·游戏
hkNaruto1 小时前
【大数据】《传统Hadoop大数据技术入门:补充与进阶——从数据格式到智能决策的问答实录》
大数据·hadoop·分布式
吾AI科技2 小时前
基于Tez引擎的 Hive SQL 性能优化
大数据·hive·性能优化·tez
焦点链创研究所2 小时前
算力核心机器人将于 7 月 18 日发布
运维·服务器·机器人
百胜软件@百胜软件2 小时前
零点零一×百胜E3+业务智能中台项目启动,中台赋能客制化机械键盘品牌“加数”发展
大数据·云计算
鼎艺创新科技2 小时前
WAIC 2026观察:应急AI三维沙盘避坑 拆解3DGIS+AI真落地的3个核心技术门槛
大数据·人工智能·国产化·电子沙盘·三维电子沙盘
Starry-sky(jing)2 小时前
如何判断 Windows 是否安装 Node.js:三种方法 + 常见漏判场景
运维·windows·node.js·环境检测
其实防守也摸鱼3 小时前
运维--ip单日获取去重数据量超过500条
运维·学习·tcp/ip·安全·web安全·安全威胁分析·工具