amBrain
AdTechOct 7, 2026阅读需 9 分钟

广告报表为什么对不上出价方日志,以及谁能重建管道

广告测量事件管道出价方日志谁来做
图片加载失败

广告报表和出价方日志对不上,原因不外乎两种:事件在送往报表的路上丢了,或者两边按不同的规则计数。按竞价 ID 做一次核对计数,就能分辨是哪一种。答案决定了是修补管道、迁到托管服务,还是重建管道。

当广告报表始终对不上出价方日志时,同一个差距背后可能是两个问题。要么是展示和点击的记录(也就是事件)在送往报表的路上丢了,这往往发生在流量高峰;要么是两边各按自己的规则计数。按竞价 ID(广告交易平台给每场竞价分配的编号)做一次核对计数,就能把两者分开。在聘用任何人之前先做这件事,因为单靠一条新管道,只能解决第一个问题。

简短的答案:按竞价 ID,把你的出价方赢下的竞价与报表中的展示逐一匹配,并逐小时比较数量。一天之后再统计一次。如果仍然对不上的胜出占比在最忙的几个小时里升高,就是管道在丢事件,这需要工程上的修复。如果事件都在,只是落到了别的小时、出现了两次或者被过滤掉,那就是两边的计数方式不同。这时的解决办法,是为两边定一套统一的书面计数规则。

广告报表与出价方日志对不上,意味着什么?

你的出价方日志记录了出价方参与的每一场竞价、给出的每一次出价和赢下的每一场竞价。你的报表则基于稍后才到达的事件生成,比如来自浏览器和应用的展示与点击。两者之间的差距有两种可能的原因,也可能两者兼有:

  • 事件丢失。展示或点击确实发生了,但对应的事件始终没有到达报表。在流量高峰时扩大的差距,说明管道中有某个环节会把处理不过来的东西丢掉
  • 规则不同。两边可能按不同的时区结算一天,或者把一个迟到的事件归到另一个小时里。一边可能在重发之后把同一个事件算了两次,或者过滤掉了出价方仍然计入的机器人流量。归因还会加上它自己的规则,比如点击之后多长时间内发生的转化仍然算数

无论哪种情况,这个差距都要花钱。如果你按自己的报表给广告主开票,丢掉的展示会让你少收钱,重复计算的展示会让你多收钱,而每个广告交易平台通常都按它自己的计数向你收费。依据这些事件进行学习的出价方,也会根据错误的数字来定出价。

怎样区分丢失的事件和按不同规则计数的事件?

把两边的事件逐条匹配。在 IAB Tech Lab 的实时竞价协议 OpenRTB 中,每场竞价都有一个由广告交易平台分配的竞价请求 ID,请求中的每个展示也有自己的 ID。你的出价方可以要求广告交易平台把这些 ID 写进你胜出时它发出的通知,以及广告本身。这样,每个展示事件就带着与你的出价方日志相同的 ID。

这两个 ID 单独拿出来都不够。按照 OpenRTB 2.6,每个广告交易平台自行设定请求 ID,所以没有什么能阻止两个广告交易平台用上同一个 ID。展示 ID 只在它所在的请求内唯一,而且通常从 1 开始。所以要把三个值合在一起匹配:广告交易平台、请求 ID 和展示 ID。

然后做核对计数:

  • 选一个繁忙的日子,逐小时统计出价方日志里的胜出次数和报表里的展示次数,两边都用 UTC 时间,并按上述由三部分组成的键逐条匹配
  • 第二天再统计一次。如果差距缩小了,其中一部分就是迟到的事件
  • 如果仍然对不上的胜出占比在最忙的几个小时里升高,管道就是在高峰时丢事件。如果这个占比每个小时都差不多,那是正常的,因为有些胜出永远不会变成展示
  • 把剩下的差异分门别类。同一个事件在两边落在不同的小时里,说明两边用的时区或截止时间不同。重复计数通常来自重试。如果一个事件只在最终报表里缺失,那是某个过滤环节(比如机器人流量过滤)把它去掉了

如果你的事件不带竞价 ID,第一步修复就是把它们加上,因为没有竞价 ID,核对计数只能比较总数。上面链接的那篇关于广告测量的技术文章,深入讲了时间戳和迟到事件。

流量高峰时,事件在哪里丢失?

以一条基于 Kafka 和 ClickHouse 搭建的管道为例。采集器从浏览器或应用接收每一个事件,把它写入消息队列 Kafka。加载器从 Kafka 读取事件,分批写入 ClickHouse,也就是支撑你报表的分析数据库。在高峰时,每个环节都可能丢失事件:

  • 采集器过载。被它拒绝或者应答太晚的请求,除非浏览器或应用重新发送,否则就没了。在事件写入 Kafka 之前就回复“已收到”的采集器,一旦崩溃,也会丢掉它手里暂存的全部事件
  • Kafka 接收事件的速度跟不上。Kafka 的文档描述了事件到达速度快于转发速度时会发生什么:负责写入 Kafka 的代码会等待一段设定的时间,然后报错放弃。忽略这个错误的采集器,会让事件消失得无影无踪
  • 重试会制造重复。Kafka 有一项设置,能防止它自身的重试写入第二份副本。Kafka 的 Java 客户端默认开启这项设置;其他语言的客户端库有各自的默认值,有些默认是关闭的。它也拦不住你自己的代码制造的重复,比如重启后重发的一批数据,或者触发了两次的像素
  • 批量写入会整批失败。ClickHouse 的文档建议以大批次写入事件。在它的某种写入模式下,只要有一行格式错误,整批都会被拒绝。放弃这一批的加载器,会丢掉其中的每一个事件;原样重发的加载器,又会再次撞上同一行坏数据,所以坏行必须单独挑出来并计数。如果一次写入超时,没人知道它到底写进去没有,那么只有当表被设置为丢弃重复批次时,原封不动地重发同一批才是安全的,而自建的基础 ClickHouse 表默认并不会这样做

找一个出过问题的日子,请你的工程师拿出其中最忙那一小时的这些记录:

  • 负载均衡器和采集器上的错误与超时,以及采集器日志中写入 Kafka 失败的记录
  • 消费延迟(consumer lag),即加载器落后了多少,以及因为等待时间超过 Kafka 的数据保留期限、还没被读取就被删掉的事件
  • 写入 ClickHouse 失败的记录,以及相应的错误信息
  • 每个环节按小时统计的数量:采集器收到的、写入 Kafka 的、加载器读出的、存进 ClickHouse 的

最后这项记录最能说明问题。如果在高峰时某个环节的计数下降,而它的上一个环节保持不变,事件就是在这两个环节之间丢的。

我们该修补管道、迁到托管服务,还是重建它?

修补现有管道:

  • 适用情况:核对计数显示差异主要来自规则不同,或者只有几处能明确指出的漏点,而且修复之后,管道能扛住你最忙的那一小时
  • 你要付出的:工程开发的时间,以及更大的高峰暴露出下一个薄弱环节的风险
  • 代码归谁:归你,而且相关知识留在你的工程师手里

迁到托管服务,比如用 Amazon MSK 托管 Kafka、用 ClickHouse Cloud 托管 ClickHouse,由服务商来运行服务器:

  • 适用情况:你的工程师花在维持 Kafka 和 ClickHouse 服务器运转上的时间,比花在计数逻辑上的还多,而且丢失是因为这些服务器在高峰时容量耗尽
  • 你要付出的:一份随流量增长的月度账单。根据两者的价格页面(2026 年 10 月 7 日查阅),这两项服务都按计算和存储收费,ClickHouse Cloud 还把数据出站传输和它自家的数据摄取服务单独列价。要估算你最忙那个月的账单,以及日后迁走的成本
  • 它解决不了的:你仍需自己运行的采集器和加载器、重复事件、迟到事件,以及与出价方日志的对账。这项服务只存储你发给它的东西,对你的出价方计了什么数一无所知
  • 代码归谁:归你,而服务按服务商的条款运行

重建管道:

  • 适用情况:核对计数显示多个环节都在丢失,或者现有设计无法随你的流量扩展。只有当补上竞价 ID 意味着要改动每一个环节时,缺少竞价 ID 才成为重建的理由
  • 你要付出的:三条路中最大的工程工作量,外加新旧两条管道并行运行的一段时期

哪些公司能基于 Kafka 和 ClickHouse 重建广告事件管道?

做这类工作的公司有两种,本文不给其中任何一种排名。广告技术工程公司构建出价方、广告交易平台和广告服务器,所以它们知道竞价 ID 从哪里来,但要问清它们是否运行过与你的数据量相当的事件管道。数据工程公司为许多行业构建事件管道,但不一定做过广告技术。要问它们是否接触过 OpenRTB,是否和广告交易平台核对过计数。

聘用一家公司之前,我们该问些什么?

向你名单上的每一家公司提出同样的五个问题。

你们怎样去重?要听对方是否提到:每个事件在创建时、在任何重试之前就获得一个 ID,这个 ID 由竞价 ID 和事件类型组成。管道要去重两次:一次在存储事件时,另一次在报表读取时。第二次很重要,因为 ClickHouse 在后台去重,时间点你无法预先安排。它的文档说,这种做法“不保证没有重复数据”。

你们怎样处理迟到的事件?要听对方是否为每种事件类型设定了一段数字仍可变动的期限,以及一个之后数字就不再改动的时点。在那之后才到的事件,仍应计入并标记为迟到,而不是被丢弃。

你们怎样把自己的数字与我们的出价方日志和合作方的报表核对?要看对方有没有每天按竞价 ID 做的核对计数,以及对每一处差异的书面原因。还要约定差距达到多大时,由专人向广告交易平台提出问题。

你们要怎样在超过我们峰值的负载下测试它?请对方以高于你最忙那一小时的速率,回放录下的一个繁忙日子。回放过程中,让他们关掉一台采集器和一台数据库服务器。结束之后,每一个事件要么已经存储,要么被计入丢弃数。

代码将归谁所有?归你的公司,要以书面形式确认,而且代码从第一天起就放在你的代码仓库里。对方保留的任何东西都应逐项列名,并附带一份许可,让你在工作结束后仍可以使用和修改它。

有哪些危险信号?

  • 还没有人做过核对计数、打开过你的出价方日志,就有人提议重建
  • 对方承诺新报表会与出价方的数字完全一致
  • 关于重复,唯一的回答是承诺每个事件都“恰好送达一次”,对你自己的代码制造的重复(比如触发了两次的像素)却只字不提
  • 唯一的证明是用编造的事件跑的压力测试,而不是对你的流量的回放

amBrain 在其中处于什么位置?

在 AdTech 领域,amBrain 从事 DSP 开发、实时竞价平台和广告交易平台工程方面的工作,其中包括 amBrain 为一家客户开发的需求方平台 RTBBidder。

amBrain 诊断交易和广告技术领域的慢系统:对运行中的平台做端到端测量,报告会指明时间耗在了哪里。

amBrain 自 2019 年起开发软件。它有三种合作方式:整体交付、专属团队,或工程师嵌入你的团队。客户拥有产品与代码的全部所有权,amBrain 的可复用组件除外。

本文不是案例研究。它不描述任何客户的事件管道,提到 RTBBidder 也只是说明它是 amBrain 开发的一个 DSP。Kafka 和 ClickHouse 在这里只是作为示例技术栈,并不是对 amBrain 项目或其所用工具的描述。本文不给出价格或时间表。

如果你的报表和出价方日志对不上,先做核对计数。然后带着结果和同样的五个问题,去找你名单上的每一家公司,包括 amBrain。

常见问题

  • 我们的报表和出价方日志有可能 100% 一致吗?不可能。OpenRTB 说,广告交易平台通知你胜出的消息“并不必然表示广告已投放、已被看到或可计费”,而且有些事件会被当作机器人流量过滤掉。目标应当是一个稳定的差距,其中每一部分都有书面原因,并与每个合作方约定按哪一方的计数计费
  • 我们必须用 Kafka 和 ClickHouse 吗?不必。其他消息队列和分析数据库也能做同样的事,核对计数和那五个问题对它们一样适用
  • 新管道搭建期间,怎样让旧报表继续运转?给两条管道输入同样的事件,每天把各自的结果与出价方日志比对。用于计费的报表最后切换,要等跑完一个完整的计费周期、每一处差异都有了解释之后

手头有类似的设计?

带上您当前的架构和让您担心的故障场景,我们用半小时一起梳理。