News Hacker|极客洞察

27 71 天前 hatchet.run
⚠️Supertoast 表:对象存储上管理大量小 blobs 的合并、压缩与元数据权衡
把不可变的 S3 当作可变数据库,这真是个主意吗?

🎯 讨论背景

讨论围绕“Supertoast 表”这一把大量小 payload 从数据库或主存储层外置到对象存储以节省空间与成本的思路展开。评论聚焦对象存储(AWS S3、Google Cloud Storage)的不可变性、按前缀过滤的查询成本、以及为满足擦除/隐私而必须做的 compaction 与事务安全性。替代方案包括把元数据放在事务性 key/value 存储(如 FoundationDB、TiKV)、用 Ceph 这类分布式存储,或用代理/缓存层在对象存储上呈现 POSIX 文件系统;具体项目例子有提供 SSD 聚合/代理的方案和在 S3 上运行 RocksDB 风格 API 的尝试。自托管与云托管的权衡、以及把 S3 操作放入 Postgres 事务路径(会阻塞 VACUUM 并受 RDS 等限制)是讨论的核心实施障碍。

📌 讨论焦点

对象存储的工程复杂性与约束

把大量小对象直接放在对象存储(如 S3/GCS)会引入多层工程复杂性:为避免大量小对象常做法是把小 blob 合并成“superblobs”,但这要求在大对象内跟踪子文件位置与边界。对象存储不支持原地写入,删除/覆盖只能通过新增对象与回收旧对象实现,因此必须设计事务安全的 compaction(整理)任务以在失败时避免遗留数据或隐私合规问题。因为对象存储的元数据查询昂贵且按前缀过滤效率有限,实践中需要在数据库里维护每个 blob 的清单,把数据库做为元数据的可信来源,而不是直接把对象存储当作数据库使用。为避免产生过多小对象,上传必须批量化/合并,否则请求成本与延迟会变得不可控。

[来源1]

替代方案与已有项目

社区和公司提出了多种替代或缓解方案:有通过代理/缓存与 SSD 聚合层把请求合并到对象存储之上的做法,从而呈现 POSIX 文件系统接口;也有像 SlateDB 这样尝试在 S3 上提供 RocksDB 风格 API 的项目。另一条路线是直接用事务性 key/value 存储(如 FoundationDB、TiKV)或分布式存储(如 Ceph)来承载小对象,或者把这些 KV 系统用作元数据存储以避免在对象存储上做复杂操作。实际案例显示,像 Tigris 这样的系统在特定场景下能高效支撑大量 ~4KB 小对象并把 FoundationDB 用作元数据后端,说明不同方案在成本、延迟和运维复杂度上有明显取舍。

[来源1] [来源2] [来源3] [来源4]

自托管与云服务的架构权衡

自托管环境面临额外挑战:把写入/合并/整理的后台任务合并到云版本通常是因为这些作业需要较多 CPU/内存并应独立运行,直接把它们并入主引擎会增加自托管部署复杂度和外部依赖。维护方表示核心管道可以开源,但写入到 S3 的实现或重负载整理流程可能先在云端运行,随后再考虑如何把资源隔离与依赖问题带回开源。作为折中,payloads 常按时间分区并在用户定义的保留期后回收,以控制成本与合规风险。多 TB 级别的自托管用户因此关心能否在不引入繁重依赖的情况下获得同样的整理与回收能力。

[来源1] [来源2]

在 Postgres 内实现 vs 在外部处理

有人建议做成 PostgreSQL 插件,在类型层把大文件上传到 S3,以保持接口简单并减少额外组件。反对者指出把慢速外部 I/O(如 S3)放到数据库事务路径会阻塞事务并延迟 VACUUM,进而影响表健康与性能;托管数据库(如 RDS)也通常不允许安装自定义扩展。虽然存在某些 S3 扩展,但并不被普遍推荐,因此更稳妥的做法是把对象读写放在应用层或数据库前的代理/网关中处理,让数据库保留为元数据与事务的一致性来源。总体结论是:避免把外部对象 I/O 拉入事务关键路径,除非能保证不影响维护作业与可用性。

[来源1] [来源2]

可视化与交互:ASCII 动画的效果

展示使用动态 ASCII 图获得了积极反馈,有读者觉得这种风格让复杂架构更直观,甚至让人联想到像 Cogmind 那样的 ASCII 交互艺术。评论中有人好奇这些动画是如何设计与实现的,暗示作者在可视化表达方面做得成功。这种简洁的可视化被认为有助于把抽象的存储/整理流程更容易传达给工程或产品受众。尽管是次要话题,但反映出技术文档中视觉呈现对理解复杂系统的重要性。

[来源1]

📚 术语解释

对象存储 (object storage, e.g., S3/GCS): 基于对象的云存储模型(如 AWS S3、Google Cloud Storage),对象为不可变单元、无原地写入,按对象读写;擅长大对象,但对大量小对象的请求延迟和操作成本通常很高。

superblob / 合并 blob: 把许多小 blob 合并成单个大对象以减少对象数量和请求次数,但必须在大对象内部维护子文件索引、支持局部回收,并处理合并失败导致的残留问题。

compaction(整理/压缩): 后台合并快照与增量、回收已删除数据并释放空间的过程。在对象存储环境下需以事务安全方式先写入新对象再删除旧对象,以免在失败时留下敏感数据或碎片。

POSIX 文件系统(在对象存储之上): 通过代理/缓存/聚合层把对象存储呈现为类 POSIX 的文件接口,使现有应用无需改写即可访问,但需要解决缓存一致性、性能和事务性问题。

VACUUM(PostgreSQL 垃圾回收): PostgreSQL 用于回收已删除或过时行并维护表健康的清理操作。将慢速外部 I/O(如 S3 调用)置于事务路径会阻塞 VACUUM,导致空间无法及时回收和性能下降。