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 读取。发布时必须识别“共享资产”,否则一次变更可能影响多个业务线。
三、依赖关系对发布顺序的约束
依赖图直接决定了发布顺序。如果先更新 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,最后才注册模型。
flow_progress 异常、MLflow Run 的指标是否落在预期区间。只有这三层都通过,才能认为依赖链完整交付。
五、共享资产与影响面分析
最后要强调共享资产的风险。假设 etl_orders_bronze 这个 Notebook 同时被“订单日报 Job”和“库存预测 Job”引用,那么修改它的输出 schema 就会同时影响两条业务线。在发布前,应当通过资产清单反向查询:哪些 Job、DLT 管道、MLflow 实验引用了这个 Notebook? 如果影响面超过一个业务域,就需要拆分 Notebook 或增加兼容层,而不是直接覆盖发布。
把资产对象、依赖方向、发布顺序和影响面这四件事梳理清楚,Databricks 的持续交付才有稳定的基础。后续的 CI/CD 流水线设计、环境晋级策略和回滚方案,都建立在这张依赖图之上。