写点什么

百度交易中台之内容分润结算系统架构浅析

作者:百度Geek说
  • 2023-09-28
    上海
  • 本文字数:4870 字

    阅读完需:约 16 分钟

百度交易中台之内容分润结算系统架构浅析

作者 | 交易中台团队


导读

随着公司内容生态的蓬勃发展,内容产出方和流量提供方最关注的“收益结算”的工作,也就成为重中之重。本文基于内容分润结算业务为入口,介绍了实现过程中的重难点,比如千万级和百万级数据量下的技术选型和最终实现,满足了业务需求的同时,最终实现了高效,准确的资金结算,文章旨在抛砖引玉,希望能给读者带来思考和帮助。


全文 5185 字,预计阅读时间 13 分钟。

01 业务介绍

什么是内容分润平台呢?简单来说,百家号等平台负责内容的生产和引入,手百等渠道方负责内容的分发,凤巢等广告平台负责在此流量上进行变现。而分润平台,则是根据上述各方提供的数据,通过核心策略模型,赋予作者、媒体、小程序主和用户,合理的、差异化的、有竞争力的分润收益,以吸引更加优质的内容和流量的入驻和合作。通过这种多方相互协作模式,实现互惠共赢的目的。

1.1 三大功能点

针对上述的业务特点,结算系统需要包含三大功能,用于支撑内容分润业务的准确性、合规性、及时性。


功能一:结算模型


这是我们最关键的功能,它负责将出色的文章转化为作者的分润收益。该模型的输入数据包括数据中台生成的用户维度的日分润明细和日补贴明细,而输出则是每月的结算账单,这些账单会被发送到统一业务平台用于付款。在这个过程中,我们经历了一系列步骤,包括每日的计算、每月的总结、预提、计提和账单生成等,所有这些步骤都是按照不同的维度逐层计算和聚合的,最终实现了账单的付款。


功能二:C 端内容交易平台


这个功能主要面向用户,旨在帮助作者及时查看他们的收益,并进一步激励他们的创作动力。作者只需登录平台,即可查看每日的预估收益、文章的分发情况、浏览量等数据,还可以查看每月实际的付款账单,提供发票等相关数据。


功能三:O 端管理端平台


为了确保资金结算更加合规和准确,整个结算体系引入了运营管理和反作弊等不同角色。这些角色在管理端负责资金管控、发票审核、黑名单管理等各种操作,以确保整个过程的合规性。

1.2 名词解释

PALO:百度数据仓库,是基于开源 ApacheDoris 构建的企业级 MPP 云数据仓库,可有效地支持在线实时数据分析。


BNS(Baidu Naming Service):是指百度名字服务。BNS 提供服务名称或服务组名称到服务所有运行实例的映射,你可以根据一个名字(服务名或服务组) 获取服务的信息,包括实例的主机名和 IP、实例的运行状态、端口、负载、实例自定义配置标签以及其他实例自定义信息。用于满足服务交互中常见的资源定位、IP 白名单维护、查询服务下的机器列表、负载均衡以及其他任何依赖于这些信息的开发、测试和运维需求。目前 BNS 已经在全百度各业务线中广泛使用,UB、RAL 等框架的支持和各语言 SDK 也已经发布。

02 业务架构

2.1 架构分层介绍

图 1 是整个内容分润的业务架构。内容分润结算面向数据中台,业务方,用户(作者)和运营管理提供服务。



△图 1.内容分润结算平台系统架构

2.2 关键汇总文件

对于数据中台,我们是直接下游,同时在整个内容分润流程的流程中,我们扮演的是最末端的角色。百家号、问一问、百度文库等业务会将作者的内容分发数据、广告贡献等给到数据中台,数据中台按照各种分润计算模型归一化数据结构,产出三份较为详细的明细文件,包括日分润明细,日内容分发明细,日补贴明细。


日分润明细:作者内容分发或流量贡献所获得的分润详情,明细中包括分润金额,文章分发渠道,父子账号等字段。


日补贴明细:基于运管管理的二次资金分配详情。


日内容分发明细:作者的内容分发贡献报表。


数据中台会将这些数据以离线文件的形式提供给我们,结算系统每日基于配置规则,进行离线计算,最终将数据进行降维汇总。后续每月月初,基于这些汇总数据,做二次汇聚产出用户收益账单。

2.3 服务提供方式

结算系统根据外部需求,提供多种接入方式。面对业务方,结算系统提供 API、网页嵌入模式接入方式。若业务有其自建平台,可将结算系统提供的网页嵌入其平台内部,用于展示用户的收入信息或上传发票等。若无自建平台,也可 API 形式接入。新用户在业务侧申请入驻作者后,业务调用结算系统 API 完成用户注册,开通计费单元,维护财务信息等。后续作者在内容分润平台查看其收入,文章分发报表,重新维护财务信息等。若有重要变更或通知,系统通过站内信方式通知作者。


系统整体支持三种账号体系,面向作者提供两类百度常用账号登录方式,面向管理端提供内网账号登录方式,基于此账户体系做了灵活权限控制,不同用户登录管理端,看到的可操作菜单栏各不相同,避免出现越权操作。同时基于此账号体系,能灵活获取上下级,构建了自动化的审批流程。


结算系统的平稳、合规、高效运行离不开各类协同生态的合力支持。反作弊能力贯穿整个内容分润的始终,着力于打击黑产,识别作弊用户。OCR、发票平台为发票识别,发票鉴定提供了通用服务。财务的各类审核,业务的多维度监管则进一步为资金结算的合规安全保驾护航。各类角色、各个系统协同合作,促成了目前内容分润结算系统。

03 技术难点和细节

上文以整体的视角介绍了内容分润结算系统的架构设计,下面我们将枚举几种业务场景构建过程中的技术选型,来详细介绍该系统的技术落地。

3.1 千万级数据日度任务的技术选型

场景:每日上游会给我们产出明细数据,数据为细粒度,量级为大几千万级别,格式为 AFS 文件(离线文件),需要基于某些过滤规则和计算规则做二次汇聚,后续支持多维度查询,作者端展示报表。

3.1.1 DB 批处理方案

最初任务是在物理机上通过 sql 批处理,任务串行执行,简单明了,同时成功同时失败。但随着数据量持续递增,串行执行可能面临着实效性问题。基于原始的 DB 思路,我们构建了基于 DDBS(关系型分布式数据库系统)的解决方案,全部依赖于 DB,因汇聚是基于用户维度,所以基于子账号 uid 计算 shardingKey 分表,过滤规则也落入库中,后续使用表之间连接过滤,相同分表中的同子用户数据汇聚。使用在线服务,按照分表规则,启动多线程执行任务,实时写入日汇总数据表。具体方案如图 2。



△图 2.基于 DDBS 的解决方案

3.1.2 离线计算

利用 SPARK 天然的分布式计算能力,采用离线计算方案,汇聚时使用 SPARK 计算。基于上游提供的离线文件,构建 RDD1 文件,后续基于一些过滤规则过滤数据和然后基于集合规则,使用 reduceBykey 聚合,产出新的 RDD2 文件。这个 RDD2 文件就是我们后续使用的日表数据。因有各类在线查询需求,需持久化到数据库中,又因产出的日表需支持各角色多维度查询,调研后采用 PALO 数据仓库,具体方案如图 3 所示。



△图 3.基于 SPARK+PALO+DB 解决方案


对比两种方案后,我们最终选择方案二实施。方案二的优点比较突出:1.SPARK 集群自带分布式计算能力,无需我们按照方案一方式自行实现分布式计算;2.数据存储于 PALO,相比于传统的 MYSQL,在大批量数据和多维度报表场景,PALO 性能优势更加明显。3.方案一有一个最大也是我们最踩坑的性能问题,实时大批量写入 DDBS 数据库导致较高的主从延迟,影响了其他业务场景。

3.2 百万级数据的月度任务

场景:基于上述场景会产出月表,数据量大约在百万级别,遵循月度出账计算模型,产出最终的预提数据。日度任务和月度任务的最主要区别在于日度任务计算过程密集,月度任务过滤过程密集。


月度产出计提任务实际就是计算用户本月收入以及本月可结算的收入,可结算收入=以前累积未结算金额+本月收入。目前该任务输入的数据量相对较少,且以过滤为核心,因此此类任务未采用 SPARK 计算。而各类过滤规则与当前用户各种属性息息相关,因此任务围绕用户 uid 展开,采用以用户 uid 为底表,先通过各类策略过滤 uid,后置再计算的方案。数据量虽然相对日度任务较少,但毕竟在百万级别,如果使用单一线程处理所有用户,速度会极其缓慢,所以必须拆分任务,使用并行计算的方式提升效率,而如何拆分任务,如何保障任务全部执行是月度任务模型需要考虑的核心问题。

3.2.1 幂等的分布式数据批处理框架 master 节点

我们设计了主从任务模型,用于支持上述任务拆分执行,主结点先置启动,用于数据备份、初始化出账任务,以及调度从节点。从结点则等待主结点启动子任务指令,启动后获取子任务执行。具体模型如下图 4,5 所示。



△图 4.主节点生命周期


图 5 描述了主节点的生命周期,主节点收到出账指令后,优先做的是账户余额类表的数据备份,这个动作归因于我们月度任务的特殊性,月度任务产出的数据表在其他时间不会更新,即上个月出账结束后,账户余额类的相关表会在下一次出账完毕才更新。


备份表的环节非常重要:


1.是可以在月度任务结束后做数据总额验证工作;


2.是可以用于兜底,一旦月度任务产出数据异常,也可回退到备份数据,重新启动任务。


主节点任务的第二步则是确认出账任务的用户 uid 范围,我们系统为了既支持 C 端用户体系,也支持商家账号体系,重新设计了一套内部用户 id,不论是用户账号还是商家账号的 id 均会唯一映射成一个内部 uid,后文提到的该任务的 uid 均为内部 uid。内部 uid 为自增 id,因此查询数据库,即可获取到最大 uid 和最小 uid,也就确定了我们本次任务的 uid 范围。在 redis 中设置两个 key 代表 uid 的最值。至此,出账任务的前置准备工作就完成了。主节点获取执行子任务配置的 BNS,基于 BNS 解析出所有实例,发送子出账任务指令,子实例获取到指令后,启动 N 个线程执行任务,即假设有 M 个子实例,那最终就是 M*N 个线程同时执行任务。从主节点的任务可看出,该任务无其特殊性,即主节点实际和从结点是平等关系,任何实例都可成为主,也可成为从,这就为调度任务进一步提高了灵活性。

3.2.2 woker 节点的任务流程


△图 5.从节点生命周期


图 5 以上述实例中的一个线程作为示例,详细描述了线程启动后,执行的子任务的过程。首先获取目前的最大 uid 和最小 uid,最大 uid 为主节点固定值,最小 uid 则是一个游标。若最小 uid 已经大于最大 uid,则代表所有 uid 已经处理完毕,线程结束。若不满足上述条件,则继续执行任务,利用 redis 的 incryBy 指令,将最小 uid 向前移动 N 个数值,这 N 个 uid 就是本次子任务的执行范围。拿到 uid 后,先将 uid 变为 N 条任务批量落入 Job 表,并设置初始化状态。落库失败,引入报警机制。落库成功后,按照出账模型,启动过滤规则。所有被过滤的用户 uid 均批量写入 job 表,设置任务结束状态,并且标记过滤原因,便于后续运营查询。过滤规则执行完毕,剩余 uid 十不存一,此时我们利用 sql 计算本月用户结算金额。计算完毕,写入 jobDB 的临时产出表,设置 job 任务完结态,此时一轮子任务就执行完毕。线程继续重复执行上述过程,直至所有线程均结束,代表出账任务执行完毕。

3.2.3 出账确认任务

所有任务执行完毕后,主节点会收到出账任务确认指令。



△图 6.出账确认任务


该任务的主要目的就是确认所有 uid 均执行完毕,无疏漏,具体如图 6 所示。上文提到,子任务执行时,都是先置落库 job 表的,确认任务的第一步:扫描 job 表,看是否有非完结态的任务,若有,则启动子任务,重新执行这批数据。确认任务第二步:获取 job 表中所有执行的 uid 数量和需要执行任务的 uid 数量,确认数量是否一致,若不一致,重新执行出账任务,任务基于 uid 和业务期间重入,已经被执行的任务会被跳过。多次兜底策略执行完毕后,数据总量校验一致后,会将临时月度产出数据写入正式 DB,清理临时数据。之所以设置临时表:1.是为了数据校验工作,若数据校验异常,可快速清理该表,重新启动任务;2.若直接写入正式线上库,大量数据的并发写入会导致数据库的主从延迟,会影响其他线上实时业务场景。后置写入实现了另类的『读写分离』,任务过程中仅读正式表,任务完毕临时表往正式表写入数据。

04 总结

本文主要介绍了在构建结算系统过程中的几个技术重点和难点,而要维护整套系统的平稳运行,不仅有这些技术重点,也有看似微不足道但却环环相扣的细枝末节,保障每个环节不掉链子是运维工作的重要一环,后续我们将着力于提升运维效率,节省人力成本,向着运维自动化、智能化改造。另外目前的技术方案取决于我们的数据量级,未来业务蓬勃发展,业务架构也会持续迭代,期待我们向着更加完备的架构前进。


——END——


推荐阅读


小程序编译器性能优化之路


百度APP iOS端包体积50M优化实践(六)无用方法清理


基于异常上线场景的实时拦截与问题分发策略


极致优化 SSD 并行读调度


AI文本创作在百度App发文的实践

发布于: 16 分钟前阅读数: 2
用户头像

百度Geek说

关注

百度官方技术账号 2021-01-22 加入

关注我们,带你了解更多百度技术干货。

评论

发布
暂无评论
百度交易中台之内容分润结算系统架构浅析_大数据_百度Geek说_InfoQ写作社区