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

- 姓名
- 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_id 或 region)进行分区,通常就会发生这种情况。
“小文件问题”则是另一面的挑战。如果你过度分区,Spark 会创建成千上万个微小文件。每个文件都需要元数据查询和 I/O 操作,这会产生巨大的开销,严重限制推理引擎的读取速度。
传统分区:老派但稳健的方法
传统分区涉及根据列值将数据物理组织到文件夹中(例如 /year=2024/month=10/)。
优点:
- 当查询在分区键上进行过滤时,具有极佳的分区剪枝(Partition Pruning)效果。
- 实现简单,易于理解。
缺点:
- 分区演进困难: 更改分区键需要重写整张表。
- 过度分区风险: 如果键的基数(Cardinality)过高,性能会崩溃。
- 静态特性: 它无法适应不断变化的数据分布。
对于许多遗留工作负载,这仍然是默认选择。然而,当你的推理任务需要连接大型查找表或处理不可预测的数据量时,分区往往无法提供所需的灵活性。在这些情况下,开发者通常会寻求 n1n.ai 等外部 API 解决方案,以处理特定的模型任务,而无需担心底层集群配置。
Liquid Clustering:现代标准
Databricks 最近推出了 Liquid Clustering,旨在取代传统的分区和 Z-Ordering。它通过动态管理数据聚类来简化数据布局,不再需要固定的文件夹结构。
为什么 Liquid Clustering 更胜一筹?
- 灵活性: 你可以在不重写数据的情况下更改聚类列。
- 增量聚类: 随着新数据的追加,Liquid Clustering 会确保其高效组织,无需全表重写。
- 缓解倾斜: 它处理高基数列的能力远强于传统分区。
在 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 推理场景中,按照用于批处理的特征进行聚类,可以确保相关数据位于同一个执行器上,从而显著加快 mapInPandas 或 Pandas UDF 的执行速度。
处理倾斜推理的艺术:加盐技术 (Salting)
当你被迫在高度倾斜的键上进行连接或聚合(例如社交媒体数据中的少数明星 ID)时,分区和 Liquid Clustering 可能都不够用。这时就需要用到 加盐(Salting) 技术。
加盐涉及向键添加一个随机整数(即“盐”),以打破大数据块。
实现逻辑:
- 向倾斜表添加一个
salt列:salt = random(0, num_partitions - 1)。 - 创建复合键:
new_key = concat(original_key, salt)。 - 对于查找表(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 UDFs或mapInPandas。这些方法允许 Spark 以 Arrow 批次的形式将数据传递给 Python,这比逐行处理快几个数量级。
总结
在 Databricks 上扩展 ML 推理需要分层策略。首先尝试 Liquid Clustering,因为它易于使用且性能提升明显。如果遇到导致执行瓶颈的特定键,请应用 加盐技术。对于无法更改表格式的遗留系统,传统的 分区 仍然是一个可行但有局限的选择。
通过优化数据布局,你可以确保 Databricks 的计算资源用于生成预测,而不是浪费在处理数据随机交换和 I/O 开销上。
立即在 n1n.ai 获取免费 API 密钥。