互联网广告请求链路_广告计费系统容灾设计(上)-数据流&系统

本文介绍了蘑菇街广告计费系统的架构和容灾设计,包括数据流的处理,系统容灾的关键问题,以及如何保证数据一致性。系统通过数据采集阶段的防刷机制,使用Kafka进行数据缓冲,保证数据处理的负载均衡和幂等性,以应对数亿级别的曝光和点击。此外,系统采用限流、降级和幂等性设计以确保稳定性,并支持AB测试和不停服切换,确保在高流量和异常情况下的数据一致性和系统可靠性。
摘要由CSDN通过智能技术生成

822df352121a6f3476d1f07bd639b184.png

互联网广告系统本身是一个对稳定性和可靠性要求极高的系统,每天面对数十亿级别的请求,广告投放主多样的投放方式变化与用户关注点及兴趣频繁的更新,同时对时效性要求严格,而作为电商广告的计费系统,则要求更加严格, 从打点到计费任何一环节出现问题,都会带来巨大的经济损失和平台信任度危机,涉及到商家账户资金,系统实时反作弊和防刷,亿级别点击(曝光)等高效稳定账务扣费,数据的强一致性和最终一致性的保证及全链路高效可靠的监控..

本次主要介绍下蘑菇街广告计费系统的持续优化改进中,系统容灾方面做的一些事情

一.计费系统介绍:

广告对很多互联网公司营收占有非常重要的比重,对互联网广告大家应该不陌生,日常pc和app应该见过很多(弹窗广告,视频广告等),电商来说也是非常重要的营收方式,那么这些广告是怎样计费的,先来了解下几种常见的计费模式

CPC(Cost Per Click ) : 按点击计费的商业产品,对于电商,常用于站内广告资源位,用于推广商品
CPS (CostPer Sale ) :按成交计费的商业产品,站外引流,站外长尾流量,用于推广商品/店铺
CPM(Cost Per Mille, 或者Cost Per Thousand;Cost Per Impressions) : 按曝光计费的商业产品,站内banner位等资源,用于推广品牌店铺
其他还有比较常用的,如:CPD(按天计费),CPT(按时间计费),CPA(按激活或者行为等).

广告计费系统的数据流,如下图所示:

5b5f2bb39a9dace236c4331ee28841f7.png
计费系统模块图

数据来源:web端用户对广告触发行为产生数据,主要是广告资源位上广告的曝光,点击等

数据收集:用于接收web产生的广告数据,为了保证下游系统的稳定性,盗刷及恶意流量一般这层要给拦截住,核心必须保证性能高效及数据防刷功能

数据处理:广告系统计费最核心的功能部分,主要是计费数据的处理,涉及到计费策略,计费金额核算,反作弊及对余额或者预算不足广告进行上下架等操作

数据存储:主要是对处理过的流水,账务及广告数据的持久化

和数据流结构对应,我们来了解下蘑菇街现在广告计费系统,整体架构如下,其中billingWorker是处理计费数据最核心的程序,unionLogAgent是自研支持规则定制和流量切分的数据收集程序,后面会对每个部分的技术及设计做重点的介绍.

a01bec2b3cad124838b6870352ac7b78.png

二.系统容灾设计

计费系统的每个数据都和钱息息相关,系统不稳定,数据不可靠直接损失的是钱,主要面临着以下的核心问题, 怎么样保证系统与数据的可靠与稳定,是我们系统在容灾设计上需要去重点考虑的点:

4026001516ab03b5a0f61f95c71a0212.png

这些问题我们是怎样考虑的了?接下来主要从数据/系统/链路完整性及监控方面重点介绍蘑菇街广告计费系统的容灾设计.

1.数据流

数据流面临的问题:

1.恶意流量攻击,异常数据对系统的冲击

2.数据回溯,快速定位失败数据

3.链路数据的一致性,数据丢失或者重复

面临着数亿级别曝光和点击,既要保证数据的一致性,不发送漏扣或多扣,又要保证系统的稳定可靠,整体在设计阶段必须重点考虑系统的容灾,先介绍下我们在数据采集阶段的设计.

▶数据采集

数据采集阶段,从整体的设计上,必须满足三个目标:

1.采集程序的性能要高效,尽量做到业务无关性,能弹性面对我们的热点流量
2.我们期望在最上层就将恶意流量拦截掉,避免对下游冲击,面对恶意盗刷或攻击(人为或者第三方程序刷点击,刷曝光,爬虫),能快速灵活定制化我们的规则拦截无效流量
3. 保证系统的稳定及能快速恢复,并且做到简单快速并保证无数据丢失

最开始在技术选型方面,主要考虑以下3种方案:

2bf130fadf26d9003f8c4de306470418.png

最终采用方案1-2,优点是 :

1.nginx只管接收数据, 日志落盘和收集解耦,不会有任何业务逻辑,能保证性能的高效

2.unionlogagent独立开发,完全自己维护,并提供防刷模块,支持规则定义及流量拆分,可以有效拦截高频恶意流量

3. 定制优化kafka客户端,对于每一条消息无论成功或失败都进行ack操作,确保不会出现数据丢失的可能

4. unionlogagent会实时持久化成功最小offset,出现异常能快速恢复并能快速自动回溯数据

方案0:公司默认的方案0,最大的问题是unionlog采用php,由于php线程切换导致性能不会很高,同时利用共享内存缓冲, 共享内存容量有限,面对热点流量冲击时,会造成共享内存满,数据丢失..同时logagent采用scala的kafka客户端,当客户端超时,消息重试3次仍失败,会丢弃而且业务无感知,可能造成数据丢失

方案2:数据收集和下发耦合,收集程序出现异常及重启过程,也会造成数据丢失,同时依赖web容器,环境重,性能无法比拟单纯nginx

其中unionlogagent主要的架构图如下:

c233f7583ba8f2f4b26c6749c8c35761.png

防刷模块:主要是根据时间跨度,MD5校验和小黑屋来拦截异常流量

时间跨度,曝光和点击时间差或点击数据与当前时间差较大,就认为是异常流量,重点针对爬虫或者单接口攻击

MD5校验,会有前端用户身份标示及后端动态口令,保证数据的有效性,能有效拦截各种盗刷及恶意分享产生的行为

小黑屋更多和反作弊结合,根据用户某段时间的行为做黑名单处理

构造MD5唯一ID,这个是非常重要的点, 会对每条日志生成唯一身份标示,对日志追踪有非常重要的作用

unionlogagent还通过一套ACK机制,会持久最小成功offset的持久化,能支持下游链路灾备的切换,保证系统的容灾及数据的快速恢复及回溯

▶数据缓冲

数据缓冲部分的设计就比较简单,主要的消息中间件是用kafka, 通过redis做灾备(轻量级,出问题恢复时间及数据量可控,redismq能稳定支持)

d433ccdf56d7b3cd494562d7aff0c637.png

之所以选用kafka,主要是kafka对于数据的持久性可靠性能保证,同时容错性做得非常好,比如kafka我们设置的副本数是3个,4台机器,就算集群中2台机器出现问题, 整个集群也能正常运行,同时在高并发和高吞吐上kafka也能很好的满足

这里要着重补充一点,为了保证kafka整个集群分区数据的一致性,我们将kafka的ack等级设置为all,保证异常情况就是出现主从分区切换,也不会出现数据丢失

▶数据处理

计费系统最核心的部分就是数处理,最核心功能是消息分发的负载均衡 及 消费端异常的接管,同时能支持很好的水平扩展, 这部分的设计,最终选用方案1

我们利用了kafka本身有partition的机制及容灾方面非常好的设计,基于kafka+zk的方式实现动态的负载均衡和调度,整个过程根据partition和billingWorker的数量,采用固定策略做自动负载分配及接管,无需人工参与,异常情况系统也具有自愈功能

71e89b60cde957014e306a0101dc3970.png

当有新的partition进行扩展或者billingWorker出现异常或者扩容,系统能自动重新分配partition和消费的billingworker,支持系统自愈和平滑扩容的功能.

▶数据一致性

链路比较长,核心主要在两个阶段:数据收集和数据处理.中间面临着很多问题:每个节点的故障,kafka分区的切换,计费程序的故障,DB操作失败等等

出现这些问题时,怎样保证数据不丢失不重复,从全局能保证数据的一致性, 异常数据能够被系统感知并快速消费,因此只有在每个阶段消费成功的offset能够被追溯, 在出问题时才能快速定点恢复异常数据

要保证全局的一致性,那必须先保证局部的一致性,因此我们设计了两套ack机制来保证我们的数据一致..两套ACK机制的核心思想如下:

d7fcaed56676fda06089465325cb44a2.png

最小成功offset持久化保存,能支持失败数据快速回溯,利用fail队列支持重试机制,通过数据收集和数据处理阶段的ACK机制,通过局部数据的一致性,最终保证全局数据的一致性

2.系统容灾

系统稳定性面临的问题

1.系统幂等,扣费时效性及热点数据处理

2.系统大流量的冲击,系统的雪崩

3.自身AB及不停服切换,平滑升级

▶系统幂等性

为了保证数据具有去重功能,过程中需要对于失败数据的重复消费,灵活快速回溯各种数据,而且最终要避免多扣,那么扣费系统需要“幂等”功能,对于有状态环节,同一数据结果必须幂等,实现计费链路去重逻辑.

ae0bef7b44eb09d4159433dfe987fa71.png

系统上为了实现幂等,首先必须保证每条数据的唯一性,刚刚在数据采集阶段也说过,日志的生产端的时候,就会构造单条扣费日志唯一性主键(GUID).

其次整个数据流上要做到无状态,整个系统有状态的环节,其实主要有两部分,一是:反作弊程序, 主要是由于反作弊规则中单用户对单广告有类似次数限制的规则,二是:计费程序,要保证这个阶段中间任何一环节,重试机制都需要加入去重逻辑,保证程序的幂等

讨论过很多次,从稳定又简单的方案考虑,我们最终选用缓存的方式保证反作弊唯一结果,DB的唯一索引来保证计费的去重逻辑

▶扣费时效性

效果广告计费是个非常实时的过程,对时效性要求非常高,出现延迟会导致投放时间差的漏洞,也会造成平台的损失(缓存点击),那么必须保证扣费的时效性

首先系统层面, 导致系统低效的原因主要如下:

1.第三方依赖(DB,redis)链接及数据传输网络开销

2.第三方逻辑耦合在主流程中,占用主链路的开销

3. 线程的频繁创建与销毁,频繁的上下文切换

4. 热点数据的分布不均匀,不能高效的利用CPU

针对这几个问题,我们的主要改进如下:

Ø减少不必要的依赖:强依赖转弱依赖

1、第三方依赖异步化(kafka/sentry/数据统计),保证主流程安全,同时提高主流程效率。

2、弱依赖埋好开关,在出现性能瓶颈时可以及时关闭。

3、连接池应用及网络部署优化,减少中间网络开销

Ø根据业务特点,找到相对合适的上下文切换

CPU密集型:线程数=2 *核数

IO密集型:线程数=核数/(1-阻塞系数) 阻塞系数=链路中IO占用的时间占比

除了系统外,扣费时效性上,在实际投放过程中,我们还面临着热点数据的挑战 ,存在热点商家或者热点流量,一种情况很多大商家全部被分到同一个线程队列中处理,则会导致某些线程阻塞而某些线程空闲,未能最大化并发效果, 处理不好同时还有可能造成系统雪崩;

1.过程中如果只是以特定的线程来处理一个队列,由于点击在商家维度的不均衡性,一定会出现某些队列堵塞。

2. 大队列堵塞会导致大量的缓存点击,会影响收入

针对这个问题,其实我们的解决方案核心思想很简单,就是:分而治之

1.按照userId的方式进行hash队列拆分,分拆合适粒度的队列,多队列并行,消费程序(billingWorker)分布式部署分配接管队列消费

2. 线程和队列分离,按队列数据长度,动态分配线程,提高热点数据消费效率.

▶限流降级方案

在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。

缓存:提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹

降级:暂时屏蔽掉非核心流程,避免对主流程造成影响,待高峰或者问题解决后再打开

限流:一个时间窗口内的的请求进行限速来保护系统,常见的限流算法有:令牌桶、漏桶、计数器也可以进行粗暴限流实现

而有些场景并不能用缓存和降级来解决,比如稀缺资源(流量飙升的会场,活动页广告)、写服务(如大量扣费,冲击下游),因此需有一种手段来限制这些场景的并发/请求量,即限流

计费系统主要采用三级限流保护:

一级:接入层限流

数据总入口,根据入口流量及系统流量瓶颈,进行限流。

二级:系统级限流

程序本身计费逻辑限流,保证队列不会出现堵塞:在程序数据拉取过程中,判断计费队列中的消息数量,比如当数量大于某个阈值(10000)时,限制流量进入(如:当前队列数据10240个,在QPS 4500时计费队列平均10000个),同时控制总量,避免内存队列堆积大量数据。

当出现断电式故障时,可以快速确定丢失的数量,进行数据恢复。

三级:重试机制限流

程序拉取上游数据限流:当程序下游雪崩时,程序会出现大量异常,异常数据会存储入fail队列,计费程序将根据异常的出现次数,fail队列的长度,决定是否继续从上游获取数据、是否进行不进行重试,走fail队列消费逻辑进行数据恢复。

系统自身AB&平滑上线

为保证系统的7*24小时服务,对于新改造的系统也需要保证稳定性,并支持小流量平滑上线 ,同时对于新的业务模式做一些计费验证,因此利用unionlogagent在数据收集阶段做流量切分服务,能够支持自定义规则的流量切分,保证我们的计费程序能做自身和业务的AB,同时也能小流量平滑上线,新程序出现故障时可以快速切回,主要的设计方案如下:

4257d7b47488ea290135338099ac9689.png

很多时候除了数据流层面和系统层面的问题,还面临整个链路完整性的问题,要保证后端接收到的数求是OK,那怎么去确认前端发送请求的链路没有丢失?后端业务数据处理没有异常? 前端链路是否出现流量劫持,是否出现第三方拦截?因此链路完整性也非常重要

同时系统必须具备一个非常重要的功能:监控,除了防范与未然,还需要更快的发现系统存在的问题,并能更好的定位问题,计费容灾下部分,将重点分享下此部分.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值