Doris architecture

ANALYTICAL DATABASE / SOURCE READING / LESSON 16

Monitoring, performance, and troubleshooting

Turn metrics, query slowness, ingestion issues, replica problems, and resource symptoms into a Doris troubleshooting playbook.

Reading
60 min
Track
Doris architecture
Source
Chinese source notes

The source notes for this track are currently maintained in Chinese.

预计阅读时间: 60 分钟 前置阅读: 全部 doc (运维必备,需要了解所有子系统) 下一次阅读: doc-17(表设计与建模), doc-18(慢 SQL 与 Profile)


1. Metrics 体系

源码导航

文件关键类/方法职责
fe/fe-core/.../metric/MetricRepo.javaMetricRepo (单例)FE 指标注册中心
fe/fe-core/.../metric/CounterMetric.javaCounterMetricCounter 类型
fe/fe-core/.../metric/GaugeMetricImpl.javaGaugeMetricImpl<T>Gauge 类型
be/src/common/metrics/doris_metrics.hDorisMetricsBE 指标注册中心
be/src/common/metrics/metrics.cppMetricsVisitor指标收集与输出
be/src/service/http/action/metrics_action.cppMetricsActionHTTP /metrics 端点

Metric 类型

类型FE 类说明典型指标
CounterCounterMetric单调递增计数query_total, load_bytes_total
GaugeGaugeMetricImpl<T>瞬时值(可增可减)tablet_num, memory_used
Histogram基于统计分桶统计query_latency, journal_write_latency

BE 端点

http://<be_host>:8040/metrics  →  Prometheus 格式
http://<fe_host>:8030/metrics  →  FE 指标

2. 关键 Metrics 速查

FE 指标

Metric类型含义异常阈值
query_totalCounter累计查询数
query_errCounter失败查询数> 1% 总查询
fe_journal_write_latency_msHistogramJournal 写入延迟P99 > 100ms
edit_log_size_bytesCounterEditLog 累计大小
tablet_report_latency_msHistogramTablet 心跳处理延迟P99 > 500ms
fe_memory_used_bytesGaugeFE JVM Heap 使用量> 80% MaxHeap
request_totalCounterHTTP/MySQL 请求总数

BE 指标

Metric类型含义异常阈值
tablet_numGaugeTablet 总数
compaction_deltas_totalCounterCompaction 合并 Delta 数
memory_pool_bytes_usedGaugeBE 内存使用量> 80% Total
segment_read_latency_msHistogramSegment 读取延迟P99 > 100ms
fragment_requests_totalCounterFragment 请求数
brpc_endpoint_latencyHistogramBrpc 点对点延迟P99 > 50ms
load_bytes_totalCounter累计导入字节数

3. Profile——查询执行分析

架构

Profile 是 Doris 最重要的性能诊断工具。每次查询都生成一个 RuntimeProfile 树,包含每个算子(Fragment、Pipeline、Operator)的执行统计。

源码导航

文件关键类/方法职责
fe/fe-core/.../profile/RuntimeProfile.javaRuntimeProfileProfile 节点(树形结构)
fe/fe-core/.../profile/ExecutionProfile.javaExecutionProfile查询级 Profile
fe/fe-core/.../profile/SummaryProfile.javaSummaryProfile汇总信息
be/src/runtime/runtime_profile.hRuntimeProfile (BE)BE 端 Profile 计数器
fe/fe-core/.../qe/ProfileManager.javaProfileManagerProfile 管理/缓存

Profile 如何使用

-- 查看最近一个查询的 Profile
SHOW PROFILE;

-- 查看特定查询的 Profile (需要 query_id)
SHOW PROFILE "/" FROM <query_id>;

-- 或通过 HTTP API
curl http://fe:8030/api/profile?query_id=<query_id>

Profile 树结构解读

Execution Profile <query_id>
├── Summary
│   ├── Query Type: SELECT
│   ├── Start Time: 2026-07-08 10:00:00
│   ├── End Time: 2026-07-08 10:00:02
│   ├── Total Time: 2.3s
│   └── Query State: FINISHED
│
├── Fragment 0 (Root)
│   ├── Pipeline 0
│   │   ├── ExchangeSourceOperator
│   │   │   ├── RowsReturned: 1,000,000
│   │   │   ├── BlocksRead: 245
│   │   │   └── TotalTime: 200ms
│   │   └── AggSinkOperator
│   │       ├── RowsProcessed: 1,000,000
│   │       └── TotalTime: 500ms
│   └── ...
│
├── Fragment 1 (Leaf)
│   ├── Pipeline 0
│   │   ├── OlapScanOperator
│   │   │   ├── RowsReturned: 5,000,000
│   │   │   ├── TabletsScanned: 120
│   │   │   ├── SegmentReadTime: 800ms
│   │   │   └── IndexFilterTime: 50ms
│   │   └── FilterOperator
│   │       ├── RowsFiltered: 4,000,000
│   │       └── TotalTime: 100ms
│   └── ...

关键 Profile 指标

指标含义优化方向
RowsReturned / RowsFiltered扫描行与过滤行比例过滤率低 → 索引不够/谓词不合理
SegmentReadTimeSegment 读取耗时太高 → 可能缺少索引过滤或 Compaction 不及时
IndexFilterTime索引过滤耗时太低 → 索引没有生效
ExchangeTimeShuffle 耗时太高 → 可能数据倾斜或网络瓶颈
TotalTime算子总耗时对比各算子找瓶颈

4. Audit Log——查询审计

架构

每一条 SQL (查询/DDL/DML) 都会记录到 Audit Log 中,包含执行时间、扫描行数、返回行数、状态等。

源码导航

文件关键类/方法职责
fe/fe-core/.../qe/AuditLogHelper.javaAuditLogHelper, AuditEvent审计日志生成
fe/fe-core/.../plugin/AuditEvent.javaAuditEvent, EventType审计事件定义

日志格式

# fe/log/fe.audit.log
2026-07-08 10:00:00,123|query_id|user|db|SELECT ...|2000(ms)|120(tablets)|5000000(scanRows)|1000000(returnRows)|OK

5. 排障场景速查表

场景 1: 查询变慢——如何定位瓶颈

症状: 某个查询突然变慢 (从 1s → 10s)
排查路径:
  1. SHOW PROFILE → 找到 TotalTime 最大的 Fragment/Operator
  2. 检查 OlapScanOperator.RowsReturned vs RowsFiltered 比例
     → RowsReturned 远大于正常值 → 分区裁剪/索引过滤失效
     → RowsReturned 正常但 SegmentReadTime 高 → Compaction 问题 (Rowset 太多)
  3. 检查 ExchangeTime → Shuffle 是否成为瓶颈
  4. 检查 AggregationTime → 聚合是否在 BE 还是 FE 端 (fe 端聚合 = 慢)
  5. 检查 `ANALYZE TABLE` → 统计信息是否过期

场景 2: Compaction 跟不上写入

症状: 查询越来越慢, Profile 中 OlapScanOperator.TabletsScanned 持续增长
原因: Rowset Accumulation — 写入速度 > Cumulative Compaction 速度
排查路径:
  1. BE metrics: compaction_deltas_total (Compaction 合并 Delta 总数)
  2. show tablet <tablet_id> → Rowset 数量是否 > 20
  3. show proc "/cluster_balance" → 是否有 Compaction 积压
  4. 检查 BE CPU / IO 使用率 (Compaction 占用)
解决:
  1. 增大 max_cumulative_compaction_num_singleton_deltas (合并更多 Delta)
  2. 减少并发导入量
  3. 触发手动 Base Compaction

场景 3: FE 内存 OOM

症状: FE Full GC 频繁 / OOM
原因: 元数据过多 (Tablet 数超标) 或 Journal 积压
排查路径:
  1. FE metrics: fe_memory_used_bytes > 80% MaxHeap
  2. show proc "/statistic" → Tablet 总数 (建议 <100万)
  3. show proc "/cluster_balance" → Clone/Repair 任务积压
  4. FE log → "java.lang.OutOfMemoryError"
解决:
  1. 增大 FE JVM Heap (-Xmx)
  2. 清理不用的旧表/Database
  3. 减少 Tablet 数量 (增大 Bucket 大小)
  4. 减少 Journal 保留时间

场景 4: BE 磁盘满

症状: BE 磁盘使用率 > 90%, 写入被拒绝
排查路径:
  1. BE metrics: disk_total / disk_used
  2. show proc "/backends" → DiskUsedPercent
  3. BE 本地: du -sh /data/doris/data/*
解决:
  1. 触发垃圾回收 (GC 线程): 清理旧 Rowset, 清理 Trash
  2. 手动删除不再需要的 Partition/Table (先 DROP TABLE, 等待 GC)
  3. 触发 Base Compaction (合并 Rowset 释放空间)
  4. 扩容 BE / 加磁盘

场景 5: Publish 超时

症状: 数据导入成功, 但查询不可见 (延迟 >30s)
原因: PublishVersionTask 超时/积压
排查路径:
  1. FE metrics: publish_version_latency_ms
  2. show proc "/transactions/<db_id>" → 查看 PENDING 状态事务
  3. BE log: "PublishVersionTask timeout"
  4. 检查 BE 心跳是否正常 (TabletReport)
解决:
  1. 增大 publish_version_task_timeout_s
  2. 减少并发导入量
  3. 检查网络延迟 (FE→BE RPC)

场景 6: 数据倾斜

症状: 某些 BE 的 CPU/IO 远高于其他 BE
原因: 数据倾斜 — 某些 Tablet 过大或访问频率过高
排查路径:
  1. show proc "/statistic" → Tablet 大小分布 (min vs max)
  2. show proc "/tablets_distribution" → 按 BE 分布的 Tablet 数
  3. Profile: 某 SubTask 的 RowsScanned 远高于其他 Subtask
解决:
  1. 重新选择分桶键 (避免热点 Key)
  2. 增加 Bucket 数 (更均匀分布)
  3. 手动 Clone 热点 Tablet 到其他 BE

场景 7: Brpc 通信故障

症状: BE 间数据传输超时 / Fragment 执行失败
原因: Brpc Channel 超时 / 连接断开
排查路径:
  1. BE log: "backup request timeout" / "Channel timeout"
  2. BE metrics: brpc_endpoint_latency (P99)
  3. 网络: ping / netstat 检查 BE 间连通性
解决:
  1. 增大 rpc_timeout_ms
  2. 检查网络带宽 (Shuffle 阶段的网络使用)
  3. 启用 Backup Request (降低 P99 延迟)

场景 8: Memory Exceed Limit

症状: 查询被 Cancel: "Memory exceed limit"
原因: 查询内存使用超过 query_mem_limit (或 Workload Group 的 mem_limit)
排查路径:
  1. FE Audit Log: "Memory exceed limit" 错误
  2. Profile: 各算子的 PeakMemoryUsage
  3. BE metrics: memory_pool_bytes_used
解决:
  1. 增大 query_mem_limit / Workload Group mem_limit
  2. 减少并发查询数
  3. 优化查询: 减少 JOIN 大小, 增加过滤条件
  4. 使用 Broadcast Join (小表) 替代 Shuffle Join

Doris 监控 & 性能 & 排障 图 01

6. 监控栈推荐

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   Doris      │───►│  Prometheus  │───►│   Grafana    │
│  /metrics    │    │  (Pull/Push) │    │  (Dashboard) │
│  (FE + BE)   │    │              │    │              │
└──────────────┘    └──────────────┘    └──────────────┘
        │
        ▼
┌──────────────┐    ┌──────────────┐
│ Audit Log    │───►│ ELK (可选)    │
│ (fe.audit.log)│   │ 日志聚合+告警 │
└──────────────┘    └──────────────┘

Prometheus 配置示例

# prometheus.yml
scrape_configs:
  - job_name: 'doris-fe'
    static_configs:
      - targets: ['fe1:8030', 'fe2:8030', 'fe3:8030']
  - job_name: 'doris-be'
    static_configs:
      - targets: ['be1:8040', 'be2:8040', 'be3:8040']

Grafana Dashboard 建议面板

面板数据源关键报警
查询 QPS & 延迟FE metricsP99 > 10s
FE JVM HeapFE metrics> 80% alert
BE 内存 / 磁盘BE metricsDisk > 85%, Mem > 80%
Compaction 积压BE metricsPending compaction > 100
Publish 延迟FE/BE metricsP99 > 30s
Tablet 总数FE metrics> 1,000,000 alert
查询错误率FE auditError rate > 1%

7. 常见问题 / 面试题

Q1: Profile 中的 RowsReturned 比 RowsFiltered 大很多,说明什么? A: 说明索引过滤效果不好——大量数据从存储层读取但在上层被过滤。浪费了磁盘 I/O 和网络传输。需要检查: 谓词是否有合适的索引 (BloomFilter/Bitmap),ZoneMap 是否生效,分区裁剪是否生效。

Q2: 为什么 Show Tablet 看到 Rowset 数量持续增长? A: Cumulative Compaction 跟不上写入速度。每个写入产生一个 Delta Rowset,Compaction 负责合并。如果 Cumulative Compaction 频率和速度不够,Rowset 数量会增长。极端情况下(Rowset Runaway)会导致查询性能严重退化。

Q3: FE OOM 的主要原因有哪些? A: (1) Tablet 数量过多(建议 < 100万),每个 Tablet 在 FE 内存中有元数据条目; (2) Journal 积压(Checkpoint 间隔过长),FE 内存持有太多未 Checkpoint 的 Journal Entry; (3) 查询结果缓存过大(SQL Cache)。解决: 清理历史表/分区,减少 Tablet 数量,调整 Checkpoint 参数。

Q4: BE 磁盘写满后数据会丢失吗? A: 不会丢失,但写入会被拒绝。Doris 有磁盘保护机制: (1) 磁盘使用率 > 90% → 新 Tablet 不再分配给该 BE; (2) 磁盘使用率 > 95% → 拒绝写入请求。已有数据不受影响。需要及时扩容或清理。

Q5: Doris 的监控和排障中最容易被忽略的指标是什么? A: fe_journal_write_latency_ms(FE Journal 写入延迟)。这个指标异常高会导致: DDL 变慢 → FE 间复制变慢 → Follower 落后 → 查询返回旧数据。但这个指标不在常见监控面板中,经常到出问题时才发现。


下一步

恭喜! 你已经完成了 Doris 的全部 17 个学习文档 (doc-00 到 doc-16)。

下一步建议:

  1. 动手调试: 编译 Doris → 搭建本地 1FE+1BE 集群 → 用 MySQL Client 执行查询 → 断点跟踪调用链
  2. 阅读源码: 从架构图中的代码路径切入
  3. 参与社区: Apache Doris GitHub Discussion / Slack / 邮件列表
  4. 配置监控: Prometheus + Grafana 搭建本地监控