Scheduled blob export silently truncates a window once the Parquet exceeds 48.8 GiB (lib-storage default partSize)

当 Langfuse 定时 Blob Storage Export 导出的单个 Parquet 超过 48.83 GiB 时,默认走 @aws-sdk/lib-storage 的 multipart 上传会因为固定 5 MiB part size 撞上 S3 的 10,000 parts 上限;配合

快速结论:当 Langfuse 定时 Blob Storage Export 导出的单个 Parquet 超过 48.83 GiB 时,默认走 @aws-sdk/lib-storage 的 multipart 上传会因为固定 5 MiB part size 撞上 S3 的 10,000 parts 上限;配合 BullMQ 重试和 ClickHouse 保留期 TTL 收缩数据,最终会把一个被截断的对象当成导出成功提交。优先排查导出窗口的 Parquet 体积、part size 配置以及是否开启了 buffered 上传路径。

适用环境:Issue 中确认的触发环境为 Langfuse 定时 Blob Storage Export(S3)、依赖 @aws-sdk/lib-storage 3.1074.0;报错与配置项涉及 LANGFUSE_S3_UPLOAD_ENABLE_BUFFERED。其余操作系统、Python、CUDA、显卡等环境未在 Issue 中给出,不做补充。

最快修复方案:按维护者回复,可优先尝试开启 LANGFUSE_S3_UPLOAD_ENABLE_BUFFERED=true。该模式改用 buffered chunked 上传路径并使用 100 MiB part size,把上限从 48.83 GiB 提升到约 977 GiB(100 MiB × 10,000),这也是 Langfuse Cloud 上运行的方式。此外可关注 #17304:导出会检测 10,000 parts 上限、抛出不可恢复错误让 BullMQ 停止重试,并把失败记录到 integration 上。

注意事项:buffered 模式会把 parts 放在内存中,单个上传的 worker 峰值内存会明显升高,因此在 EKS 等环境中需要预留足够内存,这也是它默认不开启、作为 opt-in 的原因。维护者仍在评估是否调整默认 part size。manifest 的 rowCount 已决定不填充(需要额外 ClickHouse 查询,且存在 late records 导致计数不一致的边界情况),因此不能依赖它做完整性校验。逐窗口的完整导出历史暂未规划。

问题场景

在 Langfuse 中启用定时 Blob Storage Export(S3)后,导出任务针对某个时间窗口(如 observations_v2)从 ClickHouse 查询数据并生成 Parquet 上传。当该窗口的 Parquet 体积超过 48.83 GiB 时触发 multipart 上传失败;用户不会立刻看到最终失败,而是在若干次重试后收到一个”成功”的导出,实际上该对象只覆盖了原窗口的一部分。Issue 报告者在自己的部署上因此静默丢失了将近两天的 traces。

报错原文

Error: Exceeded 10000 parts in multipart upload to Bucket: 
Key: langfuse-export//observations_v2/2026-09-06T01-20-00.parquet
    at Upload.__doConcurrentUpload (.../lib-storage/dist-cjs/index.js:330:23)
    at async Upload.__doMultipartUpload (.../lib-storage/dist-cjs/index.js:416:9)
    at async Upload.done (.../lib-storage/dist-cjs/index.js:235:16)
    at async S3StorageService.uploadFile (...)
[BLOB INTEGRATION] Getting data from DB for blob storage integration failed: The operation was aborted
[Connection] Exec: socket was closed or ended before the response was fully read
[BLOB INTEGRATION] Error exporting observations_v2 for project 

(jobId=

-2026-09-06T01:20:00.081Z attemptsMade=2 ...)

原因分析

根因是 @aws-sdk/lib-storageUpload 在调用时没有传入 partSize,于是使用 SDK 默认的 5 MiB,并且不会随 payload 大小自动放大。S3 对 multipart upload 有 10,000 parts 的硬上限,因此单个对象最大为:

10,000 × 5 MiB = 52,428,800,000 bytes = 48.83 GiB

上传抛错会中止正在喂数据的 ClickHouse 读取,所以重试必须重新执行查询而不是断点续传。此时保留期 TTL 已经删掉了窗口内最老的一批行,重试结果变小;如此反复,直到结果能塞进 10,000 parts 就提交成功。Issue 中观察到的例子:窗口 2026-09-06T01:20Z 在三天内被尝试六次,其中一次被放弃的上传已持有 42.89 GiB,最终提交的对象只有 10.3 GiB,仅覆盖 24 小时窗口中的 2 小时 07 分。被放弃的上传也不会被清理——同时有九个处于打开状态,持有 175.9 GiB 的孤立 parts,会被计费且 aws s3 ls 看不到。

环境排查

  • 确认 Langfuse 的 Blob Storage Export(S3 集成)是否启用定时导出,以及导出窗口的大小。
  • 确认 @aws-sdk/lib-storage 的版本(Issue 中受影响版本为 3.1074.0)。
  • 确认 LANGFUSE_S3_UPLOAD_ENABLE_BUFFERED 当前取值;默认关闭时走 5 MiB part size 的默认上传路径。
  • 确认目标窗口生成的 Parquet 体积是否接近或超过 48.83 GiB(可参考已成功提交的最大对象,如 Issue 中的 51,286,432,036 bytes ≈ 9,783 parts)。
  • 确认部署环境的 worker 可用内存,因为 buffered 模式会占用更多内存。
  • 检查 S3 是否存在未清理的 multipart 孤立 parts(成本与容量排查项)。

解决步骤

  1. 先评估导出窗口的 Parquet 体积,判断是否确实超过 48.83 GiB;如果尚未触顶,也要注意 Issue 中提到”距离上限只差 217 parts 运行了数周”的情况。
  2. 可优先尝试设置 LANGFUSE_S3_UPLOAD_ENABLE_BUFFERED=true。该路径使用 100 MiB part size,理论上限提升到约 977 GiB,并且在上传失败或未完整结束时显式执行 AbortMultipartUpload,有助于减少孤立 parts。
  3. 如果在 EKS 等内存受限环境,先估算 buffered 模式下的峰值 worker 内存再开启,避免因内存不足引入新问题。
  4. 关注包含 #17304 的版本:导出会检测 10,000 parts 上限(buffered 路径做客户端 guard,默认路径做错误检测),抛出不可恢复错误使 BullMQ 停止重试。
  5. 升级后确认失败信息被持久化记录在 integration 上,而不是像以前那样只显示最近一次运行状态、失败结束后消失。
  6. 对历史上已经产生的孤立 multipart parts 做单独清理(Issue 属于待处理项,注意这些 parts 计费且在 aws s3 ls 中不可见)。

验证方法

开启 buffered 上传后,对已知会超过 48.83 GiB 的大窗口执行一次导出,确认不再出现 Exceeded 10000 parts in multipart upload,且提交对象的大小与窗口预期数据量相符,而不是重试收缩后的偏小对象。升级到含 #17304 的版本后,可人为或复现触顶场景,确认任务不再被 BullMQ 反复重试,且 integration 上能看到持久化的导出错误。如果还需要额外确认对象完整性,不能依赖 manifest 的 rowCount(该字段恒为 null),需要自行从数据侧比对窗口覆盖范围。

参考来源

langfuse/langfuse #17282

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 24091

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注