Day 24|Apache Doris 可观测性与故障排查:Metrics、Grafana、Query Profile、日志与系统化诊断树
课程阶段: 第五阶段·生产环境与运维治理
建议学习时长: 3~4 小时
实验基线: Apache Doris 4.0.8 Stable / 4.1.3 Latest
今日目标: 建立一套从“发现异常”到“定位根因、验证修复、沉淀机制”的完整方法。

前二十三天,我们先后完成了 Doris 的定位、架构、表模型、导入、索引、物化视图、查询执行、存储引擎、事务更新、容量规划、高可用和工作负载治理。到了生产环境,真正考验团队的往往是另外一件事:系统发生抖动时,能否在有限时间里判断影响范围,找到可靠证据,完成止损,并把修复结果固化成长期机制。
很多故障都有相似的表象。经营大屏变慢,可能来自 SQL 扫描放大,也可能来自 Workload Group 排队、BE 磁盘延迟、Compaction 抢占、FE 规划变慢或外部 Catalog 抖动;导入延迟升高,可能来自 Kafka Lag、数据质量、事务发布、MemTable Flush、磁盘水位或副本异常。仅凭某一条报错或某一张 Grafana 曲线,很难得到稳定结论。
可观测性的价值,在于把系统运行时留下的外部信号组织成证据。Doris 提供 Metrics、日志、Audit、Query Profile、System Tables、Web 页面和 HTTP API;Linux 还提供 CPU、内存、磁盘与网络工具。运维工程师需要把这些能力串成一条有顺序的诊断链路。
一、可观测性要解决的四个问题
生产可观测体系至少要持续回答四个问题:
- 服务是否可用。 FE/BE 是否存活,查询与导入是否成功,数据是否按 SLA 更新。
- 性能是否稳定。 p50、p95、p99、排队时间、计划时间和执行时间是否偏离基线。
- 资源是否健康。 CPU、内存、磁盘、网络、线程池、Compaction、Tablet 与 Cache 是否进入饱和区。
- 异常能否解释。 能否通过 QueryID、Node、时间窗和变更编号,将 Metrics、日志、Profile 和系统状态关联起来。

可观测性建设需要避免“指标越多越好”的倾向。指标数量增长很快,维护成本、存储成本和告警噪声也会同步上升。更有效的做法是先确定服务目标,再选择能反映目标状态的信号,然后补齐根因定位所需的内部指标。
例如,一个面向经营大屏的集群,可以先定义:
- 核心报表成功率;
- p95 与 p99 响应时间;
- 数据从业务事件发生到报表可见的端到端新鲜度;
- 早高峰目标并发;
- 关键 Workload Group 的排队比例;
- 单节点故障时的服务降级范围。
围绕这些目标,继续补充 FE、BE、查询、存储和导入指标,体系会更加清晰。
二、Doris 可观测性的四类证据
2.1 Metrics:持续观察趋势与饱和度
Doris 的 FE 和 BE 都内置 Prometheus 兼容指标。FE 默认通过 HTTP 端口 8030 暴露,BE 默认通过 Web Server 端口 8040 暴露:
curl http://fe_host:8030/metrics
curl http://be_host:8040/metrics
# JSON 格式
curl 'http://fe_host:8030/metrics?type=json'
curl 'http://be_host:8040/metrics?type=json'
Metrics 适合回答“什么时候开始异常”“哪些节点偏离”“趋势是否持续”“资源是否达到瓶颈”。它能快速缩小时间窗和节点范围,却通常无法独立解释某一条 SQL 的内部行为。
2.2 Logs:记录事件、错误上下文和状态变化
日志适合回答“系统在异常时做了什么”“哪个组件返回了什么错误”“是否发生选主、崩溃、事务失败或副本修复”。FE 与 BE 的关键日志包括:
| 组件 | 日志 | 主要用途 |
|---|---|---|
| FE | fe.log |
启动、元数据、调度、查询协调、一般运行信息 |
| FE | fe.warn.log |
WARN、ERROR、权限、RPC、异常状态 |
| FE | fe.audit.log |
Query、Slow Query、Load、Stream Load 审计 |
| FE | fe.out |
标准输出、JVM 启动和崩溃信息 |
| BE | be.INFO |
查询执行、内存、Tablet、Compaction、导入等运行信息 |
| BE | be.WARNING |
OOM 风险、IO、RPC、Tablet 和任务异常 |
| BE | be.out |
C++ Crash、标准输出与启动失败 |
2.3 Query Profile:观察一条查询真实执行了什么
Query Profile 记录单条查询在各个 BE 上的 Fragment、PipelineTask 和 Operator 指标。它能回答:
- 哪个算子耗时最高;
- 实际扫描了多少行和多少字节;
- Runtime Filter 是否命中;
- Join Build 侧是否过大;
- Shuffle 发送与接收了多少数据;
- 内存峰值和 Spill 发生在哪里;
- 同一 Operator 在不同 Instance 上是否存在倾斜;
- 主要时间花在计算还是依赖等待。
2.4 System Tables:用 SQL 查询运行状态
information_schema 中的系统表让运维数据可以直接用 SQL 聚合和关联。常用对象包括:
active_queries:FE 注册的运行查询;backend_active_tasks:BE 正在执行的 Query、Load 等 Task;workload_group_resource_usage:Workload Group 的 CPU、内存和扫描速率;backend_tablets:Tablet 的 Version、Segment、Compaction Score 和大小;rowsets:Rowset 版本、状态和存储信息;routine_load_job:Routine Load 状态与任务信息;processlist:连接和当前语句。
这四类证据通过时间、QueryID、节点 ID、Tablet ID、用户和 Workload Group 关联,形成完整诊断上下文。
三、搭建 Prometheus 与 Grafana 监控链路

一个典型链路由四层组成:
FE / BE / OS Metrics
↓
Prometheus 周期抓取与规则计算
↓
Grafana 看板与变更注释
↓
Alertmanager 路由、分组、抑制与通知
官方提供了两套 Grafana Dashboard:存算一体集群使用 shared-nothing 模板,存算分离集群使用 cloud 模板。生产落地时还需要补充操作系统指标。Doris 能看到进程内部状态,系统层工具能看到宿主机 CPU steal、磁盘 await、网络重传、文件系统水位等信息,两类视角相互补充。
3.1 Prometheus 抓取配置的关键点
监控配置的关键是标签设计和实例完整性,YAML 语法只承担配置表达:
- 每个指标带有稳定的
cluster、instance、role标签; - FE、BE 和存算分离组件使用统一集群标识;
- 节点下线后保留一段时间序列,便于复盘;
- 抓取间隔一般从 15~30 秒起步,高频告警指标可按需要缩短;
- Prometheus 与 Doris 节点时间必须同步;
- 监控服务器自身也要有容量、磁盘和抓取失败告警。
3.2 Counter 要转换成速率
官方指标表中大量指标属于 Counter,它们从进程启动后持续累加。直接看绝对值没有明确意义,常见处理方式是计算单位时间增量:
rate(doris_fe_query_total[5m])
rate(doris_fe_query_err[5m])
increase(doris_fe_query_err[10m])
错误率可以使用错误 Counter 的速率除以总请求 Counter 的速率。重启会导致 Counter 归零,Prometheus 的 rate() 能处理大多数正常重置场景。
四、指标体系:从 P0 到深度诊断

Apache Doris 官方指标文档为指标标注了优先级,P0 最高。生产建设可以分三步推进。
4.1 第一层:可用性与服务结果
这一层直接映射业务影响:
- FE/BE Alive 与心跳;
- 查询 QPS、成功数、错误数;
- p50、p95、p99;
- 当前运行、排队与拒绝的查询;
- Stream Load、Routine Load、异步任务成功率;
- 数据新鲜度;
- 磁盘是否接近写保护阈值。
这组指标适合定义 P0/P1 告警和业务 SLO。
4.2 第二层:FE 健康

FE 承担连接接入、元数据、规划、事务协调和调度。重点观察:
- JVM Heap 使用量、GC 次数和 GC 时间;
- FE 是否存在 Master,Follower 是否同步;
- EditLog / Journal 写入与回放;
- RPC 队列和线程池;
- 连接数、查询规划耗时和元数据规模;
- 外部 Catalog 元数据缓存与刷新。
FE CPU 较高时,应先确认是高并发短查询造成规划压力,还是复杂 SQL 导致优化器搜索空间过大;JVM 内存持续升高时,要区分元数据、查询计划对象、外部 Catalog 缓存和异常引用。
4.3 第三层:BE 健康

BE 同时承担计算、存储、缓存、导入和 Compaction。重点观察:
- CPU 使用率与负载;
- BE 进程内存、系统可用内存、Jemalloc Cache;
- Query、Load、Compaction 等 Memory Tracker;
- 磁盘使用率、IOPS、吞吐、await 与错误;
- 网络收发、RPC 延迟和重传;
- 扫描字节、扫描行数和 Scanner 线程;
- Tablet 数、Version 数、Segment 数和 Compaction Score;
- 导入吞吐、Reject 行数与 Publish 延迟;
- 线程池 Active、Queue 与拒绝。
4.4 第四层:查询与 Operator
查询层需要使用 Audit、Explain 和 Profile。宏观 Metrics 能说明集群整体负载,Profile 能把负载落到具体 Operator。二者结合后,才能判断一次 p99 上升属于系统资源不足,还是少数异常 SQL 放大资源消耗。
五、Grafana 看板如何设计得真正可用

一个完整 Dashboard 建议分成八个视角:
- 集群总览: FE/BE 存活、Master、容量、QPS、错误率;
- 查询性能: p50/p95/p99、运行数、排队数、超时和失败;
- FE 健康: JVM、GC、Journal、RPC、连接;
- BE 资源: CPU、内存、磁盘、网络;
- 执行与队列: Workload Group、线程池、等待与 Spill;
- 导入任务: Load 吞吐、Reject、Routine Lag、Publish;
- Tablet 与 Compaction: Version、Segment、Score、副本健康;
- 容量趋势: 数据增长、磁盘水位、Tablet 增长和未来预测。
看板还需要具备下钻能力。例如从 p99 折线跳转到同一时间窗的 FE/BE 资源面板,再跳转到慢 SQL 列表和 Profile。固定时间范围、节点变量、单位、颜色和告警状态能显著提高排障效率。
5.1 变更注释
很多异常都与变更相关。建议把以下事件写入 Grafana Annotation 或统一变更系统:
- 应用发布;
- SQL 或报表版本;
- Doris 参数修改;
- DDL、索引、物化视图和分区变更;
- 扩缩容与节点重启;
- Doris 升级;
- 大规模补数、历史回灌和导入批次调整。
当指标异常起点与变更时间高度重合时,诊断可以快速收敛。
六、告警设计:症状、根因与降噪
告警需要同时覆盖用户症状和内部根因。
6.1 症状告警
- 核心查询成功率下降;
- p99 超出 SLO;
- Routine Load Lag 超出数据新鲜度目标;
- 关键报表或 API 连续失败;
- 集群无法写入或无法选出 Master。
6.2 根因告警
- FE JVM、Journal、RPC 队列异常;
- BE CPU、内存、磁盘、网络饱和;
- Compaction Score、Version Count 持续上升;
- Workload Group 排队或拒绝增加;
- Tablet 副本缺失或状态异常;
- 外部 Catalog 元数据访问持续变慢。
6.3 降噪原则
- 对瞬时尖峰增加持续时间;
- 使用短窗口快速发现,长窗口确认持续性;
- 根因告警触发后抑制同一节点的派生告警;
- 按集群、节点、业务和事件分组;
- 维护窗口保留明确记录;
- 告警恢复时发送恢复通知;
- 每条告警包含 Runbook 和可直接打开的 Dashboard 链接。
阈值需要通过历史分位数和业务 SLO校准。单纯复制其他集群的阈值,容易产生大量误报或漏报。
七、Query Profile:从查询总览下钻到 PipelineTask

Profile 的核心组件包括 FE 的 ProfileManager 和 BE 的 AsyncReportThreadPool。查询开始时,执行 FE 注册 Profile;查询执行完成后,各 BE 将本地 Profile 作为异步任务上报;FE 聚合、保留和淘汰 Profile,也可以将适合持久化的 Profile 压缩写入本地目录。
7.1 当前关键参数
| 参数 | 默认值 | 作用 |
|---|---|---|
enable_profile |
false |
是否生成 Profile |
profile_level |
1 |
4.0+ 的 Profile 详细程度,范围 1~3 |
auto_profile_threshold_ms |
-1 |
仅为超过阈值的查询生成 Profile |
max_query_profile_num |
500 |
FE 内存中最多保留的 Profile 数 |
max_spilled_profile_num |
500 |
磁盘最多保留的 Profile 数 |
spilled_profile_storage_path |
log/profile |
Profile 本地存储目录 |
spilled_profile_storage_limit_bytes |
1 GB |
磁盘 Profile 总容量上限 |
实验环境可以使用:
SET enable_profile = true;
SET profile_level = 2;
SET auto_profile_threshold_ms = 1;
生产环境更适合设置慢查询阈值,只保留真正需要分析的 Query,避免 Profile 本身增加 FE/BE 开销和存储压力。
7.2 Profile 五部分阅读顺序

- Summary: 确认 QueryID、总耗时、状态、用户和时间;
- ExecutionSummary: 判断 Planner、Fragment 调度和执行阶段的时间;
- ChangedSessionVariables: 检查查询是否修改了内存、并行度、超时、Runtime Filter 等参数;
- MergedProfile: 找出最慢 Operator,观察 InputRows、RowsProduced、ExecTime、WaitForDependency 和 min/avg/max;
- DetailProfile: 下钻到特定 BE、Instance 和 PipelineTask。
7.3 先看等待,再看计算
Operator 的 ExecTime 表示自身执行耗时,WaitForDependency 表示等待依赖条件的时间。一个 Exchange Operator 看起来耗时很长,真实原因可能是上游 Join、Sort 或网络迟迟没有数据到达。诊断时需要沿等待链向上游追踪。
7.4 用 min/avg/max 识别数据倾斜
MergedProfile 会聚合同一 Operator 在多个 Instance 上的指标。当 max 远高于 avg,或 min=0 且 max 很大时,通常需要检查分桶不均、热点 Key、Join Key 中大量 NULL、单个大文件或 Tablet 倾斜。
7.5 常见 Operator 观察点
| Operator | 重点指标 | 解释方向 |
|---|---|---|
| Scan | ScanRows、ScanBytes、FilteredRows、IOTime | 分区/Tablet/Page 裁剪、索引、列裁剪、磁盘或远端 IO |
| Hash Join | BuildRows、HashTable、PeakMemory、Wait | Build 侧大小、Distribution、Runtime Filter、倾斜 |
| Exchange | BytesSent/Received、WaitForData | Shuffle 规模、网络、上下游阻塞 |
| Aggregate | InputRows、HashTable、PeakMemory、Spill | 分组基数、局部聚合、内存预算 |
| Sort / TopN | InputRows、PeakMemory、SpillBytes | 排序范围、TopN 下推、落盘 |
八、日志、Audit 与慢查询

官方 FE 日志当前默认按 age 保留:fe.log 和 fe.warn.log 默认 7 天,fe.audit.log 默认 30 天。Audit 模块默认包含 slow_query、query、load 和 stream_load;qe_slow_log_ms 默认 5000 ms。
8.1 Audit Log 中要关注什么
Audit Log 适合做历史分析,常用字段通常包括:
- QueryID、用户、客户端 IP;
- Catalog、Database;
- SQL、SQL Digest;
- 开始时间、总耗时、状态;
- 扫描行数与字节;
- CPU Time;
- Peak Memory;
- Workload Group;
- 返回行数与错误信息。
SQL Digest 能把参数不同、结构相同的 SQL 聚合到一起,便于识别某类 SQL 的总资源消耗。只按单次最大耗时排序,容易忽略高频中等成本 SQL 的累计影响。
8.2 日志搜索方法
日志搜索建议固定几个关联键:
时间窗
QueryID
Connection ID
User / IP
Tablet ID / Backend ID
Label / Transaction ID
面对 BE 内存问题,可以先从 be.INFO 中的 Memory Tracker Summary 找到 QueryID,再回到 fe.audit.log 获取 SQL,随后获取 Explain 和 Profile。面对加载失败,先读 Stream Load 返回 JSON 和 Error URL,再查询 Label 与事务状态。
8.3 日志采集的工程要求
- 使用 Vector、Filebeat 或同类采集器集中汇聚;
- 保留原始时间戳、节点、文件名和日志级别;
- 多行堆栈需要正确合并;
- 查询 SQL 和用户信息需要权限控制;
- K8s 环境要明确 stdout 与持久卷日志的采集方式;
- DEBUG 只针对目标类或包短时开启,完成后立即恢复。
