广告归因系统

604 阅读10分钟

背景

人力背景

因为是一个创新业务部门,所以人力在初期还是比较紧张(后期虽然拿到了大量的hc,但是因为组内招聘条件限制,只补充了三个校招人力),因此,数据组的宗旨是,尽可能解放开发人力,固定的事情交给定时任务来做。结构尽量简化,以保证业务快速验证迭代为主。

广告归因背景

创新产品的起量,尤其是冷启,离不开广告投放。部分社交产品可能通过地推的方式进行冷启,但是大部分产品还是通过广告投放来起量。在广告的出价上,现在的广告平台基本都支持oCPX方式,即根据广告主反映的转化情况实时出价。具体的操作是,广告平台将广告点击信息交给广告主,广告主通过业务内部的转化信息通知广告平台,广告平台使用用户转化信息作为正样本训练投放模型,同时,发生了转化的广告的出价会相应上升,代表广告主希望这些广告更多的投放到用户。

结构

广告归因系统独立于业务系统之外,即使广告归因系统完全不可用,也不影响业务系统的正常运行。

和外部交互

广告归因系统和外部交互的主要有三个部分

  • 从广告平台获取广告点击信息。广告平台允许广告主配置一个带有通配符的链接,当用户点击广告时,会向广告主配置的链接发起请求,同时将通配符替换成对应的信息。这个接口上没有鉴权,容易被刷
  • 从业务系统获取用户转化信息。广告归因平台独立于业务之外,但是需要业务传递业务内部的用户转化信息。对转化的定义由运营同学确定。这里使用mq进行消息的传递。
  • 向广告平台回传广告归因结果。广告平台提供通用接口,通过特定参数的调用被认为是一次点击广告并转化的事件。这个接口大部分使用nonse和traceid鉴权,部分使用hash鉴权。

内部结构

广告归因系统内部分为四个微服务,分别是点击监测,广告归因,结果回传和离线数据收集。

各个微服务之间并不是通过rpc调用,而是通过上传事件到athens,以及消费athens产出的mq进行关联。这样进行了各个微服务之间的解耦,防止在某个服务发生问题时整个广告归因链路失败,同时也可以通过athens的持久化能力,将链路中的数据持久化到hive表中,方便da进行数据分析和报表产出。

点击数据流从广告平台通过点击监测服务流向归因服务,转化数据通过athens流入归因服务,两条流在归因服务中经过处理产出归因结果流,并通过回传服务流回广告平台。

离线数据收集是定时服务,通过每小时定时向广告平台拉取全量消息,获取每个时间段的广告消耗数据,同时和历史消息一起组成全量的广告信息数据。通过和回传服务进行对比,还可以发现链路外是否有问题。

实现

双流连接

本质上是点击流和转化流的二流连接的实现。这里因为这两个事件具有时间上的先后性,因此采用了缓存点击流,匹配转化流的方案。具体的逻辑由特定的归因逻辑实现。

问题:如果点击事件晚于转化事件到来怎么办

用户特征

为了获取用户最近点击广告的内容,接入了特征能力,将用户最近看到的广告信息写入特征库中。在用户首次打开app时,可以让用户直接看到广告中的商品。

为了通过广告id获取广告内容,需要离线从广告平台接入广告详细信息。这里的鉴权用到了oAuth2协议。为了实现token的刷新,使用了分布式锁。

拿到token后,定时从广告平台拉取广告信息,并上报事件。这里不仅拿了广告的内容信息,还拿了广告的投放信息,比如当前的出价,广告的曝光数和点击数等。

为什么只在首次打开这么处理:成本考虑。广告方向的考核指标是新付费用户数。

归因逻辑

由于广告平台和业务平台的id不互通,无法通过id进行join操作,因此,使用了用户的设备id进行匹配。在redis中使用用户的设备id作为key,用户的点击历史作为value存储用户的点击历史。这里点击历史有长度限制100,如果点击超过100次,那么之前的点击历史就从redis中舍弃。

由于某些操作系统上的权限管理,无法获取到设备信息,因此存在一些其他的归因方式,如剪切板归因,channelid,ip+ua+mac等。但都不如设备id好用。

归因截断

应用商店的安装包使用了特殊的channelid,用户通过其他链接下载了安装包之后,在安装时可能被系统引导到应用商店重新下载。这时用户就安装了

优化

配置化改造

为什么要做

因为是个创新部门, 需要尽可能降低人力消耗. 同时, 运营的外包人力比开发的外包人力更多, 而且进行配置化改造后, 业务的处理速度也会提升, 减少了运营的等待开发时间.

怎么做

首先让暴露一层给运营理解的概念, 如监测链接的参数, 业务id, 平台id, 渠道商id等, 这些参数由我来做归一化, 同时, 在广告归因系统内部, 将原有的零散的特殊处理的逻辑根据新的抽象概念进行重新组织, 重新编排了流式处理的整个流程, 使得业务对运营更容易理解和配置.

详细方案

  1. 给出监测链接的产出excel, 运营只需要在监测链接上手动选择广告平台, 并配置业务id和渠道商的id便可生成新的监测链接. 在新的平台接入时, 需要开发参照平台文档进行拓展.
  2. 通过无极平台给出了底层配置db的简单界面, 运营可以通过配置在db中新增业务id. 同时通过实时更新机制, 避免了业务新增时的服务重启. 同时增加了开关, 可以在紧急情况时快速停止某个业务的归因结果回传.
  3. 将服务涉及的上下游mq信息从配置文件中转移到db中, 可以在mq有变动时通过

问题

逻辑问题

监测链接鉴权

监测链接由于是配置到广告平台,只能配置get请求,难以鉴权。

解决方案

  1. 使用正则匹配过滤参数不合法的请求,防止修改参数攻击
  2. 使用redis记录30d内的历史数据,key为广告点击时间和设备id(或者traceid),如果重复则认为是重复记录,不继续处理

为什么不把负样本回传

不知道用户之后会不会发生转化,无法确定回传负样本的时机

实现问题

缓冲一段时间再归因

为什么没用:因为数据不一定是因为网络延迟没有到,也可能是因为mq问题卡住了,缓冲一小段时间无法解决问题。

分布式锁

为了更新access token,需要使用分布式锁防止多个节点同时进行更新(因为更新失败会导致整个数据拉取不可用,告警优先级较高)。

使用redis实现分布式锁,锁的value是当前节点的ip,

分布式锁的唯一性和互斥性:redis setnx

分布式锁的死锁:设置超时时间

分布式锁的操作原子性:set nx ex

分布式锁的时效性:使用定时协程续期

分布式锁的退出:删除key

分布式锁的归属:使用本机节点作为value

监控和容灾

域名服务出错

体现为所有业务在一段时间内无法获取点击监测信息。

验证方案:在公网环境(手机4G网络)手动ping监测链接域名失败。

解决方案:先联系运营和渠道商,停止所有广告投放,等待域名服务修复后再开始投放。

点击监测服务出错

体现为点击监测服务在短时间内出现大量报错,或者服务出现异常,同时点击监测数据量出现异常归零现象。

验证方案:登录广告平台,使用调试工具模拟点击监测链接请求,并在athens上检测染色数据是否上报,以及是否正确。

解决方案:先联系运营商和渠道商,停止所有广告投放,等待点击监测服务恢复后再开始投放。

athens出错

体现为所有服务都无法接收到新的消息

验证方案:咨询athens管理员,或者查看athens监控

解决方案:先联系运营和渠道商,停止广告投放,等待athens回复后再开始投放

业务字段出错

体现为点击流监控正常, 转化流数量正常, 但是没有回传数据.

验证方案: 咨询后端是否有发布, 查看日志, 查看是否有报错, 是否有编解码失败的情况

解决方案: 先联系运营和渠道商,停止广告投放, 和后端同步有无事件的字段改动, 根据改动恢复服务处理逻辑后再恢复投放.

实例: 业务调整了时间字段的编码格式, 导致归因系统无法解析转化的时间, 进而导致无法正常归因. 在停止广告投放后, 新增了额外的处理逻辑, 兼容两种时间格式, 然后将解析错误的转化mq指定偏移点重放, 恢复归因结果.

其他

遇到的问题和解决方案

点击流晚于转化流到达

经统计, 点击时间存储到缓存和点击时间相差超过30s的情况少于1%,

  1. 先到达的转化时间已经归因成功并回传 这时直接使用已经到达的结果并不再回传. 由于只有少数点击数据会最后产生转化, 和运营同步后, 运营认为这个误差是可接受的.
  2. 先到达的转化因为没有点击, 所以没有匹配成功 使用spark定时任务每小时将前一天的数据进行重新归因, 将其中的归因结果给到回传服务. 回传服务如果判断某个转化事件还没有对应的回传, 则将这个归因结果进行回传, 如果已经回传过, 则不再回传.
  3. 点击时间迟到超过1天 经过统计, 这种情况发生的概率非常低, 直接忽略.