SDE · OOD

Amazon OOD:Doc/Tag 类与多线程反向索引

同一事务维护文档和Tag关联,核对查询快照、删除、重复标签及锁粒度。

题目重点:同一事务维护文档和Tag关联,核对查询快照、删除、重复标签及锁粒度。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练Doc有稳定id与标签集合,支持创建/更新/删除和按tag查文档;这是功能化训练接口。
  • 单进程多线程,标签按精确字符串身份,重复tag幂等;不含富文本协作、全文搜索或多租户授权。
  • query返回不可变id快照;读取body需要版本核对,不能承诺快照id和之后读取正文天然同版本。

解题路线

  1. 模型Doc(id,body,version,tags)、Tag(name)、DocumentTag(doc_id,tag)多对多关系;内存可用docs[id]与by_tag[tag]=set(doc_id)。标签独立对象仅在有元数据/rename需求时引入。
  2. 一把store级锁覆盖add/update/delete、两方向索引与version。先校验全部输入并计算add/remove差集,在同临界区修改;异常要发生在部分更新前或有完整回滚。
  3. 不变量:d含tag当且仅当by_tag[tag]含d.id;删除doc要移除所有反向关系,空tag桶删除。修改标签仅按差集,不能先清整个桶影响其他doc。
  4. 查询在锁内复制目标id集合后释放,不把可变set引用直接暴露给调用者。多tag AND查询取集合交、OR取并,需在同快照读取否则并发写可出现从未存在的组合。
  5. 锁粒度优化先测争用:读写锁可增并发读,但多索引写仍须原子;分doc锁再改tag时要固定锁顺序,不能用doc→tag和tag→doc两种顺序造成死锁。
  6. 迁移DB可用关联表唯一约束和事务,version做条件更新以拒绝lost update;缓存索引要明确落后程度,数据库事务不会自动使异步缓存强一致。

手动走一遍

训练doc1={red,blue}、doc2={red},更新doc1={green}后red只含doc2、blue为空、green含doc1。并发delete(doc1)与query(green)允许返回删除前或删除后快照,不允许半更新孤儿关联。

规模与取舍

创建/删除或变更t个tag期望O(t),单tag查id快照O(m)输出;AND按最小集合候选核验可约O(min m_i·tag数)。全局锁让写串行,是先保证不变量的基线,不是假定吞吐无限。

易错点与追问

容易失分的边界

  • 两方向索引更新不在同锁。
  • query返回内部可变set。
  • 删除某doc时清整个tag桶。
  • 锁顺序随调用路径变化。

继续深挖

  • tag rename如何保持原子?
  • Doc内容可很大,怎样缩短锁内复制?
  • 多租户tag名字相同如何隔离?
✓已复制微信号!