写在前面的话
1,前段时间公司组织MOGU D-DAY技术沙龙,老大让报名去做个分享,周末我想了一下主题,周一去报名被告知后端技术的场已经排满了,排满了。既然如此,那么就先写个文章吧。
2,目前网上有很多广告系统的解决方案,每个企业对广告的需求也不一样,如果你想要的系统是下面这个样子:
那么本文对你来说可能会有小小的失望,因为我们不会涉及DSP、SSP以及ADX等,本文主要介绍的是电商广告,广告主是我们的站内商家,广告的载体是商家上架的商品,广告位是我们站内的资源位,整个流程是一个内部闭环。
整体架构
业界广告的几种常见模式:
CPC(Cost Per Click):按点击计费的商业产品,对于电商,常用于站内广告资源位,用于推广商品;
CPT(Cost Per Time):按时间计费的商业产品,比如直播频道的资源位指定,用于直播间促销活动、粉丝节等快速引流、吸粉;
CPM(Cost Per Mile):按曝光计费的商业产品,站内banner位等资源,用于推广品牌店铺;
CPS(Cost Per Sale):按成交计费的商业产品,站外引流,站外长尾流量,用于推广商品/店铺;
这几种模式在我们的业务中都有应用,其中以CPC最为核心,因此,本文主要也是以CPC作为基础来介绍我们的广告系统,下图即为CPC的系统整体架构。
整体流程是这样的:首先,商家(广告主)在广告投放平台建立推广计划,为推广的商品设置出价,广告数据通过dump系统进入到检索引擎,然后APP/PC/微信小程序等渠道通过topn召回这些CPC商品;这时候,用户看到这些商品,也就是曝光,然后用户点击,最后成交。当然,处理点击的时候主要的逻辑就是按点击扣费。最后对每个事件(曝光、点击、成交)的数据进行收集、处理,将处理的结果反馈到广告投放平台的效果报表,供商家投放决策提供指导。
将上面的流程抽象一下,即为本文接下来重点介绍的4个子系统:广告投放系统、广告检索系统、广告计费系统、数据报表系统。
(PS:这里提到的广告投放系统特别指的是广告主推广平台。)
广告子系统
1,广告主推广平台
1.1,广告结构
早期阶段(2015年6月之前),广告结构比较单一,商品即广告。为什么这样设计,我总结了几点:
第一,广告结构简单,对应的广告系统的处理逻辑也会简单,系统可以快速跑起来;
第二,早期蘑菇街是以导购起家,逛的形式居多,搜索流量占比较小;
第三,蘑菇街的人群还是比较窄的,一直号称定位18~25的年轻女性;
第四,图片风格限制比较严格,创意的部分变化不大,基本跟主站保持一致;
第五,团队搜索技术不成熟;
现阶段(2015年6月之后),广告系统精细化投放,支持关键词投放、创意等。随着公司自建电商平台,搜索流量的占比逐渐增高,加上当时搜索+算法大神问天的加入,各方面的条件已经成熟,广告结构的升级也就必然顺势而行了。新的广告结构如下图:
推广计划:包含一个或者多个推广宝贝(商品级别),需要设置推广时间段、计划预算、推广平台、定向受众等;
推广单元:扩展设计,目前功能同推广计划,目前建立一个推广计划自动建立一个推广单元,推广单元层对商家隐藏;
推广宝贝:以商品为载体,包含一条或者多条广告,在这一层,需要设置宝贝的通投出价;
推广广告:主要是指类目词或者搜索词,每个类目词或者搜索词代表一个广告,在这一层,需要设置关键词的溢价,即在通投基础上的加价。
▶️针对受众定向和创意做几点说明:
关于定向受众。精细化投放上线后不久,人群定向的功能也同步上线进行实验,当时面临的问题是圈定人群固然提升了商家的ROI,但流量急剧减少,这是大部分商家所不能接受的,最终演变成商家对人群功能并不“感冒”,该功能也在实验一段时间后下线。
关于创意。电商广告的创意应该是和宝贝相关联的,创意和宝贝下面的关键词是多对多的关系。
▶️精细化投放带来的好处:
对商家而言,可以有针对性地对推广的广告(比如关键词)进行溢价,获得更多地展现机会,同时提升ROI;
对平台而言,提升流量效率,最终提升平台收入。
▶️业界广告结构调研:
淘宝直通车:推广计划-宝贝-关键词的三级结构;
Facebook、腾讯开放平台-广点通:推广计划-广告组-广告的三级结构。
百度凤巢:推广计划-推广单元-关键词/创意的三级结构。
综合淘宝、Facebook、腾讯、百度等大厂的广告结构可以看出,三级结构是一个比较经典且实用的架构。
1.2,账务系统:
需要特别注意的点:
本金/红包系统。图中我也特别区分了本金和红包,在这边分享一个经历:在14年的时候,蘑菇街已经由导购转向自建电商,所以需要清退一批老的淘宝商家。这个时候,在退还商家余额上,平台与淘宝商家之间产生了分歧:之前有多个场景产生的奖励金作为红包的形式给到商家,但在扣费逻辑中并没有严格地按比例扣费,导致商家余额中的本金和红包不能很清晰的区分出来。如果全部退还,平台有损;如果此时再按比例进行数据回溯基本本金和余额,商家不认可。经验:账务系统即使在早期的时候也务必需要把本金和红包区分开来!
每日对账。涉及到“钱”,在充值、提现、扣费等各个逻辑上,务必做好财务快照以及财务对账。
2,检索/召回引擎
引用“一个商品的开车之旅”,非常详尽地讲解了用户请求到广告被召回的过程。
随着互联网的发展,流量变现是每个公司需要考虑的问题,蘑菇街作为垂直女性电商领域,我们有哪些变现方式,如何去搭建广告系统,接下来就带大家一起来看一下广告系统的基本构成,通过讲解一个商品在广告系统中的投放之旅,帮助大家了解广告系统各个模块之间是如何工作的。
朔月,公众号:MOGU广告技术一个商品的"开车"之旅
这里提一下算法策略系统,广告算法在整个流程中也是占了非常重要的地位。给大家普及下最基本的排序模型:ctr * bid,ctr即点击率,bid即出价。
3,计费系统
3.1,扣费逻辑
扣费逻辑描述:扣费日志(广告ID,ip,uuid,设备号,二阶价格,渠道,平台,时间戳等)从kafka中被拉取出来,经过MD5校验,数据补全,反作弊,二阶竞价,然后计算扣费分成(本金/红包比例),最终更新广告结算表(商家余额表、广告明细表以及点击流水表),完成计费。
3.2,核心关键点
广告计费系统的每个数据都和钱息息相关,系统不稳定,数据不可靠直接损失的是钱,所以对系统的可靠性、实时性、安全性、数据一致性、扩展性都有非常高的要求。看下图:
高性能(保障系统实时性)
1️⃣,缓存。一个点击到最终扣费的链路还是比较长的,针对每个环节都会调用的DB动作,通过内部缓存的方式,减少对第三方DB的连接调用。进程内缓存我们选用的是GuavaCache。
2️⃣,异步化;减少不必要的依赖,第三方依赖剥离主流程(除了DB),避免影响扣费逻辑。进程内异步的框架我们选用的Disruptor。
3️⃣,降级;针对弱依赖埋好开关,在出现性能瓶颈时可以及时关闭;
4️⃣,分库分表。分库分表解决数据容量问题和冷热分离。首先垂直拆分,将计费库从广告库中单独拆分出来;然后,水平拆分,多机多schema,然后分表。
垂直拆分:
水平拆分:
5️⃣,并发。多线程处理,提高扣费的处理能力。
高并发(保障系统实时性)
1️⃣,多线程。传统并发处理的方式就是启用多个线程,由于DB是行级锁,为了数据的一致性,需要要保证对同一个商家userId不能存在并发。可以通过加锁的方式解决,但会极大地影响效率,所以我们使用多线程+队列的方式进行优化。
2️⃣,多线程+队列。我们针对计费消息按照商家userId进行hash,投递到一个队列中,每个队列绑定一个线程,这样就保证了同一批商家的扣费消息是单线程串行执行的。这样实现既解决了并发问题,又避免加锁带来的性能消耗。此时,依然有个问题需要考虑:有些是大商家,有些是小商家,如果很多大商家的userid全部被hash到同一个队列中处理,则会导致某些线程阻塞而某些线程空闲,达不到最大化并发效果。这,即是热点数据均衡问题。我们最终引入了akka框架来解决这个问题。
3️⃣,akka框架。akka的actor非常轻量级,可以同时构建成千上万个actor;同时,由于akka中的线程与actor是解绑的,这样即可有效缓解(不能完全解决)热点数据均衡的问题。
高可靠(保障系统稳定性、可用性)
1️⃣,熔断&限流。当程序处理效率跟不上或者下游第三方出现故障等,必须保证当前程序中等待队列的长度在一定水位以下,避免继续无限拉取消息给当前系统造成更大压力的情况出现,这就是熔断机制。当然,我们的程序(尤其是第三方DB)承载能力是有限的,为了避免一瞬间爆发极大流量给系统造成极大压力、甚至是故障,系统必须要有限流机制。常见的限流算法有:令牌桶、漏桶、计数器等,我们计费系统的限流就是采用令牌桶的策略实现的。熔断和限流,不仅可以有效保障自身系统的正常执行,还可以在下游第三方出现故障时,避免更大面积的“雪崩”情况出现。
2️⃣,高可用。当出现机器故障(容量不足)、网络中断、程序崩溃等情形时,如何保证计费系统的可用性?我们利用了kafka的消费者组 (Consumer Group)的机制来解决这个问题。Consumer Group是kafka提供的可扩展且具有容错性的消费者机制,一个组内可以有多个消费者,组内的所有消费者协调在一起来消费订阅主题(subscribed topics)的所有分区(partition)。对应到我们的程序,每一个扣费程序应用就代表一个消费者,部署多个应用到不同的机器上面,当某一台机器或者应用挂掉后,kafka会自动进行Rebalance,重新进行分区分配,从而保证的扣费系统的正常运行。
安全(保障数据安全性)
1️⃣,MD5防刷。MD5校验,会有前端用户身份标示及后端动态口令,保证数据的有效性,能有效拦截各种盗刷及恶意分享产生的行为。
2️⃣,防作弊。作弊和防作弊在广告平台是个永恒的话题,这里列一下业界常见的防作弊手段:广告来源,出现大量无refer的广告流量,过滤爬虫IP,过滤内网IP等;用户行为,对广告请求、请求频次、展示、展示频次、点击、点击频次进行分析、限制。(PS:具体规则敏感,这里不深入介绍)
数据一致性(保障数据完整性、扣费事务性)
1️⃣,保证数据不丢失。借鉴storm的ack原理,实现了AckTracker,保障每一条消息都能够得到处理,不会出现扣费消息漏掉扣费的情况出现。
2️⃣,保证系统幂等性。目前使用的kafka版本为0.10.2.2,只支持at-least-once,所以无论kafka本身还是应用程序都不能保证数据不重复,所以扣费系统需要“幂等”功能。
首先,系统上为了实现幂等,首先必须保证每条数据的唯一性,日志在生产端的时候,就会构造单条扣费日志唯一性主键,因为日志落盘后就不会再变化,直接对日志的内容进行md5,构造一个32位串作为唯一性主键。
其次,整个系统有状态的环节,其实主要有两部分,一是:反作弊程序,主要是由于反作弊规则中单用户对单广告有类似次数限制的规则;二是:计费程序,要保证这个阶段中间任何一环节,重试机制都需要加入去重逻辑,保证程序的幂等。从稳定又简单的方案考虑,我们最终选用缓存的方式保证反作弊唯一结果、DB的唯一索引来保证计费的去重逻辑。
3️⃣,事务性。经过一连串的数据校验、数据组装、数据计算等,实际扣费的时候依然出现了3张表:账户余额表、广告消耗明细表和点击流水表。我们的原则是尽量保证这3张表的更新操作在一个事务中,要么全部更新成功、要么全部更新失败。如果实在无法保障强一致性,也要设法保证最终一致性。
可扩展(保障系统扩展性)
1️⃣,应用层可扩展。利用kafka的消费者组 (Consumer Group)的机制来实现应用的可扩展。注意:应用(消费者)的数量不能比分区的数量多。
2️⃣,数据层可扩展(DB)。目前我们的计费DB已经分库分表,如果后续需要扩容,则需要重新配置新的数据库以及分库分表规则,然后通过binlog的方式将线上数据同步过去,通过对账确认数据一致后,可先切读操作到新的数据源,然后再切写,可以通过双写或者停服直接切的方式,最终完成DB的扩容。(PS:不需要修改业务系统)
4,效果数据系统
点击日志经过计费后,与曝光、订单数据一同构成了基础的效果报表,供商家作为广告投放的效果依据,其中曝光和点击构成的ctr(点击率)、消耗与订单构成的roi(投入产出比)是两个核心的指标。当然,效果报表同步程序也是经过了几个阶段的迭代发展。
第一阶段:PHP阶段
早期的时候,广告系统有两个重要的特点:php开发语言以及广告结构单一,因此,此时的系统是比较简单的。
可以看出,此时的系统是通过定时全量扫描点击消耗表,然后整合订单信息,更新到效果报表中,而曝光数据是次日通过hive的方式进行导入。当然在早期,由于广告量级较小(1w),所以每次全量更新的速度基本能够保证在3分钟内完成,这个时延商家是可以接受的。
第二阶段:JAVA化
随着广告结构的升级,广告由原先的商品精细化到关键词(一个商品可能投放几十甚至上百个关键词),也就是说,原来只有1w广告的量级,现在扩大到了30w甚至40w的量,继续采用原来的数据同步的系统架构,时延扩大到15分钟以上,碰到大促的时候时延会更长,这对于部分商家是不能接受的,再加上曝光次日生效的问题,系统到了必须升级的阶段。
当然,这个阶段整个平台也在推进系统Java化(去php),同时平台技术团队封装了全站的binlog解析框架pegion,使得我们系统升级的外部环境也变得成熟。经过改造升级后,点击/消耗/订单数据的同步时延可以控制在3分钟以内,曝光数据的同步时延在15分钟以内。(PS:为什么不能更实时呢?主要还是考虑到对下游DB的压力,越实时,对DB压力越大,是综合考虑商家接受度与系统压力的一种折中。)
第三阶段:接入流处理框架Storm
截止到此时,效果报表同步的程序都是单实例部署,此刻面对的问题是:1.机器偶尔无故重启怎么办?2.程序OOM怎么办?3.程序僵死怎么办?4. 如何让程序快速重启?5.如何扩容?等等;
由于团队之前有尝试使用过jstorm,加上平台storm实时数据平台也比较完善、稳定。因此,效果报表同步程序迁到storm平台也就水到渠成了。同时,我们在开发流处理程序的过程中,不断沉淀出了丰富的通用组件,包括:通用的数据流connectors、统一的流量和性能监控、整合spring和一系列公司内部环境比如raptor等。
第四阶段:Flink的兴起和应用
从2018年开始,Flink迅速火了起来。当然,Flink确实有它的优势:SQL、Exactly-once、流批一体化等。目前,从我司到我们团队都在持续地优化Flink平台的基础设施,而且已经有部分的应用在Flink上运行。当然喽,我们的效果报表同步程序目前还没有迁移,徐徐图之。
最后,如果你对广告大数据实时计算感兴趣,请戳👇
商家和平台最关注是是什么?数据、数据、数据,平台和商家都需要根据数据进行决策和运营,那一定会涉及到离线和实时的数据系统,本文着重介绍广告技术的实时流系统的搭建和方案:高效的产出数据,同时为商家和运营提供高实时性、高质量、多维度的数据,同时支持运营自定义数据报表,提升数据化运营能力。
朔月,公众号:MOGU广告技术广告大数据实时计算系统实践
总结
1,文章主要从整体上介绍了广告系统的架构,并且详细介绍了投放业务系统、计费系统、效果数据报表同步等模块的设计思路以及演进历程。
2,当然,对广告系统的监控、告警、稳定性保障等方面还没有系统的介绍,后面有机会再跟大家分享!