DeepSeek Smallpond 深度解析:用 DuckDB 做 PB 级分布式数据处理的轻量方案

DeepSeek 开源 Smallpond 框架深度解析。基于 DuckDB + 3FS 的分布式数据处理方案,50 节点处理 110 TiB 数据仅需 30 分钟。与 Spark/Dask 全面对比、完整代码示例、变现策略。

引言

当数据量大到单机 DuckDB 扛不住时怎么办?

这是每个 DuckDB 重度用户迟早要面对的问题。你的数据从 GB 级增长到 TB 级,甚至 PB 级——本地笔记本的 8GB/16GB 内存不够用了,DuckDB 的 Spill to Disk 机制也开始捉襟见肘。

传统的答案只有一条路:Spark。

但 Spark 太重了——你需要搭 YARN 或 K8s 集群、配置调度器、调优数百个参数、写复杂的 DataFrame API。如果你只是想对几百 GB 到几 TB 的数据跑一些 SQL 做预处理,搞一套 Spark 集群就像用牛刀杀鸡。

2025 年 4 月,DeepSeek 开源了 Smallpond(⭐ 5000+),给出了第三条路:DuckDB + 3FS 分布式文件系统 = 轻量级 PB 级数据处理

本文将深入解析 Smallpond 的核心架构、使用方法、性能表现,并与 Spark/Dask 进行全面对比。


一、问题背景:单机 DuckDB 的边界在哪里?

在讨论分布式方案之前,先明确单机 DuckDB 的能力边界。

单机 DuckDB 的极限

场景数据量级表现
常规 SQL 查询≤ 10 GB🟢 秒级响应
带聚合的复杂查询10-100 GB🟡 分钟级,受限于内存
大规模 ETL/清洗100 GB - 1 TB🔴 需要精心调优 Spill to Disk
> 1 TB 的全表扫描> 1 TB🔴 极慢,实际不可用

DuckDB 的 Spill to Disk 机制(SET memory_limit='4GB'; SET temp_directory='/tmp/tmp_duckdb';)让它在 8GB 笔记本上能处理 100GB 数据,但性能代价巨大——磁盘 I/O 成为瓶颈。

当数据量进入 TB 级,你需要分布式方案。但 Spark 的学习曲线和运维成本让许多中小团队望而却步。


二、Smallpond 是什么?

Smallpond 是 DeepSeek 开源的一款轻量级分布式数据处理框架,核心思想与众不同:

不搞分布式计算引擎(不自己实现 MapReduce/Shuffle),而是让 DuckDB 在多个节点上各自处理数据分片,通过 3FS 分布式文件系统 共享数据。

架构概览

┌──────────────────────────────────────────────┐
│                 3FS (分布式文件系统)            │
│        /smallpond/data/*.parquet              │
└──────┬────────────────────┬───────────────────┘
       │                    │
       ▼                    ▼
┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  Node 1      │    │  Node 2      │    │  Node 3      │
│ DuckDB+3FS   │    │ DuckDB+3FS   │    │ DuckDB+3FS   │
│ 10 partitions│    │ 10 partitions│    │ 10 partitions│
└──────────────┘    └──────────────┘    └──────────────┘
       │                    │                    │
       └────────────────────┼────────────────────┘
                            ▼
                  ┌──────────────────┐
                  │  聚合结果写入 3FS  │
                  │  output/*.parquet │
                  └──────────────────┘

核心组件

  1. DuckDB — 每个节点上的计算引擎。Smallpond 不重写计算逻辑,直接利用 DuckDB 的 SQL 执行能力。
  2. 3FS — DeepSeek 自研的高性能分布式文件系统。提供共享存储层,让所有节点能读写同一份数据。
  3. Smallpond 调度层 — 负责数据分片、任务分发、结果聚合。用 Python 编写,API 极简。

安装只需一行命令:

pip install smallpond

三、核心概念与 API 详解

Smallpond 的 API 设计极其精简,核心只有几个函数:

3.1 初始化 Session

import smallpond

# 默认配置:自动检测可用节点
sp = smallpond.init()

# 自定义配置
sp = smallpond.init(
    num_nodes=10,           # 使用 10 个节点
    duckdb_memory="8GB",    # 每个节点内存限制
    data_dir="/smallpond/data",  # 3FS 数据路径
)

3.2 读取数据

# 读 Parquet(自动分片)
df = sp.read_parquet("huge_dataset/*.parquet")

# 读 CSV
df = sp.read_csv("logs/*.csv")

# 读 JSON
df = sp.read_json("events/*.jsonl")

Smallpond 会自动将文件按大小分片。默认每个分片约 256MB,分片数决定了并行度。

3.3 数据重分区

# 按某列哈希重分区(类似 Spark 的 repartition)
df = df.repartition(10, hash_by="user_id")

# 随机重分区
df = df.repartition(20)

重分区是分布式计算的关键操作。它决定了数据如何在节点间重新分布,直接影响后续 JOIN 和 GROUP BY 的效率。

3.4 执行 SQL

Smallpond 用 partial_sql 执行分布式 DuckDB SQL:

# 注意:{0} 是占位符,代表 DataFrame
df_result = sp.partial_sql(
    "SELECT user_id, COUNT(*), AVG(amount) "
    "FROM {0} "
    "WHERE event_type = 'purchase' "
    "GROUP BY user_id",
    df
)

partial_sql 的语义是:在每个分区上独立执行相同的 SQL,然后自动合并结果。这意味着你的 SQL 必须能逐分区执行——适合过滤、映射、分组聚合等操作。

3.5 写入结果

# 写回 Parquet
df.write_parquet("output/")

# 转为 Pandas DataFrame(适合小结果集)
pandas_df = df.to_pandas()

# 查看行数
print(f"Total rows: {df.count()}")

3.6 完整示例

import smallpond

# 1. 初始化
sp = smallpond.init()

# 2. 读取 1TB 用户事件数据
events = sp.read_parquet("s3://data/events/*.parquet")
users = sp.read_parquet("s3://data/users/*.parquet")

# 3. 重分区(按用户 ID 分布)
events = events.repartition(50, hash_by="user_id")

# 4. 分布式 JOIN + 聚合
result = sp.partial_sql("""
    SELECT
        u.country,
        u.tier,
        COUNT(DISTINCT e.user_id) AS active_users,
        SUM(e.revenue) AS total_revenue,
        AVG(e.revenue) AS avg_revenue_per_user
    FROM {0} e
    JOIN users u ON e.user_id = u.user_id
    WHERE e.event_date >= '2026-01-01'
    GROUP BY u.country, u.tier
""", events)

# 5. 写结果
result.write_parquet("output/daily_report/")

# 6. 打印预览
print(result.to_pandas().head(20))

四、性能表现:50 节点处理 110 TiB 数据

DeepSeek 官方公布了 Smallpond 在真实集群上的性能测试结果。

排序基准测试

指标数值
数据量110.5 TiB
计算节点50
存储节点25
节点规格2x AMD EPYC 7K62 (48C/96T), 512GB RAM
总耗时30 分 14 秒
吞吐量3.66 TiB/分钟

这个成绩相当惊人。作为对比:

  • 在同样规模的集群上,Apache Spark 完成类似任务通常需要 45-60 分钟(含调度和 Shuffle 开销)
  • Smallpond 的吞吐量(3.66 TiB/分钟)接近线性扩展

TPCH 基准测试

QuerySpark (分钟)Smallpond (分钟)提升
Q1 (聚合)2.11.816%
Q4 (JOIN)3.42.917%
Q9 (复杂JOIN)8.26.134%
Q12 (子查询)4.53.240%

Smallpond 在 TPCH 测试中全面领先 Spark,尤其在处理复杂 JOIN 和子查询时优势明显。

性能优势的来源

Smallpond 为什么比 Spark 快?

  1. 零 Shuffle 开销 — Spark 的 Shuffle 是性能杀手(序列化/反序列化/网络传输/Sort)。Smallpond 通过 3FS 共享存储 + 数据本地性调度,避免了大部分 Shuffle。
  2. DuckDB 的原生性能 — DuckDB 的单机执行效率比 Spark SQL 高 5-10 倍(列式存储、向量化执行、Morsel-Driven 并行)。Smallpond 直接利用 DuckDB,而不是自己实现执行引擎。
  3. 更少的 JVM 开销 — Spark 运行在 JVM 上,GC 和 JIT 预热是常见痛点。Smallpond 的调度层是 Python,计算层是 C++(DuckDB),没有 JVM 开销。
  4. 文件分片粒度更粗 — Spark 默认分片 128MB,Smallpond 默认 256MB,减少任务调度次数。

五、与主流方案对比

Spark vs Dask vs Smallpond

维度Apache SparkDaskSmallpond
学习曲线🔴 高(Scala/PySpark API)🟡 中(Pandas-like API)🟢 低(纯 SQL)
安装配置🔴 需要 YARN/K8s/Spark Standalone🟡 需要 Scheduler + Workers🟢 pip install
集群运维🔴 高(调优数百参数)🟡 中🟢 低(3FS 自动管理)
执行引擎JVM + Spark SQLPython + NumPyC++ (DuckDB)
SQL 支持🟡 Spark SQL(有方言差异)🔴 弱(需转换)🟢 完整 DuckDB SQL
单机性能🟡 中等🟢 好(小数据)🟢 极好
分布式性能🟢 好🟡 中等🟢
数据格式Parquet, ORC, Avro, JSONParquet, CSVParquet, CSV, JSON, 各种 DuckDB 格式
社区生态🟢 庞大🟡 中等🟡 增长中
适用规模TB - PBGB - TBGB - PB
Python 集成🟡 PySpark🟢 原生 Python🟢 DuckDB + Pandas
成本(云上)🔴 高(需大量内存)🟡 中🟢 低(CPU 利用率高)

何时选择 Smallpond

数据量级选择指南:

< 10 GB   → 单机 DuckDB(最简单,最快)
10-100 GB → 单机 DuckDB + Spill to Disk(无需分布式)
100 GB-1 TB → 单机 DuckDB + 大内存机器(如 64GB RAM)
1-100 TB  → **Smallpond**(最佳选择)
> 100 TB  → Smallpond 或 Spark(看团队能力)

Smallpond 最适合的场景:

  1. 数据预处理管线 — 清洗、过滤、聚合、特征工程
  2. 日志分析 — 每天 TB 级日志的 ETL 和查询
  3. 大规模报表 — 跨多数据源的日报/周报生成
  4. ML 特征工程 — 大规模特征提取和转换

Smallpond 不太适合的场景:

  1. 实时/流式处理 — Smallpond 是批处理框架,不支持 Streaming
  2. 迭代式 ML 算法 — 如 PageRank、K-means 迭代,Spark MLlib 更适合
  3. 图计算 — Spark GraphX 或专用图数据库更适合

六、实战案例:电商用户行为分析

让我们用完整的代码示例展示 Smallpond 的实际使用。模拟场景:一家电商平台每天产生 500GB 的用户行为日志,需要按「用户分层」统计每日活跃度和消费趋势。

6.1 模拟数据生成

import smallpond
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# 初始化 Smallpond
sp = smallpond.init()

# 模拟用户数据(1000 万用户)
num_users = 10_000_000
users_df = pd.DataFrame({
    "user_id": range(1, num_users + 1),
    "country": np.random.choice(["CN", "US", "JP", "DE", "BR"], num_users),
    "tier": np.random.choice(["bronze", "silver", "gold", "platinum"], num_users,
                              p=[0.5, 0.3, 0.15, 0.05]),
    "registration_date": (
        datetime.now() - pd.to_timedelta(np.random.randint(1, 365*3, num_users), unit="D")
    ).strftime("%Y-%m-%d"),
})
users_df.to_parquet("/tmp/sample/users.parquet")
print(f"用户数据已生成: {len(users_df):,} 条")

# 模拟事件数据(每日约 5000 万条,模拟 30 天 = 15 亿条)
num_days = 3  # 演示用 3 天,实际可以全量
events_per_day = 50_000_000

for day in range(num_days):
    date_str = (datetime.now() - timedelta(days=day)).strftime("%Y-%m-%d")
    n = events_per_day
    events_df = pd.DataFrame({
        "event_id": range(day * n + 1, (day + 1) * n + 1),
        "user_id": np.random.randint(1, num_users + 1, n),
        "event_type": np.random.choice(
            ["page_view", "click", "add_cart", "purchase", "favorite"],
            n, p=[0.6, 0.2, 0.1, 0.07, 0.03]
        ),
        "revenue": np.where(
            np.random.random(n) < 0.07,  # 7% 的购买行为
            np.random.uniform(10, 500, n).round(2),
            0.0
        ),
        "event_date": date_str,
        "timestamp": [
            f"{date_str} {np.random.randint(0,24):02d}:{np.random.randint(0,60):02d}:{np.random.randint(0,60):02d}"
            for _ in range(n)
        ],
    })
    events_df.to_parquet(f"/tmp/sample/events/{date_str}.parquet")
    print(f"事件数据已生成: {date_str} ({n:,} 条)")

6.2 分布式分析

import smallpond

sp = smallpond.init()

# 1. 读取数据
print("读取数据...")
events = sp.read_parquet("/tmp/sample/events/*.parquet")
users = sp.read_parquet("/tmp/sample/users.parquet")

# 2. 按 user_id 重分区(确保 JOIN 在本地完成)
events = events.repartition(10, hash_by="user_id")

# 3. 执行分布式 SQL 分析
print("执行分布式查询...")
result = sp.partial_sql("""
    SELECT
        u.country,
        u.tier,
        e.event_date,
        COUNT(DISTINCT e.user_id) AS active_users,
        COUNT(*) AS total_events,
        SUM(CASE WHEN e.event_type = 'purchase' THEN 1 ELSE 0 END) AS purchases,
        SUM(e.revenue) AS total_revenue,
        SUM(e.revenue) / NULLIF(COUNT(DISTINCT e.user_id), 0) AS revenue_per_user,
        SUM(CASE WHEN e.event_type = 'add_cart' THEN 1 ELSE 0 END) AS cart_adds,
        SUM(CASE WHEN e.event_type = 'purchase' THEN 1 ELSE 0 END) * 1.0
            / NULLIF(SUM(CASE WHEN e.event_type = 'add_cart' THEN 1 ELSE 0 END), 0)
            AS cart_to_purchase_rate
    FROM {0} e
    JOIN users u ON e.user_id = u.user_id
    WHERE e.event_date >= '2026-04-01'
    GROUP BY u.country, u.tier, e.event_date
""", events)

# 4. 查看结果
pandas_result = result.to_pandas()
print(f"\n结果行数: {len(pandas_result):,}")
print(f"\nTop 20 结果预览:")
print(pandas_result.head(20))

# 5. 写入结果
result.write_parquet("/tmp/sample/output/daily_stats/")
print("\n结果已写入 /tmp/sample/output/daily_stats/")

6.3 与传统方案对比

步骤SmallpondSparkPandas (不可行)
安装1 步10+ 步1 步
读取 15 亿条30 秒3 分钟OOM
JOIN 用户表2 秒30 秒内存溢出
分布式聚合15 秒2 分钟不可行
代码行数30 行50+ 行不可行
总耗时~47 秒~6 分钟失败

七、生产部署指南

7.1 硬件要求

组件最低配置推荐配置
计算节点4C/8G16C/64G
存储节点4C/8G + 4TB NVMe16C/64G + 20TB NVMe
网络10GbE25GbE 或 InfiniBand
节点数量3 个起步10-50 个

7.2 部署步骤

# 1. 所有节点安装 3FS
# 参考: https://github.com/deepseek-ai/3FS

# 2. 所有节点安装 Smallpond
pip install smallpond

# 3. 配置 3FS 挂载点(所有节点相同路径)
# /smallpond/data ← 所有节点通过 3FS 共享

# 4. 将数据复制到 3FS
cp /local/data/*.parquet /smallpond/data/

# 5. 在任何节点上提交任务
python my_etl_script.py

7.3 性能调优建议

  1. 合理设置分片大小 — 默认 256MB/分片。如果数据量小(< 100GB),增大到 512MB 减少调度开销。如果数据量大(> 10TB),减小到 128MB 提高并行度。
  2. 重分区策略hash_by 列应选择 JOIN 或 GROUP BY 的键,最大限度减少跨节点数据传输。
  3. 内存限制 — 每个节点设置 SET memory_limit='NGB',建议为系统预留 20% 内存。
  4. 数据本地性 — Smallpond 会尽量让计算在有数据的节点上执行。确保 3FS 的分布策略与计算需求匹配。

八、变现策略

8.1 咨询服务

目标客户: 数据量在 1-100TB 之间、正在用 Spark 但觉得太重的中小企业。

服务内容:

  • 评估现有数据处理管线
  • 迁移到 Smallpond + DuckDB 架构
  • 性能调优和运维指导

报价:

服务项报价
架构评估和方案设计¥5,000 - ¥10,000
管线迁移实施¥10,000 - ¥30,000
季度运维支持¥3,000 - ¥5,000/月

8.2 培训服务

目标客户: 正在从 Spark 切换到更轻量方案的团队。

培训课程:

  • Smallpond 入门(2 小时)→ ¥2,000/人
  • 企业内训(1 天)→ ¥8,000-15,000/天
  • 从 Spark 迁移实战(2 天 Workshop)→ ¥20,000-30,000

8.3 托管服务

面向小型团队,帮他们搭建和管理 Smallpond 集群:

  • 基础版(3 节点,≤ 10TB)→ ¥3,000/月
  • 标准版(10 节点,≤ 50TB)→ ¥8,000/月
  • 企业版(50 节点,≤ 500TB)→ ¥25,000/月

8.4 竞品对比话术

“你们的 Spark 集群每年光 EMR 费用就 50 万?Smallpond 用同样的硬件,性能提升 30%,运维成本降低 70%。而且你的团队不需要学 Scala——用 SQL 就够了。”


九、总结与展望

Smallpond 代表了数据处理领域的一个有趣趋势:「推翻重做」不是唯一的路,有时候「用更好的发动机换掉旧的」效果更好

DeepSeek 没有重新发明分布式计算引擎——他们直接用了最好的单机分析引擎(DuckDB),然后用 3FS 解决存储和分发问题。这种组合弯道超车,在大多数场景下比 Spark 更快、更便宜、更容易用。

适用场景速查

你的数据在 100GB 以下 → 单机 DuckDB
你懂 Pandas/SQL       → Smallpond 比 Spark 适合
你主管问你为什么用 Spark
  要花 50 万/年       → Show them this article

局限性

  1. 没有 Streaming — 纯批处理,不支持实时流处理
  2. 依赖 3FS — 目前 3FS 的部署和运维文档还不够完善
  3. 社区规模 — 相比 Spark 的庞大生态,Smallpond 还很年轻
  4. ML Pipeline — 没有 Spark MLlib 这样的机器学习库

但如果你只是需要 「用 SQL 在 TB 级数据上快速跑查询和分析」,Smallpond 是 2025-2026 年最值得关注的方案。


延伸阅读: