MTS · 第二轮项目 HLD / 第三轮架构深挖

Salesforce Notification System 项目深挖:事件、投递与失败隔离

Salesforce MTS 面经围绕候选人的通知系统做 HLD 与架构追问;本文用标注假设的多渠道训练方案解释事件驱动、幂等、poison message 和可观测性。

题目重点:Salesforce MTS 面经围绕候选人的通知系统做 HLD 与架构追问;本文用标注假设的多渠道训练方案解释事件驱动、幂等、poison message 和可观测性。

题意与假设

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

  • 以下是假设的多租户通知平台:上游提交业务事件,系统按模板和用户偏好生成 email/SMS/in-app 投递。渠道、schema、租户和流量数字均为训练场景,不等于原候选人的项目。
  • 核心语义为业务事件至少一次送达处理链,各渠道发送尽力做到幂等;外部服务实际可能重复发送或回执延迟,不能声称全链路 exactly-once。
  • 偏好/退订需要在发送前检查最新状态;高优先级安全通知可能绕过部分偏好,必须有产品与合规明确规则。

解题路线

  1. 先画边界:上游业务服务在本地事务写事件/outbox;发布器送入事件流;notification orchestrator 以 event_id 幂等创建各 recipient/channel 的投递记录;模板服务和偏好服务产出渲染请求;渠道 worker 独立发送、保存回执与失败原因。存储记录 tenant_id、event_id、recipient、template_version、channel、state、attempt、next_retry_at。
  2. 异步解耦适用于业务请求不必等 SMS/Email 提供商响应的情形,能吸收尖峰并按渠道独立限速;代价是最终一致、积压、乱序和更复杂排障。若某动作必须同步确认,例如二次验证代码已被供应商接受,需单独定义同步路径或明确接受通知延迟,不能用‘异步更好’一概而论。
  3. 同一用户/事件可选稳定 partition key 保持关键顺序;竞争风险包括两个 consumer 同时处理同一消息、重平衡后的重复消费和偏好更新竞态。用投递唯一键、状态版本条件写、外部 provider 的 idempotency key(若支持)以及发送前偏好再次核对。不能把 Kafka 分区顺序误当作跨渠道或跨分区全局顺序。
  4. Poison message 先区分永久 schema/模板错误与临时 provider 故障。处理异常时保留原 event_id、payload 引用、错误码与处理版本,按上限退避重试;永久失败进入 DLQ 并告警/可重放,且避免一个坏消息卡死整分区。重新放回主流前先修代码或数据并提供审计。
  5. 技术选型要以目标回答:Kafka 适合持久化事件流、分区消费与重放;RabbitMQ 等任务队列在复杂路由/单任务确认场景可能更简单;Redis 可做短期队列或缓存但持久性/重放设计需额外核对。选择不是公司偏好题,应给可靠性、操作成本、延迟和团队经验的证据。

手动走一遍

训练例:订单 ready 事件 E1 被业务库与 outbox 同事务记录。发布器重试导致 E1 两次入流,orchestrator 以 (E1,user,email) 唯一键只建一条投递。模板版本 7 渲染失败为永久错误,送 DLQ 并记录字段缺失;修模板后人工重放 E1,已成功的站内信不再重发。用户在发送前退订邮件,worker 复核偏好并将邮件标为 suppressed。

规模与取舍

假设每天 1000 万业务事件,平均约 116 事件/秒;若每事件平均 1.5 个渠道且峰值为平均 10 倍,峰值约 1740 条渠道投递/秒,仅作训练推演。瓶颈常在 provider 限流、单租户热点和重试积压;按渠道隔离队列/配额,观察事件到投递的 p95/p99 延迟、发送成功、退订误发、DLQ 量与 consumer lag。保留期与 PII 加密/删除要按真实合规要求决定。

易错点与追问

容易失分的边界

  • 把候选人的真实通知系统项目细节编成 Salesforce 固定设计题;题目只给项目深挖方向。
  • 先调用 provider 再写投递记录,崩溃后无法判定是否已发送,重试易重复。
  • 一个 poison message 无限重试且阻塞分区,未设 DLQ、告警和安全重放。
  • 只依赖消息队列的至少一次投递,却未定义 consumer 与外部发送的幂等边界。
  • 把投递成功回执解释为用户已阅读或已收到,忽略渠道回执语义差异。

继续深挖

  • 什么条件促使 monolith 拆分?从团队发布节奏、渠道故障隔离与负载差异拿证据,避免为了微服务而拆。
  • 若要做 circuit breaker,放在各 provider 适配器调用边界还是整个通知入口?不同位置对其他渠道的影响是什么?
  • 如何用 outbox 避免业务数据与通知事件双写丢失?如何清理已发布 outbox 行?
  • Pager 到来后先看哪些指标和样本:consumer lag、provider 429/5xx、DLQ、模板版本与租户热点?
✓已复制微信号!