结论先说:对象存储的目录主键我建议按轮次,平台不做一级目录。理由只有一条:对象存储成本高的是列举和批量改,不是存储;按轮次写,一轮一个前缀,回灌、删除、校验都能整段做;按平台写,同一轮的记录被拆到多个前缀,做一次跨平台对比还得拼回来。平台放进对象键尾部或做成对象标签。
这里说的「目录规划」,指的是对象存储里键的层级怎么切:一级前缀放日期、轮次还是平台,二级前缀放什么,对象名怎么拼。规划写进数据之后,改的成本接近重写全部对象。
这篇只讲目录规划:两种布局各自擅长什么、键怎么写、列举与删除的代价差在哪、旧目录怎么迁移,最后给五个能立刻做的检查。文中桶名、平台数与对象数都是假设值。
一、两种目录在跑起来之后差在哪
我接手过一份监测数据的存储:一级前缀按平台切,二十来个平台并列。写的时候顺,读的时候问题出来了:出跨平台日对比得把每个平台前缀各列一遍;补历史回灌要在每个平台前缀下各找一个轮次目录。列举调用从一次变成二十几次。
反过来,一级前缀按轮次、平台塞进对象名尾部。写入和回灌都顺,麻烦的是按平台出单表要过滤一遍;但过滤在内存里做,比多跑二十几次列举便宜。
二、结论:一级前缀按轮次,平台进键尾
两种布局的代价差别落在四个批量动作上。
布局:写入一轮 | 跨平台取数 | 按轮回灌 | 按轮删除 | 列举成本
按轮次(日期 / 轮次 / 平台):一个前缀写满 | 列一个前缀再过滤 | 覆盖一个前缀 | 删一个前缀 | 低
按平台(平台 / 日期 / 轮次):一轮写多个前缀 | 列二十来个前缀 | 每个平台各覆盖 | 每个平台各删 | 高
混合(日期 / 平台 / 轮次):一层多前缀 | 中等 | 中等 | 中等 | 中
我选按轮次,是因为监测数据的批量动作多以轮为单位:补采、撤回、校验、重算都按轮走。平台维度的动作多是出报表,报表能建索引,批量动作不方便绕路。
三、键怎么拼:目录与命名规则
一级前缀用日期,二级用轮次编号,三级按对象类型分,对象名以分片序号开头,平台键放最后一段。
bucket/runs/2026-11-01/run-0001/
manifest.jsonl
answers/0001-chatgpt.jsonl
sources/0001-chatgpt.jsonl
四条规则:日期用零填充的横线格式,排序即时间序;轮次编号由程序生成;对象名以四位分片号开头,避免对象挤在同一前缀;平台键用内部编号。
下面这段脚本我跑过。
import re
def key_for(run_date, run_id, platform, shard):
assert re.fullmatch(r"\d{4}-\d{2}-\d{2}", run_date)
return f"runs/{run_date}/{run_id}/answers/{shard:04d}-{platform}.jsonl"
print(key_for("2026-11-01", "run-0001", "chatgpt", 1))
print(key_for("2026-11-01", "run-0001", "doubao", 2))
输出:
runs/2026-11-01/run-0001/answers/0001-chatgpt.jsonl
runs/2026-11-01/run-0001/answers/0002-doubao.jsonl
四、列举与检索的代价差在哪
对象存储的列举按前缀走,前缀越窄越快。按平台做一级前缀,想拿一天完整数据,就得把前缀列一遍;按日期做一级前缀,列一次就拿到当天全部文件。
排序我也是同一个判断:键的字典序决定天然顺序,日期在前就按时间排,平台在前就按平台名排,跨天对比还得自己再排。
前缀数量也会跟着平台数长:平台从二十个加到三十个,按平台的布局要多维护十套前缀。
五、生命周期与删除:按前缀配规则
生命周期规则按前缀配。按轮次布局,只给 runs/ 配一条规则,比如 90 天转低频、180 天删除;按平台布局要写二十几条规则,规则数量跟着平台数长。
撤回同理:某轮要整批删,按轮次删一个前缀;按平台要把每个前缀下的同一轮各删一次,漏一个就留半套数据。
六、旧目录怎么迁移
目录不能原地改名。我按三步走:先双写一段时间,新数据落新布局;再生成旧键到新键的映射清单,读侧按清单回退;历史数据到期后收尾。
迁移期间最怕直接复制后删旧数据:中间态不可回滚,新布局漏了一个平台,旧数据又没了,只能重采。
七、五个能立刻做的检查
第一步,列出所有批量动作:回灌、删除、导出、校验,看它们以轮为单位还是以平台为单位。
第二步,我按多数动作定一级前缀。以轮为单位的动作多,就按轮次。
第三步,我把平台放进对象键尾或对象标签,别让它占一级目录。
第四步,给每轮写一份 manifest,列出对象数、分片数与总字节数。
第五步,我用列举抽查:随便挑一天,看能不能一次列全当天文件。
八、三个绕不开的反问
问:平台多、报表又频繁,按轮次会每次都要过滤吗?
答:会过滤,但只多一次。 过滤在内存里做,跨前缀列举是接口调用;前者便宜。报表可再建一份平台索引,缓存对象键。
问:键里带平台,平台改名怎么办?
答:改映射不改键。 平台键用稳定内部编号,展示名放字典表;改名只动字典。
问:已经按平台切了,要不要全量迁?
答:先加映射层,不急着搬。 读侧按映射找对象,写侧新数据落新布局;等历史数据到期,旧前缀自然退场。
数据说明(PROV)
数据源:本文为对象存储目录规划的工程说明,示例桶名、平台数与对象数均为假设值,不引用真实监测结果。
查询日:无真实查询日;示例日期 2026-11-01 仅用于演示键格式。
样本:假设一天二十来个平台、每个平台每轮两个分片文件。
口径:以轮次为写入单位,以前缀为列举单位;容量与费用不在本文范围。
局限:示例只演示键设计与批量动作;不同对象存储厂商的前缀语义略有差异。
九、边界
这套规划我承诺三件事:一级前缀以批为单位、每轮有一份 manifest、批量动作能整段执行。键的字段名可以按团队习惯改,但日期、轮次、分片号三段不能省。
本文不承诺任何存储性能、容量或费用数值。
本文含 AI 辅助生成内容,经人工核实。