SWE · System / Product Design

Meta 票务系统设计:五分钟保留、支付迟到与总量票

设计指定座位和generic admission两种库存,解释五分钟hold、支付慢或失败与避免超卖。

题目重点:设计指定座位和generic admission两种库存,解释五分钟hold、支付慢或失败与避免超卖。

题意与假设

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

  • 座位票按(eventId,seatId)唯一库存;通票GA只有场次库存counter。二者购买合同不同,不把所有票强行映射到固定座位。
  • 训练hold时长五分钟,服务器时间权威;支付确认超过截止如何处理必须先定,示例要求有效hold内成功确认,否则释放并补偿支付。
  • 库存强一致是核心不变量;搜索列表与剩余数量展示可有界陈旧,页面看到有票不等于购买已承诺。

解题路线

  1. 座位状态AVAILABLE→HELD→SOLD,hold记录owner/token/expiresAt/version。创建订单在事务中检查并CAS一批座位,全成或全不成;GA则原子检查remaining>=qty再减可用量。
  2. 支付订单状态PENDING/PAYING/CONFIRMED/EXPIRED/REFUND_REQUIRED独立管理。请求支付带唯一paymentId,回调按providerEventId去重,验证真实身份/金额/币种/订单,不把重复回调重复扣库存。
  3. 后台timer释放过期hold,但购买路径本身也检查expiresAt;定时器失联不应永久锁票。release带holdToken/version,旧timer不能释放已重新保留或售出的票。
  4. 慢支付优先解释业务选择:预授权成功后在有效hold内capture,或允许有上限延长并存版本。若已过期且被他人买走,迟到成功不能抢库存,走退款/撤销及可追踪客服状态。
  5. 热门开售设候场令牌、公平排队、每用户限额与bot控制,限制进入库存写路径的速率;读缓存与CDN减轻页面QPS,但无法替代最后原子库存判断。

手动走一遍

A五分钟hold座位X后发起支付;第六分钟B成功买X;A第七分钟支付回调成功。系统必须退款A,不能把X重新标给A。旧释放timer若在B的hold期执行,token不匹配拒绝释放。GA库存10,两人各买7必须只有一个成功。

规模与取舍

一笔k座位订单事务访问O(k)库存行;GA单场次counter会成为写热点,可分配库存桶但每桶总量必须受全局守恒约束。支付依赖P99超时与库存hold时长决定被占库存,不仅平均QPS。

易错点与追问

容易失分的边界

  • 先读库存再写,无锁/CAS会超卖;缓存decrement若丢失不能作为唯一账本。
  • 支付成功不代表一定确认票,库存与支付跨系统需要补偿状态机。
  • 过期清理只靠内存timer会在重启后泄漏,需持久deadline并可扫描恢复。

继续深挖

  • 若要一次买相邻k座位,先找候选再事务校验,失败重选;搜索与锁定之间仍有竞态。
  • GA分桶遇到一桶无票其他有票,如何再平衡和防止重复转移?转移需唯一ID与原子扣加或账本对账。
✓已复制微信号!