LMTS · System Design Round 1(服务设计)

Salesforce 异步 Job 服务设计:状态、租约、重试与幂等

Salesforce LMTS 系统设计面经明确考异步 Job/Task API、状态流转、retry/backoff、幂等和存储选型;本文给出可落地数据模型与失败恢复路径。

题目重点:Salesforce LMTS 系统设计面经明确考异步 Job/Task API、状态流转、retry/backoff、幂等和存储选型;本文给出可落地数据模型与失败恢复路径。

题意与假设

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

  • 训练场景是多租户后台任务:客户端提交执行一种注册过的任务类型及参数,异步查询状态;初始目标 100 万 job/日、峰值为平均 10 倍,单任务最长 30 分钟,数值并非面经事实。
  • 默认语义是至少一次投递与执行尝试,不承诺任意外部副作用的全局 exactly-once;调用方提供租户作用域的 idempotency key,worker 的外部写入也必须有幂等键或补偿。
  • 取消采用尽力语义:排队任务可阻止领取,运行中的任务可请求协作终止,但不能回滚已发生的不可逆外部动作。

解题路线

  1. 定义 POST /jobs 创建(含任务类型、参数引用、idempotency key)、GET /jobs/{id} 查询、POST /jobs/{id}/cancel 请求取消。持久化 job_id、tenant_id、payload_ref、state、attempt、next_run_at、lease_owner、lease_until、result_ref、error_summary 和版本;大 payload/result 放对象存储,数据库保留索引和元数据。
  2. 状态机可为 queued→leased/running→succeeded;可重试错误回到 queued 且更新 attempt/next_run_at,超过上限到 dead;取消进入 cancel_requested/cancelled。每个转移用版本条件更新,拒绝迟到 worker 在租约过期后覆盖新 worker 的结果。
  3. 提交请求先在数据库以 (tenant_id,idempotency_key) 唯一约束写 job,再通过 outbox 或轮询待执行表投递队列,避免‘数据库已提交但消息未发’的双写丢失。worker 领取时原子设置有期限的 lease;心跳续约,超时由 reaper 重新排队。
  4. 重试按错误分类:临时网络/限流采用指数退避、抖动和上限;无效参数或永久业务拒绝不重试。重复消息和 worker 崩溃会造成再执行,所以副作用目标必须用 job_id+操作阶段去重,或设计可恢复 saga。死信任务保留错误与输入引用以便人工处理和安全重放。
  5. 存储取舍:训练方案先用关系库承载条件状态转移、唯一键和按租户查询;队列负责调度,不作唯一事实源。若规模导致单库写入或热点成为瓶颈,再按租户/时间分区,或评估能提供条件写与所需索引的 NoSQL。选择应由一致性、查询和运营约束驱动。

手动走一遍

训练例:客户端以 key=invoice-42 提交生成报表 job,两次 POST 得同一 job_id。数据库提交后 outbox 投递;worker A 领到 60 秒租约,写外部对象存储前崩溃。租约到期后 worker B 重试,先用 job_id 检查目标对象是否已存在或以稳定键覆盖,再把结果引用与 succeeded 作条件写。若 A 迟到,版本检查禁止它覆盖 B 的终态。

规模与取舍

100 万/日平均约 11.6 次创建/秒,10 倍峰值约 116 次/秒;任务执行时长和并发比提交 QPS 更决定 worker 数量。若峰值到达率 λ=116/s、平均执行 30s,Little 定律给约 3480 个同时执行任务的粗估,再加重试与租户公平余量;这些都是训练数字。关注排队时间、任务成功率、重试率、lease 过期、死信积压和每租户份额。

易错点与追问

容易失分的边界

  • 把消息队列当唯一记录,消息过期或消费后失去客户端可查询的稳定状态。
  • 声称队列去重保证 exactly-once 外部副作用;worker 崩溃边界仍需目标系统幂等。
  • 无限重试永久错误,造成重试风暴、积压和其他租户饥饿。
  • 没有租约版本或 fencing token,过期 worker 的迟到成功覆盖新尝试结果。
  • 先返回成功再异步落库,客户端拿到 job_id 却查不到可靠记录。

继续深挖

  • 若任务有依赖 DAG,如何定义前置失败、取消传播与每个节点的幂等键?
  • 若高优先级租户不能饿死普通租户,如何按租户配额、权重和老化调度?
  • 若客户端要求强制取消运行中任务,哪些外部副作用可补偿,哪些只能标记已发生并人工处理?
  • 若任务执行要跨区域,如何处理租约时钟、数据主权和故障切换后的重复执行?
✓已复制微信号!