2. Databricks工作区与资产对象

在 Databricks DataOps 的持续交付语境里,“发布”并不是把一段代码推到某个分支就结束,而是把一组彼此依赖的工作区资产,作为一个可验证、可回滚的版本单元,从开发环境推进到测试与生产环境。要设计好这条流水线,第一步必须弄清楚:Databricks 工作区里到底有哪些东西是“可交付资产”,它们之间又通过什么关系互相绑定。如果资产边界和依赖关系没梳理清楚,后续的 CI/CD 就会出现“代码发布了但任务跑不起来”“表重建了但模型找不到特征”这类典型故障。

一、六类核心可交付资产

Databricks 工作区中参与交付的资产,可以按“计算、代码、编排、数据、模型、版本”六个维度归类:

  • Cluster(集群):计算资源定义,包括 Spark 版本、节点类型、自动伸缩范围、库依赖、Spark 配置与环境变量。它本身不是业务逻辑,但决定了 Notebook 与 Job 能否以预期方式运行。
  • Notebook(笔记本):交互式代码载体,通常承载 ETL 逻辑、探索性分析或模型训练脚本。它既是开发入口,也是 Job 最常见的执行单元。
  • Job(作业):编排与调度单元,定义任务 DAG、触发方式(定时、文件到达、连续)、重试策略、告警与依赖任务。Job 把 Notebook、SQL、JAR、DLT 管道等串成一条可调度的执行链。
  • Repo(仓库):与 Git 集成的代码仓库对象,把 Notebook 和源码文件纳入版本控制,是 CI/CD 的代码来源。
  • Delta Live Tables(DLT):声明式数据管道,用 @dlt.table 等注解定义流式或批式表,由管道负责依赖解析、增量处理与数据质量约束。
  • MLflow:模型与实验管理资产,包括 Experiment、Run、Model Registry 中的模型版本与阶段(Staging/Production)。

二、依赖关系:谁绑定谁

这些资产不是并列的,而是形成一张有向依赖图。理解这张图,才能判断“改一个对象要连带发布哪些对象”。

最底层是 Repo:Notebook 与源码文件从 Repo 检出,因此 Repo 是代码的版本源头。Notebook 需要 Cluster 提供运行环境,Cluster 上的库版本、Spark 配置会直接影响 Notebook 行为。Job 引用 Notebook 路径或 DLT 管道 ID,并绑定一个 Job Cluster(或复用 All-Purpose Cluster),因此 Job 同时依赖 Notebook 与 Cluster。DLT 管道本身由 Job 触发,或独立调度,其输出是 Delta 表,供下游 Notebook、Job 或 MLflow 训练任务消费。MLflow 训练任务读取 Delta 表作为特征,产出模型版本,模型再被推理 Job 或 Serving 端点加载。

由此可以归纳出一条主依赖链:Repo → Notebook → Cluster → Job → DLT → Delta 表 → MLflow 模型。但真实场景中依赖是网状的:一个 Job 可能引用多个 Notebook,一个 Notebook 可能被多个 Job 复用,一个 DLT 管道可能同时被多个下游 Job 读取。发布时必须识别“共享资产”,否则一次变更可能影响多个业务线。

Databricks 可交付资产依赖关系图 实线箭头 = 运行时依赖 虚线箭头 = 版本/引用关系 Repo Git 仓库 / 分支 Notebook ETL / 训练脚本 Cluster 计算 / 库 / 配置 Job 调度 / DAG / 重试 DLT 管道 声明式数据管道 Delta 表 Bronze/Silver/Gold MLflow 模型 / 实验 / Registry 检出 运行于 被引用 绑定计算 触发 写入 读取特征 训练任务 图例 运行时依赖 版本 / 引用 计算绑定 发布顺序建议 1. Repo 分支合并 2. Cluster 配置同步 3. Notebook 导入 4. Job / DLT 更新 5. Delta 表校验 6. MLflow 模型注册

三、依赖关系对发布顺序的约束

依赖图直接决定了发布顺序。如果先更新 Job 再更新 Notebook,Job 可能在旧代码上触发一次错误运行;如果先重建 Delta 表再更新 DLT 管道,下游读取可能读到不兼容的 schema。因此一个稳妥的发布顺序是:先合并 Repo 分支并同步 Cluster 配置,再导入 Notebook,然后更新 Job 与 DLT 管道定义,接着校验 Delta 表结构与数据质量,最后注册 MLflow 模型版本并切换 Serving 端点。

这里有一个容易被忽略的点:Cluster 的库依赖也是可交付资产的一部分。如果 Notebook 代码依赖 pandas==2.0.3,而生产 Cluster 上装的是 pandas==1.5.3,代码在开发环境通过、在生产环境报错。因此 Cluster 的库列表、Spark 配置、环境变量应当与代码一起纳入版本管理,而不是手工在 UI 上维护。

四、用配置清单固化资产与依赖

为了让 CI/CD 能自动识别“这次变更涉及哪些资产”,建议在仓库中维护一份资产清单。下面是一个可直接参考的示例,字段只保留与发布强相关的信息:

# databricks_assets.yaml
assets:
  - name: etl_orders_bronze
    type: notebook
    path: /Repos/prod/data-eng/notebooks/etl_orders_bronze
    cluster: job_cluster_etl
    depends_on: []

  - name: dlt_orders_silver
    type: dlt_pipeline
    path: /Repos/prod/data-eng/pipelines/orders_silver
    cluster: job_cluster_dlt
    depends_on: [etl_orders_bronze]
    target_table: prod.silver.orders

  - name: job_orders_daily
    type: job
    tasks: [etl_orders_bronze, dlt_orders_silver]
    schedule: "0 0 2 * * ?"
    depends_on: [dlt_orders_silver]

  - name: model_orders_forecast
    type: mlflow_model
    experiment: /Repos/prod/data-eng/experiments/orders_forecast
    source_table: prod.silver.orders
    depends_on: [dlt_orders_silver]

这份清单的价值在于:CI 脚本可以解析 depends_on 字段,自动计算发布拓扑顺序,并在发布后按依赖链逐级验证。例如先确认 etl_orders_bronze 的 Notebook 能成功运行,再触发 dlt_orders_silver 管道并检查 prod.silver.orders 的行数与 schema,最后才注册模型。

判断依据:发布后不要只看 Job 状态是否为 SUCCESS。应同时检查:Delta 表的最新版本号是否递增、DLT 管道的事件日志中是否有 flow_progress 异常、MLflow Run 的指标是否落在预期区间。只有这三层都通过,才能认为依赖链完整交付。

五、共享资产与影响面分析

最后要强调共享资产的风险。假设 etl_orders_bronze 这个 Notebook 同时被“订单日报 Job”和“库存预测 Job”引用,那么修改它的输出 schema 就会同时影响两条业务线。在发布前,应当通过资产清单反向查询:哪些 Job、DLT 管道、MLflow 实验引用了这个 Notebook? 如果影响面超过一个业务域,就需要拆分 Notebook 或增加兼容层,而不是直接覆盖发布。

把资产对象、依赖方向、发布顺序和影响面这四件事梳理清楚,Databricks 的持续交付才有稳定的基础。后续的 CI/CD 流水线设计、环境晋级策略和回滚方案,都建立在这张依赖图之上。