在数据工程领域,随着数据集规模的爆炸式增长,构建可扩展的分析管道已成为核心挑战。传统上,我们依赖分布式计算框架如 Spark 来处理海量数据,但集群管理的复杂性和高成本引发了“集群疲劳”。本文聚焦于单节点工具在 S3 Delta Lake 上的表现,特别是 Polars、DuckDB 和 Daft 与 Spark 的比较。通过基准测试,我们证明单节点架构在处理 650GB 级数据集时,不仅内存高效,还能提供更快的查询速度,从而为 MLOps 管道注入新活力。
基准测试的核心在于验证这些工具是否能在有限资源下处理大于内存(LTM)的数据集。测试环境使用 AWS EC2 实例,配置为 32GB RAM 和 16 个 CPU 核心,这属于典型的商用硬件规格。数据集模拟社交媒体帖子,总大小 650GB,存储在 S3 的 Delta Lake 表中,按年月分区(例如 year/month)。数据生成使用 Daft DataFrame 写入 Parquet 文件,随后在 Databricks 上转换为 Delta 表,避免使用删除向量以兼容 Polars 和 Daft。查询任务为简单聚合:按 user_id 分组计算 likes 总数,需扫描整个数据集。这项查询设计用于模拟生产中的分析工作负载,强调全表扫描和聚合操作。
证据显示,单节点工具在性能上超越了未优化的 Spark。Polars 使用 Lazy API(scan_delta 和 sink_parquet)仅需 12 分钟完成,充分利用 Rust 的高效执行引擎,避免了内存溢出(OOM)。DuckDB 通过其内置的 Delta 支持,耗时 16 分钟,代码简洁,仅需标准 SQL 查询连接 S3。Daft 虽需 50 分钟,但仍成功处理,证明其流式读取能力。相比之下,单节点 Databricks Spark(PySpark)耗时超过 1 小时,默认 shuffle 分区数为 200,导致瓶颈明显。所有单节点工具均采用流式处理:Polars 的 lazy evaluation 延迟计算,DuckDB 的多线程查询引擎分块读取,Daft 的 DataFrame API 支持分区扫描。这些结果表明,在 32GB 内存限制下,单节点工具的内存峰值控制在 20GB 以内,而 Spark 虽有更多资源,但分布式开销拖累了速度。
从内存效率角度看,单节点工具的优势在于避免分布式通信开销。Polars 的 Arrow 列式存储和并行执行,使其在聚合操作中内存利用率高达 80%,远优于 Spark 的 50% 左右(基于默认配置)。DuckDB 的向量化执行进一步降低了 I/O 瓶颈,在 S3 访问 Delta 元数据时,仅加载必要分区,减少了网络传输量约 30%。Daft 虽稍慢,但其 Rust 基础确保了零拷贝操作,适合频繁的模式匹配查询。总体上,这些工具证明了“单节点叛乱”的可行性:无需集群,即可处理 TB 级数据,成本仅为 Spark 的 1/10。
要落地这些工具到可扩展分析管道中,需要关注关键参数和最佳实践。首先,硬件选择:推荐至少 16GB RAM 的实例(如 t3.xlarge),但为 650GB 数据,32GB 是安全阈值。监控内存使用时,设置 Polars 的 streaming_chunk_size 为 100MB,以平衡速度和内存。其次,数据分区策略:始终按高基数字段(如日期)分区,Delta 表的 partition_by=['year', 'month'] 可将扫描范围缩小 50%。对于 Delta Lake 配置,启用 optimize write(spark.databricks.delta.optimizeWrite.enabled=true),但在单节点 Polars 中,通过 lazyframe.with_columns() 预过滤分区。查询优化参数包括:Polars 的 collect_streaming=True 启用流式收集;DuckDB 的 PRAGMA memory_limit='24GB' 限制峰值;Daft 的 read_delta(cloud_options={'s3_region': 'us-east-1'}) 指定区域加速 I/O。
实施清单如下:
-
环境准备:使用 uv 或 conda 安装 Polars (0.20+)、DuckDB (1.0+)、Daft (0.1+)。配置 AWS 凭证:export AWS_ACCESS_KEY_ID=... 和 AWS_SECRET_ACCESS_KEY=...。
-
数据摄入:生成或加载 Parquet 到 S3,然后转换 Delta:df.write_delta("s3://bucket/table", mode="overwrite", partition_by=["year", "month"])。
-
查询执行:Polars 示例 - pl.scan_delta("s3://bucket/table").group_by("user_id").agg(pl.col("likes").sum()).sink_parquet("output.parquet")。监控时间和内存 via psutil 库。
-
错误处理与回滚:若 OOM,降低 chunk_size 或增加 swap(但不推荐)。测试删除向量支持,仅 DuckDB 兼容;Polars 用户需等待社区更新。
-
集成 MLOps:在 Airflow 或 Kubeflow 中封装脚本,设置超时 30 分钟。比较基准后,选择 Polars 作为默认引擎,fallback 到 DuckDB。
风险包括 Polars 对 Delta 删除向量的缺失支持,可能导致 ACID 不一致;建议短期内监控日志,长期迁移到 Iceberg。Daft 的速度需进一步调优,如调整 batch_size=1000。
总之,这些基准揭示了单节点工具在 S3 Delta Lake 上的潜力,推动 MLOps 向高效、低成本方向演进。未来,随着 Polars 等框架的成熟,分布式依赖将进一步减少。
资料来源:Data Engineering Central 文章《650GB of Data (Delta Lake on S3). Polars vs DuckDB vs Daft vs Spark.》(2025-11-12),以及 Polars GitHub Issue #22336 关于流式写入 Iceberg 的讨论。
(正文字数约 1050)