在 Databricks 上扩展机器学习推理:Liquid 聚类、分区与加盐技术深度对比

作者
  • avatar
    姓名
    Nino
    职业
    Senior Tech Editor

将机器学习模型从训练阶段转入大规模批量推理(Batch Inference)阶段,往往是架构挑战最严峻的时刻。在 Databricks 等平台上,推理流水线的效率不仅取决于模型的复杂度,更取决于你如何管理数据布局、随机交换(Shuffle)操作以及资源利用率。当处理数十亿行数据时,在传统的 Hive 风格分区(Partitioning)、最新的 Liquid Clustering 以及数据加盐(Salting)技术之间做出选择,直接决定了任务是能在几分钟内完成,还是会因为数据倾斜(Data Skew)而无限期挂起。

本指南将深入探讨这些数据管理策略,提供关于如何最大化 Databricks 集群性能以实现高吞吐量 ML 推理的技术见解。对于需要通过外部 LLM 能力增强 Databricks 工作流的开发者,集成像 n1n.ai 这样高速的 API 聚合器,可以为调用 Claude 3.5 或 GPT-4o 等模型提供必要的低延迟桥梁。

核心瓶颈:数据倾斜与小文件问题

在深入解决方案之前,我们必须理解 Spark 中扩展性的两大杀手:数据倾斜和小文件问题。数据倾斜发生在某些分区包含的数据量远超其他分区时,导致部分执行器(Executor)满载工作,而其他执行器则处于闲置状态。在 ML 推理中,如果你按某个遵循幂律分布的特征(如 user_idregion)进行分区,通常就会发生这种情况。

“小文件问题”则是另一面的挑战。如果你过度分区,Spark 会创建成千上万个微小文件。每个文件都需要元数据查询和 I/O 操作,这会产生巨大的开销,严重限制推理引擎的读取速度。

传统分区:老派但稳健的方法

传统分区涉及根据列值将数据物理组织到文件夹中(例如 /year=2024/month=10/)。

优点:

  • 当查询在分区键上进行过滤时,具有极佳的分区剪枝(Partition Pruning)效果。
  • 实现简单,易于理解。

缺点:

  • 分区演进困难: 更改分区键需要重写整张表。
  • 过度分区风险: 如果键的基数(Cardinality)过高,性能会崩溃。
  • 静态特性: 它无法适应不断变化的数据分布。

对于许多遗留工作负载,这仍然是默认选择。然而,当你的推理任务需要连接大型查找表或处理不可预测的数据量时,分区往往无法提供所需的灵活性。在这些情况下,开发者通常会寻求 n1n.ai 等外部 API 解决方案,以处理特定的模型任务,而无需担心底层集群配置。

Liquid Clustering:现代标准

Databricks 最近推出了 Liquid Clustering,旨在取代传统的分区和 Z-Ordering。它通过动态管理数据聚类来简化数据布局,不再需要固定的文件夹结构。

为什么 Liquid Clustering 更胜一筹?

  1. 灵活性: 你可以在不重写数据的情况下更改聚类列。
  2. 增量聚类: 随着新数据的追加,Liquid Clustering 会确保其高效组织,无需全表重写。
  3. 缓解倾斜: 它处理高基数列的能力远强于传统分区。

在 PySpark 中实现 Liquid Clustering 的示例:

# 使用 Liquid Clustering 创建表
(df.write
  .format("delta")
  .option("clusterBy", "user_id, event_type")
  .saveAsTable("ml_inference_input"))

# 以后更改聚类列
spark.sql("ALTER TABLE ml_inference_input CLUSTER BY (new_column)")

在 ML 推理场景中,按照用于批处理的特征进行聚类,可以确保相关数据位于同一个执行器上,从而显著加快 mapInPandasPandas UDF 的执行速度。

处理倾斜推理的艺术:加盐技术 (Salting)

当你被迫在高度倾斜的键上进行连接或聚合(例如社交媒体数据中的少数明星 ID)时,分区和 Liquid Clustering 可能都不够用。这时就需要用到 加盐(Salting) 技术。

加盐涉及向键添加一个随机整数(即“盐”),以打破大数据块。

实现逻辑:

  1. 向倾斜表添加一个 salt 列:salt = random(0, num_partitions - 1)
  2. 创建复合键:new_key = concat(original_key, salt)
  3. 对于查找表(Lookup Table),根据使用的盐的数量进行扩充(Explode),确保每个可能的加盐键都能匹配到。
from pyspark.sql import functions as F

# 为倾斜的推理数据添加盐
num_salts = 10
inference_df = inference_df.withColumn("salt", (F.rand() * num_salts).cast("int"))
inference_df = inference_df.withColumn("salted_key", F.concat(F.col("user_id"), F.lit("_"), F.col("salt")))

虽然加盐增加了复杂度,但它是处理数据本质不平衡时平衡集群工作负载的终极工具。

性能基准测试:Liquid vs. Partitioned

在我们的案例研究中,我们观察到对于超过 1TB 的数据集,Liquid Clustering 相比 Z-Ordering 将“首批处理时间”缩短了近 30%。更重要的是,维护开销(运行 OPTIMIZE 命令的时间)显著降低,因为 Liquid Clustering 执行的是增量压缩。

当你的 Databricks 集群负载过重时,可以考虑将特定的基于 LLM 的推理任务外包。使用 n1n.ai 可以让你利用其优化的 API 基础设施维持高吞吐量,该基础设施聚合了多个供应商,确保你的 ML 流水线不会因速率限制或供应商停机而停滞。

实施专家技巧 (Pro Tips)

  • 监控 Spark UI: 始终检查 Spark UI 中的 “SQL” 选项卡。观察任务持续时间的分布。如果 5% 的任务消耗了 90% 的时间,说明你遇到了需要加盐处理的倾斜问题。
  • 合理调整集群规模: 对于 ML 推理,内存优化型实例(如 Azure/AWS 上的 R 系列)通常优于计算优化型,因为将大型模型权重加载到内存中是主要的瓶颈。
  • 使用向量化 UDF: 如果使用 Python 进行推理,请务必使用 Pandas UDFsmapInPandas。这些方法允许 Spark 以 Arrow 批次的形式将数据传递给 Python,这比逐行处理快几个数量级。

总结

在 Databricks 上扩展 ML 推理需要分层策略。首先尝试 Liquid Clustering,因为它易于使用且性能提升明显。如果遇到导致执行瓶颈的特定键,请应用 加盐技术。对于无法更改表格式的遗留系统,传统的 分区 仍然是一个可行但有局限的选择。

通过优化数据布局,你可以确保 Databricks 的计算资源用于生成预测,而不是浪费在处理数据随机交换和 I/O 开销上。

立即在 n1n.ai 获取免费 API 密钥。