七月月报:vanilla 对照组 ——bug 归属的实验法
覆盖范围:7.6 / 7.13 / 7.20 / 7.27 四周。本月工作背景一句话:在华为实习,研读鲲鹏 Omni 大数据加速生态并完成首批 SQL 表达式开发,月底调研九问 Agent 生态。
本月方法地图
mindmap
root((七月方法))
源码研读
模块关系图先行
主线切入到源码层
开发验证
编译地图
vanilla 对照组
结论文档化
经验沉淀
审计进流程
skill 固化重复动作
Agent 调研
声明式编排
动态生成执行原理深读:崩溃了,先问 "这是谁的 bug"
是什么:修 bug 前先做归属判断。方法是把同一用例同时跑在 vanilla(原生 Flink)和 native(自研加速引擎)上对照:vanilla 也崩 → 上游问题;vanilla 正常、native 崩 → 自己的问题。
为什么成立(机理):修复决策完全取决于归属 —— 上游 bug 自己修不了,白改代码;自研 bug 不修就是漏。但直觉归因不可靠:本月 BETWEEN 表达式的崩溃,投影 + CAST 路径和 filter 路径都是 "跑 BETWEEN 就崩",崩溃栈却完全不同,直觉会把两类问题混成一类。对照实验把 "归属" 从猜测变成可观测事实:同一个输入在参照系上能否复现,就是归属的判据。这是控制变量实验在调试里的直接应用 —— 参照系消掉了所有共同变量,剩下的差异就是问题所在。
本月结论:
flowchart TD
A[BETWEEN 用例崩溃] --> B{vanilla 是否也崩}
B -->|是| C[上游 bug<br/>Calcite Sarg.isComplementedPoints<br/>记录 + 测试规避]
B -->|否| D[自研 bug<br/>FilterCodeGen 生成 BetweenExpr 崩溃<br/>自己修复]- 投影 + CAST 路径:vanilla 同样崩溃,栈在
Sarg.isComplementedPoints←ImmutableRangeSet.span。事后查证这确是上游已知缺陷 CALCITE-5722——"Sarg.isComplementedPoints fails with anti-points which are equal undercompareTobut notequals":1与1.00000000000在BigDecimal.equals下不等、在compareTo下相等,范围集判断用错了相等语义。该 issue 直到 Calcite 1.35.0 才修复(2023-07 关闭),官方只标注影响 1.34.0,而 Flink 1.16 内置的是 Calcite 1.26.0(release-1.16 分支 pom 可查)——1.26.0 是否中招,直接依据是 vanilla 实测复现。归属上游,测试主动规避这类输入。 - filter 路径:vanilla 正常、native 崩溃,根因在自研 FilterCodeGen,属于自己,本周修复。
配套动作同样重要:上游 bug 的正确处置不是修(不在你的代码里),而是记录 + 让测试规避;排查结论写成可交接文档 —— 临时结论会丢,文档才是团队资产。
边界在哪:
- 对照必须同版本同输入:vanilla 与 native 的 Flink 基线要一致(1.16.3),否则差异可能来自版本差而不是归属差。
- 环境相关的 bug 两边可能都不崩 —— 对照组阴性不等于没有 bug,只说明这个用例分不出归属。
- 有的问题没有现成参照系(纯自研模块),此时用 "最小复现用例" 替代:把输入裁剪到最小,让归属自然浮现。
原理清单
- 模块关系图是路线图:多模块项目先画模块关系、定切入重点,再钻代码。Omni 生态四个仓库,先确定 Adaptor-Flink → OmniStream 这条链路,阅读才有方向。
- 编译地图是开发验证的地基:把 "依赖 → 安装脚本 → 产物 → 运行时依赖" 记成可复现步骤(OmniStream 依赖 JDK、BoostKit、LLVM、rocksdb 等几十个库)。先解决 "能跑起来",再谈 "跑得好"—— 没有验证链路,代码写了也不敢说能用。
- 调研大系统抓一条主线:选一个贯穿全流程的概念(这里是 skill)挖到源码层,用代码验证文档。到处看文档建立不了真实理解 —— 文档和实际行为可能对不上。
- 声明式编排 + 动态生成:源码级调研到的九问链路 ——skill 定义
workflow.md(声明子 agent、上下文、工具)→ 框架按条件生成workflow.py执行。注意:公开 README 只写到 "用 Python 脚本定义确定性多阶段工作流",声明式生成机制是源码层结论、非官方文档记载。它与微软 Agent Framework "把编排定义为数据(YAML)而非代码" 是同一思路 —— 业务用可读声明描述,执行交给框架,复杂多步骤任务既可控又可扩展。 - 经验沉淀到流程,不沉淀到记忆:人工审计迟早会漏。把项目特有注意点提炼进审计 skill,开发完自动触发 —— 经验在所有后续开发里持续生效,而不是依赖 "这次记得"。
- 重复动作固化成 skill:环境搭建、构建、测试固化后变成 "一条命令",出错概率和上手成本同时下降。
- 环境受限时做纯脑力工作:网卡没到位的那周正好读源码、理架构、写总结;环境就绪立即进入开发验证。等待不等于空转。
- 学习周留消化时间:连续输入不整理,吸收效率反而低。周期性复盘是输入流程的一部分。
反例与边界
- 把上游缺陷当自己的修(反例):不在自己代码里的 bug,改自己的代码属于白费功,正确处置是记录 + 规避。
- 只读文档不看代码(反例):文档描述与实际行为可能不一致,关键机制必须用代码验证。
- 对照组的局限:见深读边界 —— 版本不一致或环境相关 bug 会污染归因。
参考资料
- OmniOperator(openEuler) — C++ native 算子加速引擎官方仓库。
- OmniRuntime 大数据套件(鲲鹏 BoostKit) — 华为官方对算子 Native 化加速的整体介绍。
- OmniAdaptor(openEuler) — Spark / Flink 算子替换适配层,当前基线正是 Flink 1.16.3。
- OmniStream(openEuler) — 流计算 native 加速引擎仓库,表达式开发所在。
- Flink 1.16: Working with State / Windows / Checkpointing — 状态、事件时间窗口、容错三大核心机制的官方文档。
- Apache Calcite SQL Reference — BETWEEN / LIKE / IN / EXISTS 等表达式的权威定义。
- CALCITE-5722 —
Sarg.isComplementedPoints崩溃的上游 issue(2023-07 关闭,Fix Version 1.35.0)——vanilla 对照组结论的直接证据。 - Flink release-1.16: flink-table/pom.xml —
<calcite.version>1.26.0</calcite.version>,Flink 1.16 内置 Calcite 版本的直接出处。 - openJiuwen agent-core — 九问 Agent 核心 SDK 官方仓库。
- openJiuwen jiuwenswarm — 多智能体协同框架官方仓库。
- Microsoft Agent Framework: Declarative Workflows 1.0 — "编排定义为数据而非代码" 的业界对应,与 workflow.md → workflow.py 同构。