题目重点:设计 file 与 owner 的元数据关系、删除墓碑、物理对象 GC,以及请求/回收重试的一致性。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版每个 file 有单一 owner、不可变 file_id、对象存储 key 和状态 ACTIVE/DELETING/DELETED;是否允许共享/转移所有权须当轮问。
- 删除 API 对同一 file_id 重试要给稳定结果;文件内容物理删除可异步完成,但授权读必须在元数据标删除后立即拒绝。
解题路线
- schema:file(file_id PK, owner_user_id, object_key unique, state, generation, created_at, deleted_at)、delete_request(owner,idempotency_key unique,file_id,result)、gc_task(file_id,generation,run_after,status)。查询按 (owner_user_id,state,file_id) 索引列出文件。
- 创建时先定义内容对象与元数据的提交顺序:若先上传对象再写元数据,失败对象进入 orphan GC;若先写 pending 元数据,上传失败要清理 pending。上传 ID/对象 key 带稳定请求 ID,重复请求不会生成多个可见文件。
- DELETE /files/{id} 在事务中校验 owner/权限,将 ACTIVE→DELETING 写 tombstone 与 gc_task;若已 DELETING/DELETED,使用原幂等键返回同一结果。读路径只返回 ACTIVE,不等物理删除完成。
- GC worker 根据 file_id/generation 查墓碑并删对象;对象 delete 应幂等,重复执行没有副作用。成功后把元数据标 DELETED 或过保留期清除。若文件 ID 复用/对象 key 重写,generation 防旧 GC 删除新对象。
- 若外部对象删除超时未知,查询对象状态或重试;失败任务有退避和死信/人工告警。定期扫描元数据/对象存储对账 orphan 与缺失对象,保留审计记录以核追责。
手动走一遍
用户 U 删除 file F:事务把 F 标 DELETING 并写 GC 任务,立即返回 202;同时来的读请求按状态拒绝。GC 删对象时超时,下次用同一 object_key/generation 重试;用户重发 DELETE 仍得到原请求结果,不会重复建无限任务。
规模与取舍
按 file_id 删除为索引查找加常数行事务,约 O(log F);按用户列 K 条为 O(log F+K)。GC 存储/吞吐随待删对象数增长,物理回收延迟依外部存储;题目未给对象规模或保留窗口。
易错点与追问
容易失分的边界
- 元数据硬删后无法判定重复 delete 与恢复 GC。
- 读路径在 tombstone 后仍返回对象。
- 对象 key 可被复用却没有 generation 防旧任务。
- 调用外部存储放在长事务中。
- 只做 API 幂等、不做 GC worker 幂等与重试。
- 无来源支撑地加入共享文件 ACL 规则。
继续深挖
- 同一文件有多个 owner 时删除语义怎么改?
- 先上传对象还是先写 metadata,失败如何收敛?
- GC 宕机/超时如何避免误删新版本?
- 法律保留期与用户删除请求冲突怎么建模?
- 元数据和对象存储怎样定期对账?
