订阅更新

埋点数据怎么去重?event_id、重试和业务重复怎么区分?

面试问 254 约 3 分钟读完

本文目录
  1. 面试怎么回答
  2. 先定义一次“事件”,再谈唯一键
  3. 三类“重复”,要用三套判断
  4. 去重状态还需要作用域和保留期
  5. 一个典型场景:加了 UUID,重复还是在
  6. 同一个 ID,内容不同怎么办?
  7. 参考资料

面试怎么回答

我会先区分真实行为重复和同一事件重复投递。event_id 应在事件发生时生成,网络重试沿用,接收端在约定的应用或租户作用域内去重;不能每次发送重新生成。不同事件不能仅凭用户和秒级时间合并。还要明确在线去重保留期,超期回放怎么处理,同一标识不同载荷怎么隔离,并保留原始层和去重审计用于对账。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

用户连续点了两次按钮,和一次点击被网络重传了两次,看起来都可能是“同一个用户、同一个事件、同一秒”。但前者是两次真实行为,后者才是重复投递。去重键选错,少算和多算会一起发生。

埋点去重应识别同一次事件的重复投递;真实重复行为和跨端重复上报,需要各自的业务规则。

先定义一次“事件”,再谈唯一键

一次发生可以生成一条事件记录,同一记录又可能被发送多次。event_id 应绑定前者,而不是绑定 HTTP 请求次数。生成事件时确定标识,写入本地待发送队列,重试时沿用同一标识,才有条件识别传输重复。

如果客户端每次发送都新建 UUID,虽然每条消息的标识都很唯一,接收端却再也无法知道它们来自同一次点击。唯一性解决“不要撞号”,稳定性解决“重试还能认出原来的号”,两者缺一不可。

CloudEvents 的身份设计可作为参考:source 与 id 的组合识别不同事件,同一事件重复发送可以保留原 id。这是事件身份约定,不意味着任何接入系统天然实现了去重。

三类“重复”,要用三套判断

传输重试:同一事件 E1 多次到达,适合用稳定事件标识精确去重。真实重复动作:用户连续两次点击产生 E1、E2,应保留事件明细,再由 PV、UV 等指标决定如何聚合。

还有跨端双重上报:前端和服务端都上报同一次支付,各自的 event_id 可能不同。这不一定是传输故障,而是同一业务事实被两个观察者记录,需要订单号、支付流水号等业务关联,以及哪一侧作为权威来源的规则。

三类重复的处理边界

不能为了让数量“看起来正常”,直接把用户、事件名和秒级时间拼成键。它会合并同一秒发生的真实动作,也未必能识别跨秒重试。若历史数据没有稳定身份,只能说明采用了启发式归并,并评估误杀与漏重,不能称为精确去重。

去重状态还需要作用域和保留期

event_id 是否跨应用唯一?多个租户有没有各自的编号空间?通常应明确 source、应用或租户等作用域,再形成完整键,不能看到一个 ID 字段就默认全球唯一。

在线状态也不可能无限增长。假设只保留最近一段时间的已处理标识,超期回放就可能再次通过。因此要把在线防重与历史回灌拆开:在线覆盖正常重试和约定迟到范围,历史重放依靠稳定主键、批次隔离或重新计算后替换。

保留期按什么时间开始计算也要说明。事件发生时间、首次接收时间和最后一次重试时间会带来不同淘汰行为。它不是一个随手设大的 TTL,而是对可接受重复窗口和资源成本的明确选择。

一个典型场景:加了 UUID,重复还是在

比如埋点量在弱网场景下偏高,团队先怀疑消息队列重复消费,检查后却发现每条消息的 event_id 都不同。继续追客户端日志,才发现重试分支重新生成了 UUID,同一次行为被包装成多个“新事件”。

原测试只验证正常发送,并检查 ID 不重复,没有模拟断网、超时和本地队列重放,恰好把错误设计当成了优点。修复应让标识在事件创建时固定,并验证重试前后 ID 和关键载荷一致,而不是继续加更多接收端去重条件。

同一个 ID,内容不同怎么办?

这比普通重复更值得告警。可能是客户端复用了 ID,也可能是补报逻辑修改了原事件。不能一律“保留最新”,否则发送时间更晚的错误数据可能覆盖真实值。

可以保留原始层,记录同键载荷摘要冲突,并按事件契约决定隔离、修订版本或人工核验。若业务允许更正,最好用明确版本或更正事件表达,不要把修改藏进重试里。

最后,对账至少同时看原始接收条数、唯一事件数、技术重复数和身份冲突数。原始层到清洗层条数减少,并不能直接证明有数据丢失;关键是每一类减少都能解释,合法事件没有被误删。

参考资料

刷题进度保存在当前浏览器