一、元数据运维的重要性
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--- 日志写入的高层 APIfe/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
核心流程:
Checkpoint.runAfterCatalogReady()定时触发(默认每 60 秒检查一次,见FeConstants.checkpoint_interval_second)- 加载当前 Image + 回放后续 Journal,在内存中构建完整元数据副本(此时会占用额外堆内存)
- 将副本写入新 Image 文件,先写为
image.ckpt,完成后原子重命名为image.xxxxx - 通过 HTTP 推送给所有非 Master FE 节点
- 确认推送成功后,清理 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 正在生成中;如果长时间不消失,说明生成可能卡住或失败ROLE与VERSION应同时存在或同时不存在;不要手动修改这两个文件
四、八大经典故障:从日志到根因
故障一:FE 启动卡在 "wait catalog to be ready"
日志特征:
wait catalog to be ready. fe type: FOLLOWER ...
根因排查:
- IP 地址漂移 (多网卡环境常见):FE 自动探测到的本机 IP 与集群中注册的 IP 不一致。需在
fe.conf中正确配置priority_networks(例如priority_networks=10.0.0.0/8)后重启相关 FE。 - Follower 节点数不足:集群无法选举出 Master。确保多数 Follower 已成功启动。
- BDBJE 数据复制中 :新加入的 FE 正在从 Master 同步数据(视数据量可能持续数分钟)。等待直到日志中出现
QE service start和thrift 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。
排查步骤:
-
在 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)。 -
搜索:
begin to generate new image: image.xxxx- 若后续出现
checkpoint finished save image.xxxx→ Image 生成正常 - 若后续出现
Exception when generate new image/Save image failed→ 查看具体异常堆栈定位根因
- 若后续出现
-
搜索:
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 失联并发起新选举。
解决方案:
-
降低内存压力 :在
fe.conf中缩短已完成 label 的保留时间,减少内存驻留:label_keep_max_second = 21600 streaming_label_keep_max_second = 21600 -
使用 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 运转,运维门槛不低。建议把握以下原则:
- Journal 记录增量变更,Image 是快照,Checkpoint 连接二者并负责推送与旧日志清理------理解生命周期是排障前提。
- 备份决定可恢复性 ------操作前备份全部 FE 的
doris-meta。 metadata_failure_recovery仅用于极端场景------操作前联系社区确认;用完必须退出恢复模式,避免再次 reset。
实际运维中,多数元数据问题可通过 观察日志 → 定位根因 → 按文档恢复 解决。涉及复制组 reset 或全 FE 不可用的恢复,应先与社区确认再执行。