Databricks 的开发人员最佳做法

本页提供数据工程和开发生命周期的最佳做法,包括版本控制、环境管理、开发人员工具和托管部署。

源代码管理

对所有文件进行版本控制

声明性自动化基于以下概念构建:如果某些内容不在版本控制中,则不存在。 因此,Databricks 建议你对几乎所有文件进行版本控制,包括:

  • 所有笔记本和源文件(.py.sql
  • 打包配置文件(databricks.yml 和针对特定环境的 YAML 覆盖配置)

但是,请勿提交:

  • 构建产物,例如 .jar.whl 文件。 相反,在 CI 期间将编译的二进制文件上传到 Unity 目录卷。 请参阅 上传 JAR
  • 令牌或凭据。 使用云机密管理器(例如 AWS 机密管理器或 Azure 密钥保管库)支持的工作区级机密管理,并将值同步到 Databricks 机密范围。 请参阅机密管理
  • 具有 PII 的本地数据示例和文件。 使用 .gitignore 来排除它们。

单个存储库

Databricks 建议对所有代码(源代码和配置文件)使用单个存储库,因为它使协作和代码和最佳做法共享为人类和 AI 更加容易。 如果有多个捆绑包用于单独的部署生命周期,请将它们保存在单个存储库中。

单个存储库建议的一个例外是在受管制的行业,因为出于保密目的,需要多个存储库。

主干式分支策略

若要最大程度地减少合并冲突并确保主分支始终处于可部署状态,请使用基于中继的分支策略。

简单的工作流是:

  1. 在本地或工作区中进行开发,并部署到 Databricks 开发工作区以测试更改。
  2. 创建一个短期的功能分支,对更新进行版本控制,并定期同步本地或工作区中的更改。
  3. 测试完成后,将功能分支合并到主分支。
  4. CI/CD 会自动将主分支部署到过渡工作区,并触发自动测试。
  5. 过渡测试和检查通过时,CI/CD 会将主分支部署到生产工作区。

下图概述了这些步骤:

声明性自动化的 CI/CD 套件分支策略

工作区配置

隔离工作区环境

隔离工作区环境,尽量减少部署失败的影响。 例如:

  • 小型团队(最多 5 名数据工程师):从单个云帐户中的两个工作区(开发和生产)开始。
  • 不断增长的团队(5+ 数据工程师):迁移到三个工作区(开发、过渡和生产)。 预发布环境在功能上应能真实反映生产环境——具有相同的打包配置、模式和关键集成——即使其规模有所缩减。
  • 受监管行业 (银行、医疗保健、防御):物理隔离工作区和云帐户,以防止数据泄露。 可以在单一账户中通过 IAM 和 Unity Catalog 边界来实现隔离,但这种方式的安全性较弱。

对于生产工作区,请尽可能使用结合网络策略的无服务器计算。 否则,请将云帐户配置为使用具有严格控制的出口和网络安全控制的专用子网或 VNet。

有关详细信息,请参阅 基于上下文的网络策略

隔离数据存储

  • 使用单个 Unity 目录元存储,并为开发、暂存(如果适用)和生产创建单独的目录,以镜像工作区布局。
  • 对于开发和暂存(非生产)目录,请为各个开发人员使用个人架构。
  • 仅在 ISOLATED 模式下将生产目录绑定到生产工作区。 将目录的隔离模式设置为 ISOLATED 可确保开发或暂存环境无法访问生产数据,即使身份配置有误也是如此。
  • 仅为具有法规、数据主权或多区域要求的组织保留单独的元存储、帐户或区域,目录级隔离无法满足这些要求。

将表和列元数据视为代码

将表和列注释视为代码的一部分。 将它们保存在 .sql 文件中,并与您的声明式自动化捆绑包定义一同存放,再通过元数据作业进行部署,以确保始终提供准确的面向业务的定义。 编写注释,用通俗易懂的语言说明每一行表示什么、单位是什么以及有效取值,而不要只是重复列名。

配置个人架构

在开发过程中,将捆绑包配置为使用每个用户的个人架构,例如 dev_${user_name}。 这可防止开发人员在共享工作区中覆盖各自的表。

使用无服务器计算

使用无服务器计算来简化群集管理和优化成本。 请参阅连接到无服务器计算

CI/CD 建议

CI/CD 的声明式自动化套件

声明性自动化捆绑包(以前称为 Databricks 资产捆绑包)提供了一种强大的统一方法来管理 Databricks 生态系统中的代码、工作流和基础结构,建议用于 CI/CD 管道。

有关对 CI/CD 工作流使用捆绑包的其他详细信息,请参阅 Databricks 上的 CI/CD 工作流

有关声明性自动化捆绑包的详细信息,请参阅 什么是声明性自动化捆绑包?

仅对外部资源使用 Terraform

使用 Terraform 定义以下资源:

  • 云级别和外部资源
  • 非特权用户不应执行的管理员操作,例如工作区预配或云网络配置

对于所有其他 Databricks 资源,请使用声明性自动化捆绑包。

捆绑管理

创建较小的打包文件

Databricks 建议开发多个小型、聚焦的捆绑包,而不是一个大型捆绑包。

  • 将单个团队拥有的所有内容放入一个捆绑包中。
  • 通过共享相同生命周期和发布节奏的同一 CI/CD 管道进行测试和部署。
  • 每个捆绑包都应涵盖给定项目(开发、过渡、生产)的所有环境,而不是为每个环境使用单独的捆绑包。

为以下项创建单独的捆绑包:

  • 不同的产品或域,例如“计费分析”和“欺诈检测”
  • 不同的所有权或权限边界
  • 具有明显不同生命周期的工作负荷
  • 需要独立升级或回滚的情况

使用 sync.paths 同步共享文件夹

在一个存储库中管理多个包时,使用 sync.paths 来同步包根目录外部的共享文件夹。 这样,不同的项目就可以共享公共库文件夹,例如 ../common,同时维护单独的部署标识。

在 CI/CD 中对捆绑包之间的依赖关系进行建模

当包 B 依赖于包 A 发布的资源时,应在 CI/CD 或编排层中对这种依赖关系进行建模,而不是将两者合并成一个包。

  • 使捆绑 A 的部署和发布工作流成为捆绑 B 的显式先决条件。连接管道,以便捆绑 B 仅在捆绑 A 的部署成功且所有必需的验证检查通过后才启动。
  • 将已发布的资产标识符或位置作为管道输入传递,如果上游资产缺失,则快速失败。 这可确保 Bundle B 绝不会在部分已发布的状态下部署。

有关捆绑包共享的详细信息,请参阅 共享捆绑包和捆绑文件

自定义捆绑包模板

将自定义声明性自动化捆绑包模板用作新项目的默认起点,以便每个项目都继承相同的防护栏(权限、标记、群集策略、CI/CD 线路和实例基线),而无需每个团队从头开始解决。

模板应对共享的生存期约定(如治理、性能默认值、环境布局和配额限制)进行编码。 避免在模板中包含应用专属的业务逻辑、敏感信息或临时性配置。

仅将预计会随团队、项目或环境变化的输入参数化:

  • 项目或应用程序名称
  • 目标工作区设置
  • 目录或架构名称
  • 服务主体标识符
  • 计划和通知设置

保留模板中固定的平台防护和共享默认值,而不是参数化它们。

有关自定义捆绑模板以及如何创建它们的信息,请参阅 声明性自动化捆绑包项目模板

规划回滚和热修复

将捆绑包控制得足够小,这样你就可以只针对单个捆绑包执行回滚,而不必协调多个互不相关的工作负载一起回滚。

事件期间:

  1. 将受影响的捆绑包还原或回滚到最近一个已知正常的版本。
  2. 仅将热修复用于无法等待正常发布流程的紧急且影响范围有限的修复。
  3. 验证后立即将所有修补程序合并回主分支,使中继保持单一事实来源。

通用开发

使用服务主体或 OIDC

对所有非开发自动化使用服务主体将自动化工作流与单个用户帐户分离,并确保在内部用户离开时作业继续运行。 请参阅 服务主体

  • 对部署和运行时使用单独的服务主体。 捆绑部署的专用部署服务主体应具有最少的数据访问。 每个生产作业或管道都应有自己的运行即服务主体,其范围仅限于工作负荷所需的数据和资源。 这种分离可确保在轮换或收紧数据访问权限时部署保持安全,并避免将基础结构更改与生产数据访问耦合。
  • 受管制行业:将工作负荷标识联盟(OIDC)用于 CI/CD。 这消除了GitHub Actions或Azure DevOps中长期存在的机密。 请参阅 在 CI/CD 中启用工作负荷标识联合

使用 Databricks 开发工具

使用 Git 文件夹或本地 IDE 在 Databricks 工作区 UI 中进行开发。 如果您使用 Visual Studio Code 或兼容的分支版本,请安装官方 Databricks 扩展,用于:

  • Databricks 特有的代理技能
  • Unity Catalog 和文件系统访问
  • 用于在 Databricks 计算资源上运行工作负载的远程开发功能

有关详细信息,请参阅用于Visual Studio Code的 Databricks 扩展

最小化笔记本中的业务逻辑

不要将笔记本视为业务逻辑的主容器。 仅将它们用于浏览和可视化。

  • Python:将核心逻辑放入位于src/src/py/中的可导入.py模块,并在笔记本中调用这些函数。
  • SQL:将查询保存在位于 src/src/sql/ 中的 .sql 文件里,并在作业和管道中引用这些文件,而不要在笔记本中内联 SQL。

仅将笔记本用作调用底层代码的轻量编排和可视化层。 此方法使测试和重用更加容易。

迁移笔记本密集型项目时,请以增量方式执行此操作。 一次提取一个可重用的模块或 SQL 文件,并使用声明性自动化捆绑包将迁移的资产置于与项目的其余部分相同的部署和测试工作流下。

动态传递上下文

避免任务依赖项的静态变量。 使用动态值引用,例如 {{tasks.<task_key>.values.<value_key>}} 在多阶段作业中的任务之间传递运行时上下文。

测试和可观测性

实现测试层

使用三层测试,与捆绑包如何迁移到生产环境相匹配:

  1. 单元测试:将业务逻辑保留在可 src/ 导入模块中,并包含 pytest 或等效框架。 在每个拉取请求上都运行这些检查,以便在失败时阻止合并。
  2. 捆绑验证:在本地运行 bundle validate 。 在 CI 中,优先将 bundle deploy 用于非生产工作区,以便在部署到生产环境之前发现 YAML 和资源映射问题。
  3. 预发布环境中的集成测试:部署到预发布环境后,运行端到端作业,并进行完成情况检查以及关键数据质量断言,例如行数统计或模式预期。

将“主分支和预发布环境中的所有测试均通过”作为将构件提升至生产环境的准入门槛。

对于 Lakeflow Spark 声明性管道,请使用内置开发和验证功能,而不是即席笔记本运行。 针对包含错误的记录的小型代表性数据集测试管道逻辑,并使用开发模式在更新生产表之前验证更改。

将日志记录视为部署的一部分

对于声明性自动化捆绑包部署的工作负荷,请将指标和日志记录视为部署协定的一部分,而不是每个项目独立定义的一部分。

  • 跨作业、管道和任务一致地发出结构化日志。 包括捆绑名称、目标环境、工作负荷名称、运行标识符以及跟踪故障所需的任何业务标识符。
  • 跟踪每个生产工作负荷的标准操作指标集:运行状态、持续时间、重试计数以及相关吞吐量或新鲜度指标。
  • 在共享库、可重用工作负载定义或捆绑模板中对这些约定进行编码,以便团队不必为每个项目重新创建可观测性模式。