题目重点:设计价格历史与降价通知,解释商品标识、抓取频率、重试、变更判定和故障恢复。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练为跟踪公开或授权可访问的商品价格,不绕过访问控制;价格包含币种、地区、运费与促销条件,必须先界定可比较口径。
- 同一商品多个URL与商品变体可能不是同一价格实体;entityKey至少含商家/商品/variant/region/currency。
- 例1千万商品,每日抓一次平均116抓取/秒;若每页200KB约23MB/秒输入,未计失败重试、图片和JS渲染。
解题路线
- URL frontier按商家分队列,调度按变化频率/关注人数/失败backoff决定nextFetchAt;每域限并发与速率,robots与授权规则按实际站点。HTTP缓存验证和已有数据源减少重复下载。
- crawler记录fetchId、contentHash、HTTP状态与解析器版本。原始页面可短期存储便于复现,parser提取结构化priceObservation与有效条件;页面改版导致解析失败不能当价格0发送降价通知。
- 历史按observedAt保存,与receivedAt区分;重复fetchId幂等,内容同价可压缩连续区间但保留观测证据。晚到结果不要覆盖更新价格,当前态按有效观测版本选取。
- 告警订阅(user,product,threshold)按价格跨阈值触发,notificationId=(subscription,transition)去重,outbox重试发送。继续低于阈值是否每日提醒需产品合同,不能每次抓取都重复发。
- 服务故障后持久frontier与租约恢复,旧crawler迟到结果带attempt版本。worker扩容不突破单域许可速率;监控解析成功率、数据年龄、抓取成本与告警延迟。
手动走一遍
昨日100,今日80触发低于90告警;两次抓到80只发一次。如果币种由USD切到CAD,不能直接把80当降价。解析价格缺失时状态为UNKNOWN,当前有效价格保留并显示过期。
规模与取舍
存储约商品数×观测频率×保留期×每条bytes;热商品按分钟抓取会远超日抓平均,调度应按预算优先。提醒扇出与抓取QPS是不同维度,一次大促可能触发百万订阅。
易错点与追问
容易失分的边界
- 按URL dedup会把同一变体别名重复抓,也可能误合并不同商品。
- 只有最后价格不能画历史,只有历史没有当前索引会使每次查询扫描全部。
继续深挖
- 价格变化检测用固定精度decimal与币种单位,不能用浮点等于判定。
- 若告警只允许一次,幂等事实与通知provider重试结果怎样对账?保持send状态并查询provider确认,不假定timeout就是失败。
