3. 集群配置与成本优化基础

在 Databricks 上跑机器学习任务,成本的大头几乎永远落在计算资源上。同一份训练代码,集群配置不同,账单可能相差数倍。理解集群类型、节点类型、自动伸缩以及 Spot 与按需实例的权衡,是后续所有性能与成本优化的地基。本节先把这些基础概念讲清楚,再落到实际配置与判断依据上。

三类集群:先选对"跑道"

Databricks 提供三种主要的计算形态,它们的计费方式、生命周期和适用场景差异很大,选错类型往往是最容易被忽视的成本浪费。

All-Purpose(通用)集群用于交互式开发,比如在 Notebook 里探索数据、调试特征工程、反复试跑小规模模型。它支持多人共享、可手动启停、可挂载库和配置环境,但计费单价最高,且只要处于运行状态就持续计费——哪怕你只是开着页面发呆。因此它适合"人在电脑前、需要反复交互"的阶段,任务跑完应及时终止。

Job 集群由作业调度自动创建,作业结束即销毁,单价通常低于 All-Purpose,且支持更激进的自动伸缩与 Spot 策略。它适合生产化的训练、批量推理、定时特征计算等无人值守场景。核心原则是:能放到 Job 集群上跑的,就不要用 All-Purpose 集群常驻。

SQL Warehouse面向 SQL 分析与 BI 查询,采用独立的计算模型,按查询或按运行时长计费,支持 Serverless 与多集群伸缩。它一般不用于 Python 模型训练,但在特征查询、指标看板、数据校验环节会与 ML 流程配合。若你的"训练"其实主要是大宽表 SQL 聚合,用 SQL Warehouse 可能比 Spark 集群更划算。

判断口诀:交互调试用 All-Purpose,生产任务用 Job,纯 SQL 分析用 SQL Warehouse。三者不要混用,尤其别把生产作业挂在常驻的 All-Purpose 集群上。

节点类型:Driver、Worker 与实例族

一个 Databricks 集群由一台 Driver 节点和若干 Worker 节点组成。Driver 负责调度、协调、维护 Spark 上下文,并运行 Notebook 主逻辑;Worker 执行实际的分布式计算。对机器学习而言,Driver 内存不足会导致收集结果、广播模型或聚合指标时 OOM,因此当你在 Driver 上做 collect()、训练单机模型或处理大广播变量时,要给它留足内存。

Worker 节点按实例族划分,常见的有:

  • 通用型(General Purpose):CPU 与内存均衡,适合大多数 ETL 与特征工程。
  • 计算优化型(Compute Optimized):高主频 CPU,适合单线程密集的 Python 训练、XGBoost/LightGBM 等。
  • 内存优化型(Memory Optimized):大内存,适合大宽表 join、缓存、图计算。
  • GPU 型:带 A100/V100 等加速卡,适合深度学习训练与微调,单价高但单位算力效率可能更高。

选择节点时不要只看单价,要看"单位任务成本"。例如一个深度学习训练任务,用 8 台 CPU 节点跑 6 小时,可能不如 2 台 GPU 节点跑 1 小时——后者总费用更低,且迭代更快。判断依据是:先估算任务的计算特征(是否 GPU 友好、是否内存瓶颈、是否 IO 瓶颈),再选实例族,最后用自动伸缩控制规模。

自动伸缩:让集群跟着负载走

自动伸缩通过设置最小和最大 Worker 数,让集群在负载高时扩容、空闲时缩容。它有两种模式:

  • 标准自动伸缩:基于集群当前负载动态调整,扩容相对保守,适合负载波动平缓的场景。
  • 优化自动伸缩:针对 Spark 任务更积极地增减节点,缩容更快,适合 Job 集群和波动明显的批处理。

配置时常见的误区是把最小值设得过高。比如 min=4, max=16,即使任务只需 1 个节点,也会常驻 4 个 Worker 持续计费。更合理的做法是 min=1 或 2, max=按峰值估算,让空闲时真正缩下去。但要注意:缩容有延迟(通常几分钟),且缩容后重新扩容需要时间,对延迟敏感的交互式场景不宜把 min 设得过低。

另一个关键点是分区与并行度。自动伸缩的效果取决于任务能否被切分成足够多的并行单元。如果数据倾斜严重,扩容出来的节点可能闲置,钱花了但没提速。因此自动伸缩要配合合理的分区策略一起调。

Spot 实例与按需实例的权衡

Spot 实例(云厂商的抢占式实例)价格通常只有按需实例的 30%~70%,但可能被云厂商随时回收。Databricks 允许在集群中混合使用两者,典型策略是:Driver 用按需实例保证稳定,Worker 用 Spot 实例降低成本。

Spot 被回收时,运行在该节点上的 task 会失败并重试,Spark 的容错机制会把它调度到其他节点。因此 Spot 适合"可重试、无状态、任务粒度小"的计算,比如特征转换、批量推理、数据清洗。而以下场景应谨慎或避免使用 Spot:

  • 长时间运行的单个 task(回收后重试代价大);
  • 需要保存中间状态且不易重建的训练;
  • 对完成时间有硬性 SLA 的生产作业。

实践中可以用"按需保底 + Spot 扩容"的组合:设置一定数量的按需 Worker 保证基础进度,其余用 Spot 承担弹性部分。这样即使 Spot 大面积回收,任务仍能推进,只是变慢。

集群类型与实例策略选择图 All-Purpose 集群 交互式开发 / 调试 单价最高,常驻计费 用完必须终止 Job 集群 生产训练 / 批量推理 作业结束即销毁 支持 Spot + 自动伸缩 SQL Warehouse SQL 分析 / BI / 特征查询 按查询或时长计费 Serverless 可弹性伸缩 集群节点结构 Driver 节点 调度 / 协调 / 主逻辑 Worker 节点 ×N 分布式计算 / 可伸缩 实例族选择 通用/计算/内存/GPU 实例采购策略:按需保底 + Spot 弹性 按需实例(On-Demand) 稳定不回收 · 单价高 用于 Driver 与保底 Worker Spot 实例(抢占式) 价格低 30%~70% · 可能被回收 用于可重试的弹性 Worker

一个可参考的配置示例

假设你有一个每日运行的特征工程 + LightGBM 训练作业,数据量约 200 GB,训练耗时对完成时间要求是"当天出结果即可",没有严格 SLA。一个合理的起点配置如下(示例参数,需按实际数据量调整):

集群类型: Job 集群
Driver:  按需实例, 计算优化型, 16 vCPU / 64 GB
Worker:  计算优化型, 8 vCPU / 32 GB
自动伸缩: min=2, max=12 (优化模式)
实例组合: 2 台按需保底 + 最多 10 台 Spot
Spark 配置: spark.sql.shuffle.partitions=400
            spark.databricks.cluster.profile=serverless 不适用, 保持默认

运行后要观察几个信号:如果任务大部分时间只有 2~3 个 Worker 在跑,说明 max 设得过高或数据并行度不足;如果频繁出现 Spot 回收导致 task 重试,日志里会有节点丢失记录,此时应提高按需保底数量;如果 Driver 内存告警,则升级 Driver 规格。这些观察点比盲目调参更有效。

成本优化不是一味压低配置。配置过小会导致任务超时、重试、甚至失败,反而更贵。正确做法是先保证任务能在合理时间内稳定完成,再逐步压缩空闲资源与单价。

把本节的选择逻辑串起来:先按场景选集群类型,再按计算特征选节点族,然后用自动伸缩控制规模,最后用 Spot 与按需的组合压低单价。这四步是后续所有优化的基础,任何一步选错,后面的调优都会事倍功半。