SWE · System / Product Design

Meta 商品价格追踪:抓取调度、历史去重与告警

设计价格历史与降价通知,解释商品标识、抓取频率、重试、变更判定和故障恢复。

题目重点:设计价格历史与降价通知,解释商品标识、抓取频率、重试、变更判定和故障恢复。

题意与假设

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

  • 训练为跟踪公开或授权可访问的商品价格,不绕过访问控制;价格包含币种、地区、运费与促销条件,必须先界定可比较口径。
  • 同一商品多个URL与商品变体可能不是同一价格实体;entityKey至少含商家/商品/variant/region/currency。
  • 例1千万商品,每日抓一次平均116抓取/秒;若每页200KB约23MB/秒输入,未计失败重试、图片和JS渲染。

解题路线

  1. URL frontier按商家分队列,调度按变化频率/关注人数/失败backoff决定nextFetchAt;每域限并发与速率,robots与授权规则按实际站点。HTTP缓存验证和已有数据源减少重复下载。
  2. crawler记录fetchId、contentHash、HTTP状态与解析器版本。原始页面可短期存储便于复现,parser提取结构化priceObservation与有效条件;页面改版导致解析失败不能当价格0发送降价通知。
  3. 历史按observedAt保存,与receivedAt区分;重复fetchId幂等,内容同价可压缩连续区间但保留观测证据。晚到结果不要覆盖更新价格,当前态按有效观测版本选取。
  4. 告警订阅(user,product,threshold)按价格跨阈值触发,notificationId=(subscription,transition)去重,outbox重试发送。继续低于阈值是否每日提醒需产品合同,不能每次抓取都重复发。
  5. 服务故障后持久frontier与租约恢复,旧crawler迟到结果带attempt版本。worker扩容不突破单域许可速率;监控解析成功率、数据年龄、抓取成本与告警延迟。

手动走一遍

昨日100,今日80触发低于90告警;两次抓到80只发一次。如果币种由USD切到CAD,不能直接把80当降价。解析价格缺失时状态为UNKNOWN,当前有效价格保留并显示过期。

规模与取舍

存储约商品数×观测频率×保留期×每条bytes;热商品按分钟抓取会远超日抓平均,调度应按预算优先。提醒扇出与抓取QPS是不同维度,一次大促可能触发百万订阅。

易错点与追问

容易失分的边界

  • 按URL dedup会把同一变体别名重复抓,也可能误合并不同商品。
  • 只有最后价格不能画历史,只有历史没有当前索引会使每次查询扫描全部。

继续深挖

  • 价格变化检测用固定精度decimal与币种单位,不能用浮点等于判定。
  • 若告警只允许一次,幂等事实与通知provider重试结果怎样对账?保持send状态并查询provider确认,不假定timeout就是失败。
✓已复制微信号!