腾讯内容中台提供从内容生产、内容加工、内容分发、内容结算等全链路环节的一站式服务,在这个过程中,会产生大量的数据以及围绕这些数据衍生的实时流业务应用,如智能审核、运营决策、在线学习等,从底层去看这些内容生态场景的本质,它需要我们提供一套完善的基于规则引擎的实时流信号服务来控制信号和业务流转,且实时信号场景具有内容数据源复杂、吞吐量高、计算量大、准确度高等特点。因此,我们利用业界前沿的实时流技术,并结合一些核心内容生态实时流场景的自研关键技术,沉淀了一套数据复用度高、可用性强、需求响应快的实时流服务,高效赋能腾讯内容生态产品。
问题 1:多实时数据源动态感知、内容 OneID 数据
腾讯内部各个业务方生产的数据各异,且拥有各自的 ID 体系;随着业务发展,数据源还会动态添加消息 Topic,需要实时动态感知新增的数据源,并以中台统一的 ID 视角串联各个业务的内容数据。
问题 2:TB 级多流数据拼接、批数据重建流状态
内容加工时会产生较多的复杂计算需求,比如,我们需要在有限资源内保障 TB 级多条实时数据拼接工作,以及长时间运行下需要对实时流应用的计算口径进行调整而面临的批数据重建流式数据状态等问题,我们探索了一系列自研技术,解决了海量数据实时流计算问题。
问题 3:规则引擎日千亿次实时信号触发
内容生态系统很多场景依赖实时信号,并且基于规则进行控制和流转,烟囱式开发有较大成本,我们需要构建一套日千亿次匹配的规则引擎信号服务,保障资源共享,实现新增场景一键配置即可支持。
问题 4:全链路全生命周期信号服务质量保障
内容场景中实时信号通常用于审核、运营等核心在线场景,稳定性要求极高。而数据往往面对依赖组件多、链路长、吞吐高等问题,会引起反压、偶发崩溃等多种质量问题,需要我们建设一套通用的质量保障体系,包括可观测性、状态高可用等。
图 3-1 内容生态实时信号系统架构图
数据接入:构建准确统一的基础数据,通过动态新增数据 Topic 自适应感知、十万级 QPS 的 ID 映射等手段,解决数据源消息 Topic 动态拓展无法自动感知、数据孤岛等接入问题。
信号生产:提供滑动大窗口计算、多流 TB 级数据拼接、融合批数据重建流状态、单体流量适应水平扩展等通用解决方案,保障大吞吐下的信号生产的时效性、稳定性。
规则引擎:结合业务个性化触发逻辑,提供统一的规则引擎触发系统,支持日千亿次的实时规则匹配、信号高效去重分发,保障多样场景一键快速支持。
信号工厂:一些信号特征无需经过规则引擎流转,按照主题管理,直接透传给业务应用。
服务质量:我们构建了全链路全生命周期的服务质量保障体系。包括全链路可观测性系统,Flink 核心状态高可用设计、全生命周期质量监控和解决流程、元数据管理等。
腾讯内容中台,提供一站式工业化的内容加工能力,每个业务方可自定义编排加工内容的任务流拓扑。为了稳定性和隔离性,每条任务流拓扑内容加工操作流水会生成一个 Topic,随着业务发展,新的 Topic 会不断增加,同时存量 Topic 数据量可能变大。因新增 Topic 所属集群地址差异大,Flink Source 无法用正则匹配到,导致程序无法自动感知。因此,我们设计了 Topic 动态添加的自适应感知的技术方案,可以做到:
图 3-2 动态实时源自适应感知示意图
主要由以下几个模块构成:
因每个业务渠道(如腾讯新闻、QQ 浏览器等)有自己的内容 ID 体系,为此,在整合各渠道的消费流水时,我们需要将业务 ID 映射成腾讯内容中台统一的内容 One ID 体系。如果直接请求现有的 ID 映射服务,大量的网络 IO 会消耗较大的实时流计算资源。
为此,我们构建了基于二级缓存的 ID 映射解决方案,大幅降低对远程服务的访问,可节约上百倍的计算资源。
图 3-3 基于二级缓存的实时 ID 映射
如上图所示,具体步骤如下:
在实际应用场景中,需要提供多样的实时特征信号,信号生产过程中,我们遇到了多种挑战,本章将结合实际问题,介绍我们通用自研的解决方案。
在内容场景中,需要对内容消费数据的大时间窗口 (如 1 天、30 天等) 的每分钟滑动指标进行日千亿次的实时流计算,并基于这样的数据指标来控制业务流转,如果我们直接基于 Flink 内部的窗口函数,进行实时计算窗口指标时,因不能及时关闭窗口,状态数据会占用大量的内存,导致计算出现反压的情况,程序稳定性差,容易出现卡死现象。
基于上述挑战,我们设计了一种高性能的大窗口计算方法,主要有如下优点:
我们针对大窗口(如 1 天)、超大窗口(如 30 天等),结合计算复杂度和精度要求,采用了不同的计算方案,保障小成本高精准计算多种窗口指标。
大窗口计算
对实时流数据根据数据自身的事件时间是否连续分为如下不同的几种情况:
情况一:分钟级别滑动,每分钟窗口连续有流量的情况
当数据自身的事件时间连续的时候,我们需要拿到上次大窗口的计算结果值,在上次计算结果的基础上,对窗口的头部和尾部进行加减操作就可以得到新的大窗口的值。
图 3-4 分钟级滑动每分钟连续的大窗口
其中,T(6, 4) 代表的是 6min 时候近 4min 的累计值大小,其中 6 代表的是当前最新时间,4 代表的是需要统计的窗口大小,是人为规定的。M(5) 代表的是第 5min 的值。
情况二:分钟级别滑动,每分钟窗口流量不连续情况
当间隔的时间小于窗口大小的情况下,计算当前窗口的值需要得到上一个窗口的值进行加减操作,由于数据自身的事件时间中断,所以要对最后一次窗口的值进行校准。
图 3-5 分钟级滑动每分钟不连续大窗口
其中,T(5, 4) 代表的是 5min 时候近 4min 的累计值大小,其中 5 代表的是当前最新时间,4 代表的是需要统计的窗口大小,是人为规定的,M(5) 代表的是第 5min 的值。
情况三:分钟级别滑动,每分钟窗口流量不连续并且当间隔的时间大于窗口的情况
当间隔的时间大于窗口大小的情况下,由于窗口时间内没有出现流量,可以直接认为大窗口的计算值为当前分钟流量值。
图 3-6 分钟级滑动每分钟不连续大窗口
其中,T(6, 4) 代表的是 6min 时候近 4min 的累计值大小,其中 6 代表的是当前最新时间,4 代表的是需要统计的窗口大小,是人为规定的,M(5) 代表的是第 5min 的值。
超大窗口(如 30 天)
针对 30 天等超大滑动窗口计算,资源开销会成数十倍的膨胀,成本难以承受。我们构建了一套解决方案,成本降低到千分之一,精度只损失了百分之一,在成本和精度间达到了高效平衡。
图 3-7 超大滑动窗口指标计算
如上图所示,计算单个内容 ID 的超大滑动窗口指标过程如下。
在内容生态场景中,由于历史原因和服务器时钟问题导致会出现超自然时间的数据,以及网络原因造成的延迟的数据。传统通过设置窗口水印的方式存在一定问题,对于超自然数据,会导致窗口立刻关闭;对于延迟数据,窗口关闭后,延迟到来的数据未能被统计到窗口指标中。
为了解决上述问题,我们设计了一种可以同时处理超自然数据和延迟数据的方案,优点如下:
图 3-8 延迟流数据滚动大窗口计算
我们窗口计算转换为 Key 的分类聚合问题,通过对要参与聚合计算的 Key 进行巧妙设计,进而实现聚合统计。
步骤 1:计算数据所属的窗口起始值,窗口起始时间值 = 事件时间 / 窗口大小 * 窗口大小,窗口大小是根据业务需求来指定的。对于超自然数据,需要基于业务场景进行时间矫正。
步骤 2:根据窗口的起始值对数据进行分配,正常数据直接放入正确的窗口中,延迟数据由于只是晚到,但是数据的生成时间是正确的,所以可以根据窗口标记找到对应的窗口,放入对应的窗口中。
步骤 3:对窗口中的数据生成独有的聚合 Key,聚合 Key= 计算 Key+ 日期 + 窗口起始时间值。
步骤 4:按照聚合 Key 的值进行 Shuffle 分组,聚合 Key 相同的数据会被发送到同一个计算任务,进行聚合或者更加复杂的计算,并且清理内存中过期的聚合 Key,避免程序随着时间推移出现性能下降问题。
Flink 原生实现进行 TB 级数据拼接时,计算较慢,且状态备份时可能异常导致难以升级 APP。
因此,我们构建了可以解决大状态下多流拼接的时效性和稳定性问题的技术方案,并保证最终一致性。
图 3-9 基于 HBase 实现 TB 级实时多流拼接
主要思路如上图所示,我们借助第三方 HBase 存储完成多流关联。
在本阶段的存储设计中,HBase 的 Rowkey 为待关联的 Key,列分别为属性 Key 和属性值。同时,我们进行了大量优化设计:
在内容生态的实时计算场景中,我们经常会遇到累计指标的统计,比如某一条内容的实时总点击数、展现数等。传统的方式主要是用 Lambda 架构进行加工,面对口径发生变化等情形时,会有如下问题:
因此,我们设计了批流状态融合架构,主要优点如下:
图 3-10 批量融合状态重建架构
首先计算业务历史全量累计数据存入 Key-Value 缓存中作为基准数据,把实时数据和基准数据进行融合计算得到最新累计值,并可根据下游系统的负载能力调整数据的输出间隔。
步骤 1:初始化时或者业务口径变更后,通过离线批处理计算历史全量数据,作为每个 Key 的基准数据,导入到 Key-Value 存储系统。
步骤 2:重启实时流计算应用程序后,每个 Key 根据是否初始化过基准数据,从 Key-Value 中初始化基准数据。
步骤 3:将基准数据和实时数据进行合并计算,通过流量控制把数据写入到下游业务存储系统中,供业务查询使用。
内容生态面临着内容的消费数据越来越大的情况,单个实时流计算程序在 Flink 状态不断增大的情况下,由于单个程序需要维护的状态越来越大,程序频繁出现反压问题,增加程序的并发度也提高不了稳定性。
通常我们会增加实时流应用来适应流量水平扩容的架构,但是增加应用后,如果把数据随机发往扩容后的程序,会有一些潜在的问题,例如在计算某个内容 ID 累计值的场景,需要这个内容 ID 对应的所有数据严格发送到同一个程序,才能保证最终结果的准确性。
图 3-11 单体流量适应水平扩容
为了解决以上问题,我们设计了如下可以适应流量水平扩展的架构。步骤如下:
步骤 1:记录数据首次进入系统的时间,为了防止数据丢失做高可用的持久化存储。
步骤 2:维护系统扩容前后的 buckets 的值,当数据过来之后根据数据首次进入系统时间所处的时间段找到对应的 buckets 的值。
步骤 3:对内容进行寻址,将内容 ID 哈希后分配到 buckets 个桶中,而下游每个 App 对应一个桶。
在内容加工场景中,需要将消息队列数据同步到 HDFS 中。同步时,会有 N 个同步子任务,其中 N 由流量峰值决定,N 在同步过程中不能调整,当数据时效性为分钟时,每分钟会有 N 个子文件。然而,在流量低峰期时,由于 N 不会改变,会产生大量的小文件。
图 3-12 输出文件数自适应流量
如上图所示,我们构建了一种输出小文件数自适应流量减少的解决方案。取单个文件为目标大小 S(如 64MB),以控制文件数目。我们将整个过程由原来的 1 个阶段拆分成了 2 个阶段:Map 阶段和 Reduce 阶段,其中 Map 任务数是 M,Reduce 任务数是 N。以下两个阶段,每分钟调度一次:
在内容生态中除了实时流信号的生产服务,往往我们还需要进一步基于实时流信号,结合规则引擎管理业务个性化的触发逻辑,以此来支持内容周期智能管理等多种应用场景。
图 3-13 基于规则引擎的实时信号触发
规则类型
基于不同的业务需求场景,规则定义区分了固定规则和动态规则:
规则管理
提供规则以及内容阈值的增加、更新、查询等能力,并支持如下数据管理能力:
规则定义
配置模块旨在对规则进行进行抽象,通过定义通用的规则抽象定义,把用户在管理配置信息进行接入存储。解耦用户规则定义和规则引擎,降低用户输入和规则引擎的依赖,这样可以便于我们无负担去升级替换规则引擎而对用户无感。
图 3-14 规则信息
规则描述包括两部分,规则条件表达式 + 规则动作:
基于上面信号产生的实时信号和规则管理提供的规则信息,我们探索了开源的 Aviator、Flink CEP 等组件。Flink CEP 构建规则执行引擎时有如下问题:
Aviator 支持丰富的运算符和表达式,同时具有轻量级和高性能特点,能够完全覆盖我们的场景。为此,我们选取了 Aviator 作为规则匹配引擎。
规则执行引擎主要有如下三个模块:
规则加载
负责进行执行器所需配置的加载和实时感知,主要提供如下能力:
规则路由
从输入信号中提取业务渠道,和规则中业务渠道进行关联匹配,依次路由到不同的规则匹配算子中。
规则匹配
为不同规则提供相应的匹配能力:
并发匹配:由于单个任务计算能力有限,把数据分为若干份,在多个任务中进行规则匹配,极大的提高了规则引擎在大数据量场景下的匹配能力。
二级缓存:动态规则匹配时,需获取(内容 ID、规则 ID)的阈值,因输入信号峰值 QPS 数十万,拉取阈值会有较大网络 IO,造成极大资源开销。参考前文 ID 映射的解决方案,我们构建了(内容 ID、规则 ID)-> 阈值的二级缓存,可以极大节省匹配资源。
预编译技术:进行规则匹配时,首先将规则编译成机器能理解的字节码,然后将上游信号作为数据输入进行匹配运算。该过程主要耗时在将规则编译成字节码阶段,我们将规则对应的字节码进行缓存,可以节省上千倍的算力开销。
信号去重
经过规则执行引擎后,仍然能召回大量信号,针对审核等场景,一个内容触发后,短时间内不需要再次输出,以免重复审核。为此,我们进行了个性化去重模块,支持灵活的去重周期,如永久去重、天级去重等,为不同的业务场景召回所需的信号。
信号分发
下游有多个业务系统,基于规则和业务场景的关系,将信号分发给对应的业务模块。分发方式支持消息队列投递以及接口回调,业务可以根据需要进行定制。
实时流服务对接的数据源多、加工链路长,会导致如下问题:
我们构建了全链路端到端端的可观测性系统,可以监控端到端延迟并快速定位问题环节,主要分位以下 4 个模块:
图 3-15 数据染色示意图
图 3-16 全链路实时拥堵分析
内容生态中,计算内容的累计值、首次时间等场景,强依赖于 Flink 自身状态,但是因为依赖组件异常等原因,导致 Flink 有概率丢失状态,无法满足对数据一致性要求非常高的场景的需求。
我们构建了旁路系统,保障 Flink 状态异常丢失后,作业重启后核心状态的高可用。架构如图所示,主要由 2 个模块构成
图 3-17 旁路系统保障状态高可用
创作者文章发布后,需要进行相关必要审核,以保障线上内容的安全、优质、健康。因此,我们构建了智能审核机制,可以保障内容更高效的分发,更快地触达用户。
图 4-1 内容质量智能审核流程
整体流程如上图所示,主要有 2 个模块:
为满足不同用户的体验,需要给内容进行多种场景适配,随着内容不断增加,服务商成本非常高。为此,我们提供了一种基于内容周期提供分级服务的能力,在保障整体体验的前提下,可有效降低成本。当内容访问量达到一定阈值时,提供可适配多种场景的服务能力,保障用户体验;当内容访问量极低时,只提供基础服务,降低成本。
内容从生产到消费,中间会有大量的个性化加工需求,围绕其构建了一套微服务编排系统。其中会有调度器控制任务的分发、路径寻优、弹性伸缩等工作,在不同的算法选择中,通过性能效果的实时反馈,可以极大提升调度效果,减少加工耗时,提高处理成功率。
图 4-2 实时信号赋能网络流量智能路由
如上图所示,主要有以下几个过程:
内容创作运营平台会发起各种精细化运营活动,围绕实时信号,可以进行分析、达标判断等,高效的对作者进行拉新、留存。
图 4-3 内容创作精细运营
如上图所示,运营人员发起运营活动后,创作者领取相应运营任务,并进行发文。基于实时计算的消费量、互动量等特征信号,可以进行活动达标判断,进而将激励实时触达给创作者,提升运营活动效率。
目前,我们已经在基于 Hudi 数据湖进行了一些批流一体的基础场景的探索,后面我们会进一步的将本文一些复杂、成本高的场景迁移到数据湖中,比如探索数据湖上实现 TB 级别实时流数据拼接、批流融合状态重建等场景的可能性,实现一套代码,两种执行模式;一套系统,统一技术栈;一套运维,统一资源调度。
另外,当前计算模式能较快、较好地满足业务发展需求,随着行业降本增效的大环境,我们未来会围绕快、好、省的方向更好的支持业务。比如探索计算资源动态弹性自适应、存储等方向,技术赋能业务。
作者介绍:
王冬,腾讯内容中台研发工程师,熟悉技术产品、技术优化、技术赋能、技术管理等领域。
杨浩,腾讯内容中台数据研发工程师,专注数据平台、内容处理的架构设计与研发。
李文斌,腾讯内容中台数据研发工程师,专注海量实时数据高性能处理,通用性架构设计。
王玢,腾讯内容处理中台产品设计师,专注内容处理全链路设计,智能化处理工具设计。
李会珠,腾讯内容处理中台后端研发工程师,关注微服务、内容处理、流程引擎、高并发架构领域
最后,感谢 kyler、richard( 飞哥)、stan、mars、gavin、jamie 等的大力支持指导,以及腾讯数据科学与分析中心、腾讯内容处理中心、相关业务团队每一位成员的共同付出。
动动嘴就能写代码了!Copilot测试新功能“嘿,GitHub”,告别键盘编码
再不拥抱Serverless就晚了 | Q推荐
和Rust一样好,编程更安全?三年实践、员工态度反转,英伟达用 SPARK 换掉 C
反转!马斯克正在求被裁工程师复职,尤其是Android和iOS开发
活动推荐
想探究如何更好的设计物联网场景数据管理架构?想了解 Apache 基金会唯一时序数据库 top-level 项目 Apache IoTDB 提供的物联网数据管理方案?期待、好奇 Apache IoTDB 最新 1.0 版本 (分布式)?想知道 Apache IoTDB 在各领域龙头企业的实践案例和合作生态?12 月 3 日,在北京丽都皇冠假日酒店举行的 [2022 Apache IoTDB 物联网生态大会] 将解答你的所有问题!扫描下方二维码,免费领取价值 399 元的大会门票!