腾讯内容处理中台是打通腾讯内容生产、内容处理、内容分发、内容变现等内容生态闭环的核心基础服务。作为衔接内容生产端和内容消费端的关键路径,旨在通过智能化、规模化的人机协同内容处理和内容审核等关键技术方案,对内容供给端产生的各种形态内容如视频、图文、商品、评论等,进行安全化、标准化、算法化等流水线工业化处理,并将处理后的内容统一分发到腾讯视频、QQ 浏览器、腾讯新闻等多端渠道,为不同的用户群体提供更好、更高效的内容服务体验。
图 1-1 内容生态概览图
腾讯内容处理中台作为工业化内容处理技术基座,面对多元化的业务渠道以及海量复杂多样的内容处理诉求,需要不断抽象业务模型,构建高效稳定的场景化内容处理审核服务拓扑链路,来满足内容生态各种内容处理场景。因此,我们需要重点解决解决以下几个关键核心问题。
图 2-1 内容处理中台关键问题
问题 1:百亿级的异构元数据内容物料接入
由于腾讯每个渠道产品都有自身产品的内容类型及内容调性需求,比如视频、图文、音频、直播、商品、评论、账号、标签等,面对这样多态性的内容,需要进行标准模板化处理,并提供业务场景化的内容预处理机制,同时为了能够唯一识别内容,从中台视角,需要提供内容中台的统一内容 ID 以及和各业务渠道映射关联的 ID-Mapping 服务。
问题 2:单链路数百个算子微服务低代码乐高式编排
由于腾讯各个渠道业务既有通用公共内容处理逻辑诉求,又有各自个性化的内容处理逻辑诉求,且内容处理服务链路通常涉及到 AI 能力和审核等多个服务提供方和多种协同模式的编排。因此,如何支持快速集成到端到端处理流程,提高研发效率,降低搭建内容处理流程成本,成为内容中台架构的核心关键之一。内容中台需要对系统进行高度的抽象化处理,通过可插拔的插件模式进行标准化,并提供高度灵活的低代码形态多元化内容处理服务编排能力。
问题 3:每日数十亿次任务毫秒级优先级可靠调度执行
面对每天数千万的各类图文、视频等海量内容处理需求,需要在数千个内容编排任务链路上在线流式运行,保障数十亿次任务调度毫秒级的延迟,并保障存储资源的低成本诉求,对我们构建消息队列系统、调度系统、运行系统、存储系统等都形成了较大挑战。同时,在面对复杂内容处理系统,如何构建全链路运行优化机制也十分重要,只有这样才能为腾讯内部各个渠道业务方提供高效稳定的定制化内容分发服务。
问题 4:端到端的可观测性和服务稳定性
系统中每一条内容处理流程接入数百个处理能力,每一个能力的处理容量,可用性,服务方式都不一样,如何保障系统在各种协同系统故障时能够快速发现、定位、解决问题,以及如何应对突发流量,提升系统稳定性等问题都对系统提出了更高的要求。
为了更好地理解内容处理中台工作的交互流程,下面将从业务架构图和技术架构图对内容生态领域工业化处理中台进行简要的介绍。
图 3-1 内容处理中台业务架构图
内容处理工业化业务架构和我们熟悉的传统工厂流水线生产模式极为相似。我们从端到端将整个内容工业流水线生命周期分为了 7 大子系统:接入系统、消息系统、存储系统、组件系统、编排系统、调度系统、运行系统等。同时对关键核心功能进行了关键解耦,以满足腾讯内部各渠道对内容原料的复杂多变的私有化处理需求,支持多渠道高效分发。
图 3-2 内容处理中台技术概览图
接入系统:针对问题 1,主要解决腾讯内部各渠道多形态内容物料的自动化接入适配问题,支持对内容进行预处理,比如筛选、合并等。同时,为了保障内容物料在内容处理中台的唯一性,中台对内容进行唯一识别码赋值。基于统一的内容 ID 体系,内容作为最基本的数据单元在各系统间流转和调度,中台也以内容为核心视角来构建业务。
插件系统:针对问题 2,主要解决内容处理服务能力原子化和标准化的问题,使用户能够在全链路复用、共享、扩展内容处理能力,同时大幅降低业务使用方的开发成本。通过对服务处理能力的协议抽象,有效地避免了对基础内容处理功能的重复建设,比如常见的内容算法服务、内容工具服务等;同时,也对内容处理服务提出了标准化的服务范式,提供零开发组件导入,组件同步执行、异步执行的能力。
编排系统:针对问题 2,主要解决用户构建内容处理链路的易用性、高效性问题,低代码 + 代码化多元化模式构建内容处理工业化流水线工作。
Pipeline 模式:适合更低的熟悉成本、更快的开发,基于算子插件组成 stage,stage 内部的多个插件并行执行,多个 stage 之间串行流转构成内容处理链路。同时,我们提供基于 YAML 构建任务拓扑、更好的编码体验、代码式多版本管理。
DAG 模式:适合较低的开发成本、较好的业务理解,基于有向无环图,构建业务场景化内容处理服务分支链路,让开发同学可以有更清晰的业务认知。
调度系统:针对问题 3,主要解决日均数十亿次任务调度的低延迟、优先级队列等问题,并建设智能反压机制。
运行系统:针对问题 3,主要解决全链路端到端,涵盖请求智能路由、弹性执行、代理执行、执行流控、状态微批持久化、结果共享等核心运行优化机制。
存储系统:主要解决内容处理的列更新场景以及宽表存储问题,同时,在降本提效的基础上,基于多租户机制,建设私有和共有的存储服务。
观测系统:针对问题 4,主要解决多系统融合后的可观测性,包括对内容粒度和工程质量的核心指标秒级观测洞察等。
相关术语
为了应对百亿级的异构元数据内容物料接入的挑战,针对多元化的腾讯各业务渠道的内容数据,接入系统主要需要解决的是数据标准化处理与自动化接入的问题,并把业务内容及其原始属性转化为星航系统能够标记、识别和处理的元素。
图 3-3 接入系统流程
为更好的支撑复杂业务场景以及敏捷接入需求,接入系统在设计实现上具备了以下能力要素:
标准化:针对常用的内容形式制定了不同内容类型的标准化协议,最大程度提高星航管线间的能力复用以及降低数据理解成本;
可扩展:在标准化协议之上保留了可扩展性,业务可以通过追加附加协议定制个性化的数据字段,满足标准字段外的业务个性化需求;
低代码:JSON 协议定义的高度可扩展性以及 JsonPath 解析的灵活性以及完备的数据 schema 和校验,实现业务接入特征的配置化解析;
自动化:提供管理端,业务方按照约定的方式自助录入内容接入以及特征定义,节约对接运营成本;
由于腾讯内部不同渠道业务的调性定位不同,接入系统需要高度抽象,统一处理不同类型的内容信息。
图 3-4 各业务的内容类型
由于历史发展原因,各渠道业务线的内容 ID 体系不一,ID 存在生成方案不统一、长短不一、ID 可能冲突的问题。内容中台作为内容的桥梁,需要对各渠道的 ID 进行标准化映射到星航平台内容统一 ID,并进行统一管理。
图 3-5 内容中台 ID 和各渠道业务 ID 映射体系
为便于腾讯各业务层面的内容运营管理,内容处理中台的内容 ID 中,希望能够日期信息方便数据管理和定位;同时,系统层面上,需满足以下要求:
全局唯一:全局唯一不能重复
趋势递增:日期相关,尽量保障数据的有序性
低延迟:接口耗时低,毫秒级别
高可用:底层服务,系统可用性要求高
容量:亿级 / 天
基于底层组件的稳定性以及运维成本考虑,我们选择分布式数据库自增的方式。为了规避 DB 取号段的过程消耗网络耗时影响请求响应,采用双 buffer 的方式,程序内存有两个号段缓存区 segment。当前号段已下发特定百分比时,如果下一个号段未更新,则另启一个更新线程去更新下一个号段。当前号段全部下发完后,如果下个号段准备好了则切换到下个号段为当前 segment 接着下发,循环往复。
插件是内容处理平台编排的核心组件之一,它是对算法特征、质量特征、策略逻辑、人工审核处理等的原子化微服务或者云函数能力抽象,插件包含了插件 ID、版本、微服务的服务名、输入、输出、分类等重要属性。
图 3-6 插件的分类和示例
在业务层面上,插件主要分为:算法特征、质量特征、策略逻辑、人工审核等类型;在平台层面上,为了适配不同性能的插件,按照耗时长短分成同步插件、异步插件。异步插件包含发送插件与查询插件。
对于业务使用方,研发效率的关键主要包括插件开发和管线编排等链路环节,插件主要包括两大类:自定义协议插件和代理协议插件(普通插件、脚本插件、函数插件)。因此,我们在插件开发模式的道路上也做了大量的探索和迭代演进。
3.3.1.1 代理协议插件
图 3-7 代理协议插件开发模式演进
普通模式
普通插件的创建流程主要分为如下 7 个步骤:
开发部署;
熟悉 RPC 开发框架,了解星航插件协议;
代码开发、同步 git 仓库;
服务创建、审批、编译、发布、测试;
注册插件;
编排管线;
管线执行;
图 3-8 普通插件开发模式
对于普通开发模式,内容处理中台本身无需介入管线开发者的开发和部署环节,只要开发者实现了上文提到的插件协议即可。但是,普通模式存在一定的优化空间,因为创建一个功能简单的插件,也需要上述多个步骤,导致创建普通插件成本相对较高。
脚本模式
在许多轻量的内容处理业务场景中,我们可能只需要一些对内容进行简单的逻辑处理。为了优化普通插件开发的成本,星航提供了一种用户仅需提供业务处理逻辑代码,无需关注创建插件的过程中无需了解协议、编译、部署、扩缩容等问题的脚本开发模式。
图 3-9 脚本插件开发模式
如下图创建一个简单的 echo demo,创建插件的过程中,用户只需要关注业务代码,极大简化了插件的创建流程,而且修改代码后逻辑可直接生效,没有延迟。
图 3-10 脚本插件开发 UI 示例
函数模式
对于脚本插件模式,由于是基于 Go + 脚本语言实现,主要存在 2 类问题:
a)脚本插件存在调试困难、适用于简单的需求场景、外部系统交互不易实现等缺点;
b)脚本插件多任务处理流中共享代码逻辑,因此,逻辑更新、结果共享都存在一定的局限性。
基于以上问题,我们参考云原生时代的解决方案,实现了函数插件。用户仅需关注业务代码,平台侧根据用户提供的代码信息,完成从函数到服务完全自动的 CICD【函数 ->可编译的服务 -> 镜像 -> 发布 -> 运行扩缩容】。具体流程如下图:
图 3-11 函数插件开发模式
3.3.1.2 自定义协议插件
由于开发环境和历史因素,部分渠道业务的插件能力使用了自定义协议,为了不额外增加开发部署代理协议插件模式的适配层服务,需要解决快速导入渠道自定义插件服务的共性问题。
图 3-12 自定义协议插件流程示例
PB 协议除开常用的静态引用,还存在动态解析执行的方式,因此中台可以提供服务 PB 协议的注册、解析功能。具体的操作与执行步骤如下:
插件开发者,首先在平台注册自定义的 PB 协议,中台协议代理保存并动态预反射解析协议;
插件开发者创建新插件时,引用新协议,并配置插件协议与自定义协议的字段 JsonPath 映射关系列表
;中台的执行器在调用插件代理时,协议代理会按照 JsonPath 映射关系,把插件协议的请求转换成自定义协议的请求,进而继续调用 PB 中指定的 RPC 接口;
中台获得响应后,采用类似的方式,把自定义协议的响应再转换成插件协议的响应。最终执行器拿到了插件协议的响应,继续调用后续插件。
对于插件开发者来说,整个过程是自助化、配置化的,没有开发协议转换代码与转换服务,可以达到快速导入自定义协议服务的目的。
插件创建成功后,为了便捷地验证接口与功能的正确性,插件支持在线模式的调试。按照预定义的插件输入参数列表进行填充输入参数,通过随机选择后台任一节点方式,即可获取插件的响应结果。另外,还支持生产环境下的插件灰度调试功能:先灰度发布少量服务节点,再到页面指定灰度节点进行请求调试。
图 3-13 在线调试示例
开放是协作的基石,足够开放,才可以让协作足够顺畅。为了解决内容生态基建能力的复用性和扩展性,我们采用多方共建维护的运营模式,打造了算法插件市场,连接腾讯内部多个部门的职能,共同营造现代化的内容处理链路。比如:插件开发者在机器学习平台训练算法模型并部署服务后,可以直接注册成插件。再当试跑数据满足准召指标后,即可被引入到插件市场。
图 3-14 插件运营模式
当前 30 多个团队参与共建,插件累计达到数千个。
图 3-15 插件市场线上示例
为了应对单链路数百个算子微服务低代码乐高式编排的挑战,内容处理中台提供了两种编排模式:pipeline 模式链式编排,适合比较简单的业务场景;DAG 模式有向无环图编排,适合分支较多、比较复杂的业务场景。
图 3-16 任务编排拓扑类型
值得注意的是,每个管线允许多个编排版本的存在,内容会根据灰度比例进入不同版本的编排,实现不同的流程。
3.4.1.1 管线
管线的基本元素有 Materials(内容源)、Triggers(触发事件)、Stage(阶段)、Task(任务 / 插件)、Deliverpoint(交付点)、Deliverables(交付物),其含义为
图 3-17 Pipeline 编排模式示意图
3.4.1.2 插件集
对于流程比较简单的业务,我们提供了插件集模式(Pipelite)。插件集是简化版的管线功能,将整个管线流程封装成一个同步接口,用户通过 RPC 调用的方式输入内容材料(Materials),接口输出内容特征(Deliverables)。
图 3-18 插件集示意图
管线和插件集的区别如下:
我们基于 BPMN(Business Process Model and Notation)2.0 标准,构建了管线编排的 DAG 模式,用于支持比较复杂的业务模型。主要的元素有:
图 3-19 DAG 编排模式示例
上图为线上一个基础的 DAG 管线,内容通过事件网关区分不同事件流程,在不同的分支上进行处理,最后汇总到结束点。
消息是调度系统运转的催化剂,内容处理系统整个生命周期中产生大量数十亿级的消息信号,如业务内容类消息、外部干预类消息、系统工程类消息信号等。因此,需要一个统一的消息系统来及时可靠地处理这些海量消息。
消息系统需要从多方面保障其服务质量,主要包括如下:
(1)消息需要保证可靠性,特别是发文消息还需要保证时序性;
(2)不同类型的消息对时效性要求不同,需要分级处理消息队列;
(3)整体消息量非常大,需要保证处理及时;
(4)推送失败时,需要重试但不能阻塞后续消息;
图 3-20 消息系统架构
(1)消息接入服务:作为接入层,负责消息的接入和校验等工作,并根据消息类型路由到不同的消息队列。通过为不同的业务分配不同的 topic 进行业务隔离,创建多分区来提高吞吐量。同时为了保证同一个内容的消息的时序性,使用星航平台统一内容 ID,作为 key 保证哈希到同一个分区。
(2)消息处理服务:负责持续消费消息队列,根据消息类型调用对应的服务。其中对外部干预类消息的处理,需要考虑一条消息会干预多个管线中的同一条内容。例如,外部检测到一篇文章的热度达到了阈值,需要干预多条管线中的这篇文章都跳转到人审环节,这时需要并发调用多个管线的状态跳转服务。如果对有些管线处理失败了,需要将这条消息以及这次各个管线处理的结果,都发送到延时队列,用于下次重试时不重复处理。使用延时队列,能够避免阻塞消息队列里后面的消息。而对于延时策略,使用指数退避算法(Exponential Backoff),根据失败次数延长下次调度时间,失败次数每增加 1 次,延时时长增加 1 倍,同时为了避免同时到期,还在延时上增加一个波动值。另外还考虑到,如果延时一直增加,当接收服务的故障恢复时无法及时感知,因此会延迟递增到设定值后会周期性重头计算。
(3)状态跳转服务:每个管线有对应的状态跳转服务,接收外部干预类消息,判断管线中的内容应该跳转到哪个步骤,并更新存储状态,然后存储代理发送调度消息到消息队列,供调度系统进行调度。
对于每日数十亿次任务毫秒级优先级可靠调度执行的挑战,调度系统是内容处理链路的核心子系统之一,它需要保障每天千万级内容数十亿次任务的高效调度处理工作,由多个任务单元组成,任务单元之间存在时间先后顺序和前后依赖关系,本质是一个任务链路编排是一个工作流,需要由调度系统对多个工作流进行管理和调度。
对工作流的描述方式,常用的有 FSM(Finite State Machine,有限状态机)和 DAG(Directed Acyclic Graph,有向无环图)。这两种方式各有优缺点,适用的场景有所不同。
FSM 为每个步骤设定一个状态,每个步骤可以有多个任务并行执行,步骤之间顺序执行,也能跳转到指定步骤重复执行。FSM 适合处理过程简单,状态明确的内容处理场景。
DAG 是每个节点一个状态,能描述复杂的依赖关系,还支持子图减少重复执行步骤,但所有节点的状态集合才能表示当前的状态,不便于观测。DAG 适合处理过程复杂,条件繁多的内容处理场景。
目前星航调度系统支持这两种工作流模型,跟据当前的状态执行对应的任务步骤,然后更新状态和结果属性,记录执行的事件流水,方便全链路观测。
(1)调度任务以内容为粒度,任务量大,时效性要求高;
(2)需要支持内容级别的调度优先级;
(3)需要支持分布式调度,动态调配资源,并支持业务隔离;
(4)能够对每条内容进行全链路观测。
图 3-21 工作流调度系统示意图
Scheduler:任务调度模块,负责从存储模块获取任务分配给执行器。
Executor:执行器模块,负责从调度模块获取任务,从元数据中心获取工作流配置,调用相关插件进行计算,最后将结果写回存储模块。
Storage:加工存储模块,存储内容处理任务状态属性和事件流水。
MetaCenter:元数据中心,存储用户编排的工作流配置和管线其他相关元数据。
Plugin:插件,统一封装业务方提供的原子化的计算能力。
3.6.3.1 优先调度队列
内容处理的调度,需要考虑任务量大,时效性要求高,还要能按内容优先级进行调度。借鉴流式处理方式,调度流程使用消息队列进行传输任务。
图 3-22 调度系统流程示意
加工存储模块,记录每条任务的状态和执行结果,在收到新增和更新的请求后,会将需要调度的任务发送到 kakfa 任务队列。这种方式比起常规的轮询任务的方式,时效性更高,并且能减少重复的任务发送。
为了增加系统可靠性,当任务队列集群不稳定或故障时,会将任务发送到补偿队列,保障任务不丢失。
调度队列服务,不断地从任务队列和补偿队列中消费任务,计算每个任务的动态优先级,然后送入 redis 优先级队列。动态优先级的计算,结合了业务指定优先级和调度因素(如状态变更时间和失败次数等),保证高优内容及时处理的同时,避免长时间失败导致影响低优任务的处理。
优先级队列为每个执行器模块的 worker 建一个子队列,一个管线配置多个 worker,每个 worker 只从对应的子队列获取任务。任务入队服务使用一致性哈希算法,计算每个任务哈希到对应管线的某个子队列,当 worker 动态调整数量时,会重新计算,动态均衡。子队列方案比起常规的高低级双队列方案,优先级粒度更小,减少争抢,调度效率更高。
延时队列,对失败任务进行延时调度,减少无效调度,降低对插件计算服务的压力。
任务分配服务,接收执行器模块的请求,从对应的优先级队列中返回任务,可以控制分配速率。
3.6.3.2 动态流控反压
调度系统还考虑了动态流控,当任务大量执行失败时,自动减少对故障环节的压力,帮助快速恢复。
图 3-23 动态流控示意
当插件服务故障持续发生,待调度任务不断增加,监控到优先级队列积压到一定阈值时,会启用反压机制(Back Pressure)。一方面调度队列服务会减少任务入队速度,一方面任务分配服务减少初始任务的分配,先消化处理中的任务,降低执行模块的负担。等故障恢复后,越来越多的任务由于执行成功,会进入正常优先级队列,再快速恢复处理速度。动态流控的效果主要如下:
对故障插件减少平均 60+% 的无效调度,利于插件服务恢复。对插件的调用峰值减少 60%,避免发生雪崩。
故障恢复后,10 分钟内整体调度速度恢复正常。
目前,星航管线调度系统,实现了分布式高可用、秒级调度延迟、动态优先级、动态流控、多租户管理等多种特性,支持了腾讯内容开放平台、腾讯新闻、腾讯视频、小世界等二十多个重要业务上百条管线,每天处理千万级内容量,累计处理近百亿级内容量。
Pipeline 执行引擎基于 FSM(finite-state machine)有限状态机实现,每个 stage 对应一个状态。正常情况下,每执行完一个 stage, 状态 +1。当某个阶段的插件执行失败时,状态在原地流转。流程运行异常时会进入拦截状态,停止流转。被拦截的内容收到触发消息后,可以再次激活流程。流程运行结束后进入完成状态。
图 3-24 Pipeline 执行机制流程示意
由于我们支持 Pipeline 的多版本管理和执行,运行系统需要对并发执行进行控制。在一些场景下,两个执行器会拿到同一个内容的任务,我们用数据版本 row_version 作为乐观锁进行并发控制。当执行器 A 和执行器 B 同时拿到 row_version = 1 的某条任务时,先提交的执行器会将这条任务的 row_version 改为 2。此时后完成的执行器 B 便无法提交成功了。并发执行机制确保了任务只会在一个执行器里执行,避免数据写脏。
图 3-25 Pipeline 多版本并发执行控制
DAG 引擎的设计理念是一个纯抽象、可复用、与业务逻辑无关的引擎,驱动流程在 DAG 图上的流转。将业务逻辑通过开放接口的形式,交给业务系统实现。主要模块包含以下部分:
图 3-26 DAG 执行机制流程示意
由于各渠道业务提供的插件服务的性能与耗时存在较大差异,但被调用的流程相似,因此需要引入插件代理。插件代理对插件行为进行抽象,屏蔽实现方式,统一插件的调用流程。
图 3-27 插件代理示意
插件代理向上面向执行引擎时,插件代理屏蔽各类插件实现细节,表现出一致性;向下面向插件时,提供全局统一的缓存、限流能力,转发流量到各类具体插件或插件中间件。
插件的标准协议,使用自描述结构表征每个字段,并使用 Protocol Buffers 新增的 Map 类型包裹全部业务字段,从而定义出通用的插件协议。
3.7.3.1 插件共享
由于多个管线可能引入相同的内容源,插件在这些管线被引用时,会导致相同内容的特征会重复计算,浪费大量机器资源,因此需要引入插件共享机制。
图 3-28 插件结果共享示意
插件共享用于多个管线之间共享相同内容的能力特征。用户在插件上,可以配置是否开启缓存共享、缓存主键、有效期等参数。当内容处理中台的管线之间存在重复内容时,对于用户开启了共享功能的插件,如果没有命中某条内容的缓存,则调用插件开发者提供的特征能力服务,获取特征能力结果并创建缓存。其他管线如果命中了缓存,则优先使用缓存的特征能力结果,不再调用特征能力服务。通过对插件共享,实现了能力特征的跨管线复用,节省了机器计算资源(CPU、GPU)。
3.7.3.2 流量控制
图 3-29 流量控制示意
当前线上每天有十亿级别的插件流量,每个插件的计算能力都有极限,如何平衡在线系统的插件流量和离线系统的插件流量是个值得思考的问题。
平台采用流量分级机制,对管线的流量进行实时采集、实时计算,评估出主要业务所需的插件流量配额。并将剩余的插件流量配额(增量桶)分配给离线任务,配额的计算窗口秒级动态调整。
3.7.3.3 同步异步
对于执行引擎而言,所有插件都被统一成了同步调用过程。插件模型主要有以下几种分类:
(1)同步插件:短耗时服务只需要注册一个插件。执行器同步阻塞调用插件指定的服务。
图 3-30 同步插件
(2)异步发送与查询插件:异步插件都包含发送与查询两个步骤,需要注册两个插件。执行器通过发送插件,把任务发送给业务。执行器再通过查询插件,查询任务结果。
图 3-31 异步发送与查询插件
(3)异步发送与回调插件:业务把结果回调给中台,中台统一存,执行器到存储中查询结果。
图 3-32 异步发送与回调插件
(4)同步转异步插件:由于业务处理视频时,较多特征能力耗时都会较长,如果使用第二种异步插件模型,那么会迫使业务重复开发多个异步系统,增加特征上线周期与难度。因此,内容处理中台提供了同步转异步中间件,把业务的同步服务在管线上转换成异步服务。执行器把任务通过发送插件发给同步转异步中间件系统,它再调度任务并实际调用业务的同步服务,并把返回的结果写入到内容处理中台存储,执行器再到中台存储查询任务结果。最终达到了业务只需要提供同步特征服务,即可快速上线。
图 3-33 同步转异步插件
管线的执行流程往往很长,为了提高执行效率、减少存储压力,平台采取状态连续执行,结果合并回写的方案进行状态管理。
图 3-34 执行过程状态持久化
状态的回写时机包括:
流程进行到分发点
流程执行结束
插件执行失败
连续执行超过 N 个状态
区别于常规的 workflow 工作流系统,星航所面临的内容处理流程诉求更加复杂多样,诸如特定插件结果变更以及批量洗数据等。有些应用场景业务希望有触发信号干预影响系统的流转走向图,当业务信号发生时流程跳转到指定位置运转。另外一些应用场景业务希望对大规模内容数据进行数据清洗,同时要求对常规的增量内容处理流程不受影响。对此,星航提供了不同的干预能力以覆盖不同的业务需求场景。
特定内容信号触发器
图 3-35 星航系统信号干预触发示例
特定内容的信号触发可以通俗理解成编程语言中的“goto”语句。星航允许用户自定义触发器并在管线特定位置配置引入触发器,当业务方通过回调触发器 Callback API 发送触发信号后,系统通过事件接入模块存储该信号并对关联触发器的管线进行信号广播;调度服务接收到触发信号后把内容对应调度状态重置成目标状态并进行进一步调度处理。业务可以自由定义回调信号对应的附加数据以用于流程控制。
大规模数据回溯处理
图 3-36 大规模数据回溯示例
星航提供的大规模数据回溯处理能力根植于“轻量级”管线即插件集能力之上,通过旁路任务队列接收数据回溯任务数据,基于插件集调度处理获取回溯结果之后在回写至对应管线,在节约了数据回溯存储成本的同时也避免了对常规增量内容的流程影响。
管理端干预能力
除了前面提到的信号触发器以及大规模数据回溯能力,星航还在管理端内置了内容干预入口,方便用户对少量数据进行状态干预处理。
内容属性宽表 schema 需要灵活扩展,同时需要对字段进行规范管理;
需要提供单个内容的详细处理流水供业务查询追溯;
需要支持 PB 级的数据存储,以及对内容万级 qps 的在线读写能力,以及较高的可用性;
需要支持不同业务个性化的关键字段的检索需求;
需要有离线 + 实时数仓提供给业务进行各种查询分析;
在降本的背景下还需要平衡好资源成本。
实际场景中,业务数据主要分为两类:
以内容 id 为主键的属性数据,既包括业务原料库中的数据(比如标题 / 封面等),也包括内容加工的产出特征(比如机器分类标签 / 人审结果等);
内容每个步骤的变更流水,时序数据。
综合考虑,采用了以 HBase 为主要存储,辅以 ES/Clickhouse 等组件的异构存储系统,中间利用 Kafka 进行数据同步。写操作时,先更新 HBase 属性表,成功后写结构化的事件日志到 Kafka,后续再异步消费 Kafka+ 查属性快照的方式将数据同步到后续各个存储。综合考虑性能和业务数据特点,此处 HBase+Kafka 双写的模式实现上不保证原子性,仅对 Kafka 增加了一个容灾集群,当两个集群都失败时需要主调方进行重试。如下图所示:
图 3-37 存储数据流示意图
HBase 具有高性能 / 高可用 / 低成本 / 列易扩展的优势,比较适合平台的场景。根据两类数据的特点,使用了两个不同的集群提供服务:
HBase 属性宽表。需要同时支持较高随机读写,故而该集群使用了高性能 SSD 硬盘,开启自带的内存缓存;同时利用 rs group 来区分核心 / 非核心业务,做到互不影响 ;
HBase 事件流水表。写量极大,存储量大,但是读量极少,主要用于运营展示页面流水查询,故而选择廉价磁盘型机器搭建集群,能够很好的满足写多读少低成本的需求;
由于在内容接入时已经为不同业务生成了星航平台内容统一 ID,从其生成的机制看,经过稍加转换便能保证很好的随机性,从而避免了 HBase 分区的数据倾斜
为了支持除星航平台内容统一 ID 之外的其他关键字段的检索(比如标题、作者、分类、标签等等),目前会根据每个业务的配置,把其需要检索的字段入到 ES,从 ES 检索出数据后,根据需要再从 HBase 中查询完整的属性。这里设计上的几个优化点:
尽量只存储需要检索的字段,以便减少存储量,降低 ES 成本
根据不同业务规模,按季 / 月 / 天分索引,同时采用冷热分离的设置,有定时任务定期将热索引落冷,减少集群整体成本
根据需要预先配置好索引模板(比如让字段名形如 *_ik 的字段值自动分词),针对实际业务数据特点设置的配置肯定会优于 ES 自动生成的配置
不同业务可配置 Jsonpath 规则,定义 HBase 到 ES 字段的解析映射逻辑,以满足不同业务可配置化的检索需求
同时,这里也会异步消费事件 Kafka,将属性 + 事件数据写到离线数仓和实时数仓,离线数仓主要采用司内统一的大数据平台,实时数仓则是选择 Clickhouse 大宽表,作为后续衍生的各种平台分析 + 监控功能的数据底座。
对于端到端的可观测性和服务稳定性的挑战,复杂系统的可观测性是非常重要的问题。平台的监控不仅包含核心系统的可观测性,也包括外围业务系统的可观测。这里分为 Metrics(指标)、Tracing(链路)、Logging(日志)三部分来介绍。
图 3-38 管线监控示意图
本文基于腾讯内部多个渠道的对内容的场景需求,高度抽象并深度优化内容处理中台架构,端到端地对系统进行了解耦设计和优化开发,有效地支持了内容生态的业务场景。
接入效率:强大的接入能力,累计处理百亿级内容数据,支持自定义和模板化的近 10 种异构内容接入,管线创建实现自举,接入周期从 1 周降低至 2 个小时。
研发效率:端到端的效率优化,提供三种不同的高效插件开发模式和在线调试模式,支持 30 多个团队的自定义协议和代理协议进行高效封装算法、业务逻辑等数千个算子插件的微服务;算法能力引入从天级别降低至 1 小时,引入百余个算法插件算子;链路编排,提供低代码乐高式自助化编排,支持任意复杂的内容处理链路拓扑编排、调试与上线,整体链路迭代的交付周期从月级别降低到天级别。
运行效率:每天数十亿的消息信号,高效的延迟队列补偿保障,水平扩展优先级队列处理机制;融合统一 Pipeline 和 DAG 的调度架构,辅以智能反压稳定性保障;插件共享,每天缓存命中数亿次,为业务节省万余核 CPU、千余张 GPU。基于插件的共享机制和执行状态微批持久化等多种执行优化方案,和列式低成本存储机制,支撑起每日千万级的高效内容处理加工。
维护效率:全链路秒级业务内容视角和平台工程视角健康性和追踪性可观测能力。管线的故障恢复、资源伸缩、流量调控通过自动驾驶模块统一管理。目前故障自动处理率 75%+,自愈率 75%+,平均故障恢复时间 2.4 分钟。
内容处理中台高效支持了腾讯视频、腾讯新闻、QQ 浏览器、微视、腾讯体育等 10+ 个业务的高效的内容特征级粒度任意链路节点结果进行高效分发。图文处理端到端 P95 耗时下降 59%,视频处理端到端 P95 耗时下降 96%,分发服务最大数据延迟小于 3s,可用率>99.9%。
中台提供了事件流订阅和内容特征获取两种内容分发能力。平台上流转的内容定义成一个 doc,一个完整的 doc 包含了两部分字段,一部分来自输入字段,一部分来自链路中编排的能力,随编排逻辑动态变化。在运行过程中,doc 中的字段值随着处理流程的调度执行逐渐被写入。
实际生产环境的内容处理链路通常比较复杂,整体耗时在分钟级完成,除了在链路执行成功和中止之外,往往需要实时感知中间态的关键结果产出,因此平台提供了自定义分发点的能力,支持在流程中任意执行阶段进行内容分发,即在流程的任意阶段向变更事件流中写入一次 doc 数据。
图 4-1 内容分发示意图
通过内容特征服务可以获取到最新的 doc 特征,但是由于需要调用方发起请求,因此会有实时性的问题,通常只在一次性查询的场景使用。事件流订阅支持按行按列(即内容维度和特征维度)的规则过滤,对接收方提供 at least once 的变更数据投递和最终一致性保证,使用方可以实时感知自身关注的内容和关键处理过程。
内容审核是星航平台的重要使用场景,也是当前内容行业必不可少的业务环节,结合团队自研的通航审核平台,业务可以快速搭建人机协同的内容审核链路。并只需要专注在具体业务场景的需求上,整体交付周期缩短 90% 以上。
一般业务都会有“机审 + 人审”的流程需求,通常采用机审在前,人审在后的方式,这样可以尽量减少人力成本。在人审过程中往往需要采用人机协同的方式,使用星航平台可以便捷的将算法计算结果打通到通航平台,在通航平台内部实现人机协同,提高审核效率。这个过程中只需要编排相应的算法插件并调整送审插件的参数而无需开发。
相较于传统的开发方式,搭建一条新的审核链路的成本大大降低,开发者可以从重复的工作中解放出来。
图 4-2 内容审核示意图
需要注意的是,内容审核相比机器计算具有耗时更长、计算成本更高、结果可变更的特点。为了让审核过程不阻塞内容处理流程,同时可以更好的响应审核结果。内容审核使用异步插件与触发器相结合的方式接入星航。
对于先发后审的业务场景,星航平台提供流量触发器的方式并结合规则引擎,实现灵活的送审策略定制,包括流量触发、算法模型触发等。同时基于规则引擎,业务可以控制内容流向的审核队列或者目录,不同的队列之间可以采用串联或者并联的方式,视业务需求而定。内容进入通航后,不同队列或者目录内的任务由专业审核人员进行审核,达到质量和效率的最优配置。
未来,我们将从全链路 TCO 成本出发,以降本提效为目标,从开发效率、运行效率等路径视角,进一步深挖技术给内容业务可能带来的价值。
图 5-1 未来工作方向概要
提升心流式插件开发体验,插件作为根基角色,进一步深度探索低代码 + 函数插件极速开发流程,以云原生函数服务 FAAS 为基础,打造全链路自动化开发、提交、编译、部署、实验、上线、洞察等更成熟的开发方案,让开发者只专注对业务核心逻辑开发。
提高任务链路编排效率,探索低代码化 + 智能化编排模式,当前开发者可以基于插件开发业务场景的服务编排任务,但存在两个问题,一方面,如果相同或者类似算法插件多,开发者面临选择问题;另一方面,插件和插件之间还存在着依赖血缘关系,面临熟悉成本。所以,后面我们将探索以业务场景诉求为出发点,智能化整合相关插件,提供插件逻辑视图模块化能力,用户直接从业务功能级出发选择插件模块,无需直接通过插件到拓扑的编排,提高开发效率。
提高系统稳定性并降低系统平响,优化网络请求路由算法,当前一些基础的路由算法不能够满足我们的业务场景,引入网络请求更灵活的 Locality-aware 路由算法,并融合多维度系统特征和业务的实时特征,构建路由权重模型,从资源实际能力角度处理业务请求;同时,我们还将基于全链路效果视角,进一步探索 N3 算法(N 个最近邻居)在路由权重的应用优化。
持续降低内容处理成本,除了系统级资源自动伸缩,我们将从业务本身视角进行物理资源的智能化伸缩,比如,失败率,mttr,业务的某些请求阈值等视角,并通过上文提及的血缘关系,进行水平或者级联等多策略资源伸缩,提高的服务质量,保障用户体验。
提高 CPU 资源利用率和并发能力,在早期系统通过配置及反压的方案上,为了更灵活地动态适配请求的波峰波谷,引入 actor 响应式编程,通过对 actor 的自动伸缩更好利用计算资源,智能化处理计算需求。
移动互联网内容生态繁荣而复杂多样,内容作为移动时代的信息知识载体,对于不同业务场景,我们往往面对着各种各样的业务和技术挑战,因此,我们将在内容生态业务场景的基础上,不断用技术创新去驱动降本提效,并持续优化内容中台用户体验。
作者简介:
李欣,腾讯内容处理中台总监,负责内容处理中台的产品规划、技术研发和团队管理工作。
王冬,腾讯内容处理中台技术负责人,熟悉后端架构领域、大数据领域的技术产品化工作。
蒋靖,腾讯内容处理中台后端开发负责人,关注内容处理、流程引擎、微服务治理等技术方向。
施驭,腾讯内容处理中台后端研发工程师,关注云原生、微服务、高并发架构领域技术。
李湘军,腾讯内容处理中台后端研发工程师,专注于高并发、高吞吐场景的架构设计与研发。
唐伟,腾讯内容处理中台后端研发工程师,关注内容处理业务方向的分布式调度与计算方向。
李会珠,腾讯内容处理中台后端研发工程师,海量后端服务设计开发经验。
贾洪强,腾讯内容处理中台后端开发负责人,关注关系和非关系型存储中间件方向。
刘斌,腾讯内容处理中台后端研发工程师,关注消息队列、云原生领域等技术方向。
黎帆,腾讯内容处理中台后端研发工程师,关注大数据,分布式存储等方向。
陈昇辉,腾讯内容处理中台后端研发工程师,关注微服务、领域驱动设计等方向。
李瀚,腾讯内容处理中台前端开发负责人,长期关注 React/Node 相关技术方向。
最后,感谢 kyler、richard、gemini 等的大力支持,以及腾讯内容处理中台团队和相关业务团队每一位成员的共同付出。
80 岁 Unix 大神还在修复 AWK 代码;华为全线收缩和关闭边缘业务;小鹏汽车回应苹果汽车前工程师窃密认罪案|Q 资讯