预计阅读时间: 60 分钟 前置阅读: 全部 Doris 课程, 尤其是 doc-01, doc-03, doc-04, doc-06 下一次阅读: doc-26(可观测数据最佳实践)
1. 专家的最后一公里
从使用者到专家, 有一道分界线:
能解释现象
→ 能定位源码
→ 能构造复现
→ 能修改并验证
→ 能把风险讲清楚
你不一定每天给 Doris 提 PR, 但如果要成为这一领域的专家, 至少要能:
- 从 SQL 找到 FE/BE 调用链。
- 根据 Profile 定位到 Operator 或 Storage 模块。
- 本地复现一个查询、导入或 Compaction 问题。
- 看懂测试失败。
- 写出最小修复或最小验证 patch。
参考:
- https://github.com/apache/doris
- https://doris.apache.org/community/how-to-contribute/
- https://doris.apache.org/docs/4.x/admin-manual/trouble-shooting/memory-management/memory-issue-faq/
2. 源码地图回顾
fe/
fe-core/
mysql/ MySQL 协议入口
qe/ ConnectContext、Coordinator、StmtExecutor
nereids/ 新优化器
catalog/ 元数据模型
transaction/ 事务管理
load/ 导入任务
persist/ Journal / EditLog
be/
src/
exec/ 算子和旧执行框架
exec/pipeline/ Pipeline 执行引擎
vec/ 向量化表达式和列类型
storage/ Tablet、Rowset、Segment、Compaction
runtime/ RuntimeState、MemTracker、RuntimeFilter
service/ Thrift/BRPC/HTTP 服务
common/ Metrics、配置、工具
定位入口:
| 问题 | 入口 |
|---|---|
| SQL 解析和执行 | ConnectProcessor, StmtExecutor |
| 优化器规则 | fe-core/.../nereids |
| Fragment 调度 | Coordinator |
| Pipeline 执行 | PipelineTask, Operator |
| Scan 慢 | OlapScanOperator, SegmentIterator |
| 写入问题 | StreamLoad, DeltaWriter, MemTable |
| Compaction | Compaction, Tablet |
| 元数据异常 | Catalog, EditLog, BDBJE |
3. 从 Query ID 到源码
一次慢查询的源码定位:
query_id
→ audit log 找 SQL
→ EXPLAIN 找计划
→ Profile 找最慢 Operator
→ Operator 名称映射到 BE 类
→ 找指标和日志
→ 构造最小复现
例如 Profile 显示 OlapScanOperator 慢:
- 检查 Partition/Tablet 裁剪。
- 检查 Segment 数和 Rowset 版本。
- 检查索引过滤指标。
- 进入
be/src/exec/operator/olap_scan_operator.*。 - 继续追
SegmentIterator,BlockReader, index reader。
如果是 HashJoinProbeOperator 慢:
- 看 Build/Probe 行数。
- 看 RuntimeFilter 是否生效。
- 看 Exchange 是否倾斜。
- 进入 Join Operator 和 Hash Table 实现。
4. 最小复现
优秀 issue 或 PR 的起点是最小复现。
CREATE TABLE repro_t
(
dt DATE,
k BIGINT,
v STRING
)
DUPLICATE KEY(dt, k)
PARTITION BY RANGE(dt)
(
PARTITION p20260727 VALUES [('2026-07-27'), ('2026-07-28'))
)
DISTRIBUTED BY HASH(k) BUCKETS 3;
INSERT INTO repro_t VALUES
('2026-07-27', 1, 'a'),
('2026-07-27', 2, 'b');
EXPLAIN SELECT * FROM repro_t WHERE dt = '2026-07-27' AND k = 1;
复现要求:
- 数据量尽量小。
- SQL 尽量短。
- 表结构保留关键属性。
- 参数明确。
- 预期结果和实际结果都写清楚。
- 如果是性能问题, 给出前后 Profile。
5. FE 调试思路
FE 是 Java, 常见关注:
- 解析、分析、权限。
- Nereids 计划生成。
- 统计信息和代价。
- Catalog 元数据。
- Journal 和 HA。
- Load Job 调度。
调试策略:
1. 用日志定位请求入口
2. 在 StmtExecutor / Nereids 入口加断点
3. 打印 Logical Plan 和 Physical Plan
4. 检查 Session Variable
5. 检查统计信息
6. 用单元测试固定复现
常见输出:
EXPLAIN VERBOSE SELECT ...;
不要只看最终计划, 要看规则为什么没有触发:
- Pattern 不匹配。
- 统计缺失。
- Session 开关关闭。
- 语义不等价。
- 成本比较没有获胜。
6. BE 调试思路
BE 是 C++, 常见关注:
- Pipeline 调度。
- 向量化表达式。
- Scan 和索引。
- Join/Aggregation/Sort。
- 内存和 Spill。
- Storage 和 Compaction。
调试策略:
1. Profile 确认 Operator
2. 打开相关日志
3. 找到 Operator::get_block / sink / close
4. 检查 RuntimeState 和 MemTracker
5. 检查 Block 行数和列类型
6. 用小数据复现
7. 写 BE 单元测试或回归 SQL
性能问题要避免只凭感觉改代码。至少用一种证据:
- Profile 前后对比。
- 火焰图。
- 指标变化。
- 微基准。
- 回归测试。
7. 测试分层
| 层级 | 用途 |
|---|---|
| FE 单元测试 | 解析、分析、优化器规则 |
| BE 单元测试 | 数据结构、表达式、存储组件 |
| Regression SQL | 端到端 SQL 行为 |
| P0/P1 用例 | 核心稳定性 |
| 性能基准 | 防止优化退化 |
一个专家级修复必须回答:
- 覆盖了哪个失败场景。
- 是否影响兼容性。
- 是否影响性能。
- 是否影响存量数据。
- 是否需要配置开关。
- 如何回滚。
8. 选择第一个贡献点
不要一上来改 Nereids 大规则或存储格式。更好的起点:
- 文档修正或示例补充。
- 错误信息优化。
- 小型 SQL 回归用例。
- Profile 指标展示补充。
- 明确边界的小 bug。
- 某个函数或类型的兼容问题。
避开:
- 需要重构多个子系统的问题。
- 没有复现的性能优化。
- 只在本地环境出现的模糊 bug。
- 缺乏测试的行为改动。
9. 专家成长路线
阶段 1: 会用
建表、导入、查询、看 Profile
阶段 2: 会调
解释慢 SQL、调表结构、调 MV、管资源
阶段 3: 会运维
处理副本、扩容、备份、升级、事故
阶段 4: 会读源码
能把现象定位到 FE/BE 模块
阶段 5: 会贡献
能复现、修复、测试、说明风险
最后的学习方式:
- 找 5 条真实慢 SQL, 写完整调优报告。
- 做一次从 Kafka 到 Doris 的 CDC POC。
- 设计一套日志/Trace/指标表。
- 演练一次 BE 下线和副本修复。
- 给 Doris 提一个文档或测试 PR。
一句话总结:
Doris 专家的标志不是记住所有参数, 而是能把业务问题、运行证据、源码路径和可验证修复连成闭环。