关于美团:广告平台化的探索与实践-美团外卖广告工程实践专题连载

7次阅读

共计 15680 个字符,预计需要花费 40 分钟才能阅读完成。

随着美团外卖业务一直倒退,外卖广告引擎团队在多个畛域进行了工程上的摸索和实际,目前曾经获得了一些成绩。咱们打算通过连载的模式分享给大家,本文是《美团外卖广告工程实际》专题连载的第一篇。本文针对业务提效的指标,介绍了美团外卖广告引擎在平台化过程中的一些思考和实际。

1 前言

美团外卖曾经成为公司最为重要的业务之一,而商业变现又是整个外卖生态重要的组成部分。通过多年的倒退,广告业务笼罩了 Feed 流模式的列表广告,针对 KA 以及大商家的展现广告,依据用户查问 Query 的搜寻广告,以及一些翻新场景的翻新广告等多个产品线,并对应十几个细分的业务场景。

从技术层面而言,一次广告申请的过程,能够分为以下几个次要步骤:广告的触发、召回、精排、创意优选、机制策略等过程。如下图所示:即通过触发失去用户的用意,再通过召回失去广告候选集,通过预估对候选集的店铺打分、排序,再对于 Top 的店铺再进行创意的抉择,最初通过一些机制策略失去广告后果。

2 现状剖析

在业务迭代的过程中,随着新业务场景的一直接入,以及原有业务场景性能的一直迭代,零碎变得越来越简单,业务迭代的需要响应逐步变慢。在业务倒退后期,发展过单个模块的架构重构,如机制策略、召回服务,尽管对于效率晋升有肯定的改善,然而还会存在以下一些问题:

  1. 业务逻辑复用度低 :广告业务逻辑比较复杂,比方机制服务模块,它次要性能是为广告的管制中枢以及广告的出价和排序的机制提供决策,线上反对十几个业务场景,每种场景都存在很多差别,比方会波及多种召回、计费模式、排序计划、出价机制、估算管制等等。此外,还有大量业务自定义的逻辑,因为相干逻辑是算法和业务迭代的重点,因而开发人员较多,并且散布在不同的工程和策略组内,导致业务逻辑形象粒度规范不够对立,使得不同场景不同业务之间复用水平较低。
  2. 学习老本高 :因为代码简单,新同学相熟代码老本较高,上手较难。此外,线上服务很早就进行了微服务革新,线上模块数量超过 20 个,因为历史起因,导致多个不同模块应用的框架差别较大,不同模块之间的开发有肯定的学习老本。在跨模块的我的项目开发中,一位同学很难独立实现,这使得人员效率没有失去充分利用。
  3. PM(产品经理)信息获取难 :因为目前业务场景较多、逻辑简单,对于信息的获取,绝大多数同学很难理解业务的所有逻辑。PM 在产品设计阶段须要确认相干逻辑时,只能让研发同学先查看代码,再进行逻辑的确认,信息获取较难。此外,因为 PM 对相干模块的设计逻辑不分明,往往还须要通过找研发人员线下进行询问,影响单方的工作效率。
  4. QA(测试)评估难 :QA 在性能范畴评估时,齐全依赖于研发同学的技术计划,且大多数也是通过沟通来确认性能改变波及的范畴和边界,在影响效率的同时,还很容易呈现“漏测”的问题。

3 指标

针对以上的问题,咱们从 2020 年初,启动美团外卖广告引擎平台化我的项目,旨在通过平台化的我的项目达成以下指标。

  1. 晋升产研效率

    • 高性能复用度,晋升开发效率。
    • 升高研发人员(RD)、PM、QA 之间的合作老本,晋升产研合作的效率。
  2. 晋升交付品质

    • 准确 QA 测试的范畴,晋升交付的品质。
    • 对业务进行赋能。
  3. PM 可通过可视化的平台化页面,理解其余产品线的能力,相互赋能,助力产品迭代。

4 整体设计

4.1 整体思维

目前,业界曾经有不少“平台化”方向的钻研,比方阿里巴巴的 TMF,定位于泛交易类零碎的平台化畛域领域,次要建设思维是,流程编排与畛域扩大分层,业务包与平台拆散的插件化架构,治理域与运行域拆散。而阿里巴巴的 AIOS 则定位于搜推平台化畛域领域,次要依赖于底层 5 大外围组件,以算子流程图定制的模式对组件疾速组合与部署,从而实现了业务的疾速交付。

美团外卖在平台化我的项目启动时,从业务场景和业务痛点登程,确定了咱们我的项目的外围指标: 利用平台化设计理念构建相适应的技术能力,将现有外卖广告的业务零碎和产研流程转变为平台化模式,疾速反对外卖广告多业务进行交付 。咱们借鉴了行业内平台化的成熟思维,确定了以业务能力标准化为根底、构建平台化框架技术能力为撑持、产研平台化模式降级为保障的平台化建设整体思维,整体思维可分为三局部:业务能力标准化、技术能力框架化、平台化产研新流程。

  • 业务能力标准化 :通过对现有逻辑的梳理,进行标准化的革新,为多业务场景、多模块代码复用提供根底保障。
  • 技术能力框架化 :提供组合编排能力将标准化的逻辑串联起来,通过引擎调度执行,同时实现了可视化能力的透出,帮忙用户疾速获取信息。
  • 平台化产研新流程 :为保障我的项目上线之后实现研发迭代的整体提效,咱们对于研发流程的一些机制也进行了一些优化,次要波及研发人员、PM、QA 三方。

即通过标准化提供复用的保障,通过框架承载平台化落地的能力,通过产研新流程的运行机制保障了整体提效的持续性。整个广告引擎服务波及到的模块都遵循了平台化的思维,撑持上游各个产品场景,如下图所示:

4.2 业务标准化

4.2.1 业务场景与流程剖析

提效是平台化最重要的指标之一,而提效最重要的伎俩是让性能在零碎中失去最大水平上的复用。咱们首先针对外卖广告业务线场景和流量的现状做了对立的剖析,得出以下两点论断:

第一,各业务线大的流程根本相似,都包含预处理、召回、预估、机制策略、排序、创意、后果组装等几个大的步骤;同时,不同业务雷同的步骤里会有很多类似的性能和业务线特有的性能。第二,这些性能实践上都是能够整体进行复用的,但现状是这些性能都集中在业务线外部,不同的业务线之间,不同的小组之间的复用情况也不尽相同。而造成这一问题的次要起因是:

  • 不同业务处在不同的倒退阶段,也有着不同的迭代节奏。
  • 组织构造人造存在“隔离”,如举荐和搜寻业务分在两个不同的业务小组。

因而,妨碍外卖广告进一步晋升复用水平的次要起因,在于整体的标准化水平有余,各业务线间没有对立的规范,所以咱们要先解决标准化建设的问题。

4.2.2 标准化建设

标准化建设的广度和深度决定了零碎复用能力的高下。因而,本次标准化的建设指标要笼罩到所有方面。咱们对广告零碎所有的服务,从业务开发的三个维度,包含实现的性能、性能应用的数据、性能组合的流程登程,来进行对立广告的标准化建设。从而使得:

  • 在个体开发层面 :开发同学不必关注如何流程调度,只需将重心放在新性能的实现上,开发效率变得更高。
  • 从零碎整体角度 :各个服务对于通用的性能不必再反复开发,整体的复用水平更高,节俭了大量的开发工夫。

4.2.2.1 性能的标准化

针对性能的标准化问题,咱们首先根据性能是否跟业务逻辑相干,将其划分为两局部:业务逻辑相干和业务逻辑无关。

① 与业务逻辑无关的性能通过双层形象来对立共建

  • 所有业务线对立共建的标准化模式是进行双层形象。对于单个的、简略的性能点,形象为工具层;对于可独立实现并部署的某一方面性能,比方创意能力,形象为组件层。工具层和组件层对立以 JAR 包的模式对外提供服务,所有工程都通过援用对立的 JAR 包来应用相干的性能,防止反复的建设,如下图所示:

② 与业务逻辑无关的性能,在复用范畴上进行分层复用

  • 业务逻辑相干的性能是此次标准化建设的外围,指标是做到最大水平的业务复用。因而,咱们将最小不可拆分的业务逻辑单元形象为业务同学开发的根本单位,称为 Action。同时依据 Action 不同的复用范畴,将其划分为三层,别离是所有业务能够复用的根底 Action,多业务线复用的模块 Action,具体繁多业务定制的业务 Action,亦即扩大点。所有的 Action 都是从 Base Action 派生进去的,Base Action 里定义了所有 Action 对立的根底能力。
  • 不同的 Action 类型别离由不同类型的开发同学来开发。对于影响范畴比拟大的根底 Action 和模块 Action,由工程经验丰富的同学来开发;对于仅影响单个业务的业务 Action 或扩大点,由工程能力绝对单薄的同学来进行开发。
  • 同时咱们把多个 Action 的组合,形象为 Stage,它是不同 Action 组合造成的业务模块,目标在于屏蔽细节,简化业务逻辑流程图的复杂度,并提供更粗粒度的复用能力。

4.2.2.2 数据的标准化

数据作为实现性能的根本元素,不同业务的数据起源大同小异。如果不对数据进行标准化设计,就无奈实现性能标准化的落地,也无奈实现数据层面的最大化复用。咱们从数据起源和数据应用形式两方面来划分数据:对于业务能力的输出数据、两头数据,输入数据,通过标准化的数据上下文来实现;同时对于第三方内部数据及词表等外部数据,通过对立的容器存储和接口获取。

① 应用上下文 Context 形容 Action 执行的环境依赖

  • 每个 Action 执行都须要肯定的环境依赖,这些依赖包含输出依赖、配置依赖、环境参数、对其余 Action 的执行状态的依赖等。咱们将前三类依赖都形象到业务执行上下文中,通过定义对立的格局和应用形式来束缚 Action 的应用。
  • 思考不同层级 Action 对于数据依赖应用范畴由大到小,遵循雷同的分层设计,咱们设计了三层顺次继承的 Context 容器,并将三类依赖的数据标准化存储到相应的 Context 中。
  • 应用标准化 Context 进行数据传递,劣势在于 Action 可自定义获取输出数据,以及后续扩大的便利性;同时标准化的 Context 也存在肯定的劣势,它无奈从机制上齐全限度 Action 的数据拜访权限,随着后续迭代也可能导致 Context 日渐臃肿。综合思考利弊后,现阶段咱们依然采纳规范的 Context 的模式。

② 第三方内部数据的对立解决

  • 对于第三方的内部数据的应用,须要成熟的工程教训提前评估调用量、负载、性能、批量或拆包等因素,所以针对所有第三方内部数据,咱们对立封装为根底 Action,再由业务依据状况定制化应用。

③ 词表数据的全生命周期治理

  • 词表依据业务规定或策略生成,须要加载到内存中应用的 KV 类数据,标准化之前的词表数据在生成、拉取、加载、内存优化、回滚、降级等能力上有不同水平的缺失。因而,咱们设计了一套基于音讯告诉的词表治理框架,实现了词表的版本治理、定制加载、定时清理、流程监控的全生命周期笼罩,并定义了业务标准化的接入形式。

4.2.2.3 调用流程的标准化

最初,将性能和数据进行组合的是业务的调用流程,对立的流程设计模式是业务性能复用和提效的外围伎俩。流程设计对立的最佳形式就是标准化业务流程。其中对于第三方接口的调用形式,让框架研发的同学用集中封装的形式进行对立。对于接口的调用机会,则基于性能优先并兼顾负载,且在没有反复调用呈现的准则下,进行标准化。

在具体实际中,咱们首先梳理业务逻辑所应用到的标准化性能,而后剖析这些性能之间的依赖关系,最初以性能优先并兼顾负载、无反复调用等准则,实现整个业务逻辑流程的规范设计。

从横向维度看,通过比拟不同业务逻辑流程的相似性,咱们也提炼了肯定的实践经验,以中控模块为例:

  1. 对于用户维度的第三方数据,对立在初始化后进行封装调用。
  2. 对于商家维度的第三方数据,有批量接口应用的数据,在召回后对立封装调用;无批量接口应用的数据,在精排截断后对立封装调用。

4.3 技术框架

4.3.1 整体框架介绍

平台次要有两个局部组成,一部分是平台前台局部,另一部分是平台开发框架包。其中前台局部是一个给研发人员、PM 以及 QA 三种角色应用的 Web 前台,次要性能是跟集成了平台开发框架包的引擎服务进行可视化的交互,咱们也给这个平台起了个名字,叫 Camp 平台,这是大本营的意思,寓意助力业务方攀登业务顶峰。平台开发框架包被引擎后盾服务所集成,提供引擎调度隔离、能力积淀、信息上报等性能,同时还能确保各个模块放弃同样规范的框架和业务能力格调。

各个在线服务都须要引入平台开发框架包,服务性能与平台通用性之间如何均衡也是咱们须要着重思考的中央。这是因为,引入平台框架会对原有的代码细节进行增强性扩大;在 C 端大流量场景下,平台框架做得越通用,底层性能做得越丰盛,与单纯的“裸写”代码相比,会带来一些性能上的折损。因而,在性能开销与平台形象能力上,须要尽量做到一个折中。咱们联合本身业务的个性,给出的平安阈值是 TP999 损失在 5ms 以内,将各个业务通用的能力下沉至框架,提供给下层的在线服务。

综上,整个零碎架构设计如下:

① Camp 平台提供管理控制和展现的性能,该平台由以下几个子模块包组成:

  • 业务可视化包,提供各个后盾零碎上的能力的动态信息,包含名称、性能形容、配置信息等,这些信息在需要评估阶段、业务开发阶段都会被用到。
  • 全图化编排和下发包,业务开发同学通过对已有的能力进行可视化的拖拽,通过全图化服务主动生成并行化最优的执行流程,再依据具体业务场景进行调整,最终生成一个有向无环图,图的节点代表业务能力,边示意业务能力之间的依赖关系。该图会动静下发到对应的后盾服务去供执行框架解析执行。
  • 统计监控包,提供业务能力、词典等运行期间的统计和异样信息,用于查看各个业务能力的性能状况以及异常情况,达到对各个业务能力运行状态可感知的目标。

② 平台开发框架包被广告引擎的多个服务引入,执行编排好的业务流程并对外提供服务,平台框架开发包由以下几个子模块包组成:

  • 外围包,提供两个性能,第一个是调度性能,执行平台下发的流程编排文件,依照定义的 DAG 执行程序和执行条件去顺次或并行执行各个业务能力,并提供必要的隔离和牢靠的性能保障,同时监控运行以及异常情况进行上报。第二个是业务采集和上报性能,扫描和采集零碎内的业务能力,并上报至平台 Web 服务,供业务编排以及业务能力可视化透出应用。
  • 能力包,业务能力的汇合,这里的业务能力在后面章节“4.2.2.1 性能的标准化”中已给出定义,即“将最小不可拆分的业务逻辑单元,形象为业务同学开发的根本单位,称为 Action,也叫能力”。
  • 组件包,即业务组件的汇合,这里的业务组件在章节“4.2.2.1 性能的标准化”中也给出定义,即“对于可独立实现并部署的某一方面性能,比方创意能力,形象为组件”。
  • 工具包,提供业务能力须要的根底性能,例如引擎罕用的词典工具、试验工具以及动静降级等工具。这里的工具在章节“4.2.2.1 性能的标准化”中同样给出了定义,即单个的、简略的非业务功能模块形象为工具。

一个典型的开发流程如上图所示,开发人员开发完业务能力后(1),业务能力的动态信息会被采集到 Camp 平台(2),同时,通过全图化依赖推导失去最优 DAG 图(3),业务同学再依据理论业务状况对 DAG 图进行调整,引擎在线服务运行期间会失去最新的 DAG 流程并对外提供最新的业务流程服务(4,5),同时会把业务运行的动静信息上报至 Camp 平台(6)。

在上面的章节中,咱们将对几个比拟要害的技术点进行详细描述,其中就包含了可视化相干的组件主动上报和 DAG 执行相干的全图化编排、执行调度等,最初,本文还会介绍一下跟广告业务强相干的、词典在平台化中对立封装的工作。

4.3.2 业务采集 & 上报

为了方便管理和查问已有业务能力,平台开发框架包会在编译时扫描 @LppAbility 注解和 @LppExtension 注解来上报元数据到 Camp 平台。业务同学能够在 Camp 平台中对已有组件进行查问和可视化的拖拽。

// 原子能力(Action)@LppAbility(name = "POI、Plan、Unit 数据聚合平铺能力", desc = "做估算过滤之前,须要把对象打平",
        param = "AdFlatAction.Param", response = "List<KvPoiInfoWrapper>", prd = "无产品需要", func = "POI、Plan、Unit 数据聚合平铺能力", cost = 1)
public abstract class AdFlatAction extends AbstractNotForceExecuteBaseAction {

}
// 扩大点
@LppExtension(name = "数据聚合平铺扩大点",
        func = "POI、Plan、Unit 数据聚合平铺", diff = "默认的扩大点,各业务线间接无差别", prd = "无", cost = 3)
public class FlatAction extends AdFlatAction {
@Override
    protected Object process(AdFlatAction.Param param) {
    //do something
      return new Object();}
}

4.3.3 全图化编排

在广告投放引擎服务中,每个业务的 DAG 图,动辄便会有几十甚至上百的 Action,通过传统的人工编排或业务驱动编排,很难做到 Action 编排的最优并行化。因而,平台化框架包采纳数据驱动的思维,通过 Action 之间的数据依赖关系,由程序主动推导出并行化最优的 DAG 图,即全图化编排,尔后再由业务人员依据业务场景和流量场景进行定制化调整,动静下发到服务节点,交由调度引擎执行,这样通过主动推导 + 场景调优的形式便达到了场景下的最优并行。

① 全图化主动编排的基本原理

咱们定义某个 Action x 的入参汇合为该 Action x 执行时应用的字段,示意如下:

$input_x(A,B,C……N)$

定义某个 Action y 的出参汇合为该 Action 执行后产出的字段,示意如下:

$output_y(A,B,C……M)$

当存在任意以下两种状况之一时,咱们会认为 Action x 依赖于 Action y。

  • input_x ∩ output_y ≠ ∅,即 Action x 的某个 / 某些入参是由 Action y 产出。
  • output_x ∩ output_y ≠ ∅,即 Action x 与 Action y 操作雷同字段。

② 全图化主动编排总设计

全图化主动编排总体分为两个模块:解析模块、依赖剖析模块。

  • 解析模块 :通过对字节码剖析,解析出每个 Action 的 input、output 汇合。

    • 字节码剖析应用了开源工具 ASM,通过模仿 Java 运行时栈,保护 Java 运行时局部变量表,解析出每个 Action 执行依赖的字段和产出的字段。
  • 依赖剖析模块 :采纳三色标记的逆向解析法,剖析出 Action 之间的依赖关系,并对生成的图进行剪枝操作。

    • 依赖剪枝:生成图会有反复依赖的状况,为了缩小图复杂度,在不扭转图语义的前提下,对图进行了依赖剪枝。例如:

③ 全图化主动编排收益成果

主动纠正人工谬误编排,并最大化编排并行度。某理论业务场景中,全图化前后的 DAG 比照,如下图所示:

标记蓝色的两个 Action,会同时操作同一个 Map,如果并发执行会有线程平安危险。因为办法调用栈过深,业务开发同学很难关注到该问题,导致谬误的并行化编排。通过全图化剖析后,编排为串行执行。

标记绿色、红色、黄色的三组 Action,每组内的两个 Action 并没有数据依赖关系,业务开发同学串行化编排。通过全图化剖析后,编排为并行。

4.3.4 调度引擎

调度引擎的外围性能是对上述下发后的 DAG 进行调度。因而引擎须要具备以下两个性能:

  • 构图 :依据 Action 的编排配置生成具体的 DAG 模板图。
  • 调度 :流量申请时,依照正确的依赖关系执行 Action。

整个调度引擎的工作原理如下图:

出于对性能的思考,调度引擎摒弃了流量申请实时构图的办法,而是采纳“动态构图 + 动静调度”的形式。

  • 动态构图 :在服务启动时,调度引擎依据下发的 DAG 编排配置,初始化为 Graph 模板并加载至内存。服务启动后,多个 DAG 的模板会长久化到内存中。当 Web 平台进行图的动静下发后,引擎会对最新的图进行构图并齐全热替换。
  • 动静调度 :当流量申请时,业务方指定对应的 DAG,连同上下文信息对立交至调度引擎;引擎依照 Graph 模板执行,实现图及节点的调度,并记录下整个调度的过程。

因为广告投放引擎服务于 C 端用户,对服务的性能、可用性、扩展性要求很高。调度引擎的设计难点也落在了这三个方面,接下来咱们将进行简要的论述。

4.3.4.1 高性能实际

流程引擎服务于 C 端服务,与传统的硬编码调度相比,引擎的调度性能要至多能持平或在一个可承受的性能损失阈值内。上面,咱们将从调度器设计、调度线程调优这两个有代表性的方面介绍下咱们的性能实际。

① 调度器设计

含意 :如何让节点一个一个的执行;一个节点执行实现,如何让其余节点感知并开始执行。如下图中,A 节点在执行实现后,如何告诉 B,C 节点并执行。常见的思路是,节点的分层调度,它的含意及特点如下:

  • 依赖分层算法(如广度优先遍历)提前计算好每一层须要执行的节点;节点一批一批的调度,无需任何告诉和驱动机制。
  • 在同批次多节点时,因为各节点执行工夫不同,容易呈现长板效应。
  • 在多串行节点的图调度时,有较好的性能劣势。

另一种常见的思路是,基于流水线思维的队列告诉驱动模式:

  • 某节点执行实现后,立刻发送信号给音讯队列;生产侧在收到信号后,执行后续节点。如上图 DAG 中,B 执行实现后,D/ E 收到告诉开始执行,不须要关怀 C 的状态。
  • 因为不关怀兄弟节点的执行状态,不会呈现分层调度的长板效应。
  • 在多并行节点的图调度时,有十分好的并行性能;但在多串行节点的图中,因为额定存在线程切换和队列告诉开销,性能会稍差。

如上图所示,调度引擎目前反对这两种调度模型。针对多串行节点的图举荐应用分层调度器,针对多并行节点的图举荐应用队列流水线调度器。

分层调度器

依赖于下面提到的分层算法,节点分批执行,串行节点单线程执行,并行节点池化执行。

队列流水线调度器

无论是外层的图工作(GraphTask)还是外部节点工作(NodeTask)均采纳池化的形式执行。

  • 节点调度机制

    • 调度机制:生产侧收到音讯到节点被执行,这两头的过程。如下 DAG 中,节点在接管到音讯后需顺次实现:测验 DAG 执行状态、校验父节点状态、测验节点执行条件、批改执行状态、节点执行这几个过程,如下图所示:

  • 这几个步骤的执行,通常存在两种形式:一种是集中式调度,由对立的办法进行解决;另一种是扩散式调度,由每个后续节点单独来实现。
  • 咱们采纳的为集中式调度:某节点执行实现后,发送音讯到队列;生产侧存在工作散发器对立负责生产,再进行工作散发。

这样做的出发点是:

  • 如上图中,ABC 三个节点同时实现,到 D 节点真正执行前仍有一系列操作,这个过程中如果不加锁管制,D 节点会呈现执行三次的状况;因而,须要加锁来保障线程平安。而集中式工作散发器,采纳无锁化队列设计,在保障线程平安的同时尽量躲避加锁带来的性能开销。
  • 再如一父多子的状况,一些公共的操作(校验图 / 父节点状态、异样检测等),各子节点都会执行一次,会带来不必要的零碎开销。而集中式工作散发器,对公共操作对立进行解决,再对子节点工作进行散发。
  • 扩散式调度中,节点的职责范畴过广,既须要执行业务外围代码,还须要额定解决音讯的生产,职责非繁多,可维护性较差。

因而,在我的项目理论开发中,思考到实现的难度、可维护性、以及综合考量性能等因素,最终采纳集中式调度。

② 调度线程调优

调度引擎在 DAG 执行上,提供了两种 API 给调用方,别离为:

  • 异步调用 :GraphTask 由线程池来执行,并将最外层 GraphTask 的 Future 返回给业务方,业务方能够精准的管制 DAG 的最大执行工夫。目前,外卖广告中存在同一个申请中解决不同广告业务的场景,业务方能够依据异步接口自由组合子图的调度。
  • 同步调用 :与异步调用最大的不同是,同步调用会在图执行实现 / 图执行超时后,才会返回给调用方。

而底层调度器,目前提供上述讲到两种调度器。具体如下图所示:

由此看出,调度引擎在外部工作执行上,屡次用到了线程池。在 CPU 密集型的服务上,申请量过大或节点过多的话,大量线程切换势必会影响到服务的整体性能。针对队列告诉调度器,咱们做了一些调度优化,尽量将性能拉回到没有接入调度引擎之前。

  • 调度线程模型调优

    • 针对同步调用的状况,因为主线程不会间接返回,而是在期待 DAG 图执行实现。调度引擎利用这一特点,让主线程来执行最外层的 GraphTask,在解决每个申请时,会缩小一次线程的切换。
  • 串行节点执行优化

    • 如下面 DAG 图中,存在一些串行节点(如单向 A→B→C→D),在执行这 4 个串行节点时,调度引擎则不会进行线程的切换,而是由一个线程顺次实现工作执行。
    • 在执行串行节点时,调度引擎同样不再进行队列告诉,而是采纳串行调度的形式执行,最大化缩小零碎开销。

4.3.4.2 高可用实际

在高可用上,咱们从隔离和监控上简要介绍下咱们的实际,它的外围原理如下图所示:

① 业务隔离

广告场景中,同一服务中常常会存在多条子业务线,每条业务线的逻辑对应一张 DAG。对于同一服务内各个业务线的隔离,咱们采纳的是“ 单实例 - 多租户 ”的计划。这是因为:

  • 流程引擎沉闷在同一个过程内,单实例计划治理起来要更容易。
  • 流程引擎外部实现过程中,针对图的粒度上做了一些多租户隔离工作,所以在对外提供上更偏向于单实例计划。

除 DAG 调度和 Node 调度为动态代码外,图的存储、DAG 的选取与执行、Node 节点的选取与执行、各 DAG 的节点告诉队列都采纳多租户隔离的思维。

② 调度工作隔离

调度工作次要分为:DAG 工作(GraphTask)、节点工作(NodeTask)两类。其中一个 GraphTask 对应多个 NodeTask,并且其执行状态依赖所有的 NodeTask。调度引擎在执行时,采纳二级线程池隔离的形式将 GraphTask 和 NodeTask 的执行进行隔离。

这样隔离的出发点是:

  • 每个线程池职责繁多,执行工作更加繁多,相应的过程监控与动静调整也更加不便。
  • 如果共用一个线程池,如果呈现刹时 QPS 猛增,会导致线程池全被 GraphTask 占据,无奈提交 NodeTask 最终导致调度引擎死锁。

因而,无论是线程精细化治理还是隔离性上,两级线程池调度的形式都要优于一级线程池调度。

③ 过程监控

对 DAG 调度的监控,咱们将其分成三类。别离为异样、超时、统计,具体如下:

  • 异样:图 / 节点执行异样,反对配置重试、自定义异样解决。
  • 超时:图 / 节点执行超时,反对降级。
  • 统计:图 / 节点执行次数 & 耗时,提供优化数据报表。

4.3.4.3 高可用实际

广告业务逻辑简单,在投放链路上存在大量的试验、分支判断、条件执行等。并且广告投放服务的迭代频率和发版频率也十分高。因而,调度引擎在可扩大上首先要思考的是如何调度条件节点,以及编排配置如何在无公布下疾速失效这两个问题。

① 节点条件执行

对于节点的条件执行,咱们在配置 DAG 时,须要显示的减少 Condition 表达式。调度引擎在执行节点前,会动静计算表达式的值,只有满足执行条件,才会执行该节点。

② 配置动静下发

  • 如前图所示,咱们将构图与调度通过两头态 Graph 模板进行解耦,编排配置能够通过 Web 平台编辑后,动静下发到服务上。
  • 因为调度引擎在调度过程中,屡次用到了线程池,对于线程池的动静更新,咱们借助了公司的通用组件对线程池进行动态化配置和监控。

4.3.4.4 调度引擎总结

① 性能方面

DAG 外围调度

  • 调度引擎提供两种常见调度器的实现,针对不同的业务场景,能较好的提供反对。
  • 调度引擎采纳经典的两级调度模型,DAG 图 / 节点任务调度更具备隔离性和可控性。

节点条件执行

  • 对于节点的调度前置减少条件校验性能,不满足条件的节点不会执行,调度引擎会依据上下文以及流量状况动静判断节点的执行条件。

超时解决

  • 对 DAG、Stage、Node 节点均反对超时解决,简化外部各个业务逻辑的超时管制,将主动权交给框架对立进行解决。在保障性能的前提之下,进步外部逻辑的解决效率。

节点可配置化

  • 同一个 Node 节点,会被对个业务场景应用,但各业务场景的其解决逻辑且不近雷同。针对这种状况,减少节点的配置化性能,框架将节点的配置传入逻辑外部,实现可配置。

② 性能方面

  • 在多串行节点的 DAG 场景下,性能根本能够持平原有的裸写形式。
  • 在多并行节点的 DAG 场景下,因为池化的影响,在多线程池抢占和切换上,存在一些性能折损;再进行屡次调优和 CPU 热点治理上,TP999 折损值能够管制到 5ms 以内。

4.3.5 业务组件层积淀

如“4.2.2.1 性能的标准化”中给出的定义,可独立实现并部署的业务功能模块形象为业务组件。从业务逻辑中提取高内聚、低耦合的业务组件,是晋升代码复用能力的重要伎俩。在实践中,咱们发现不同业务组件蕴含的逻辑千差万别,具体实现形式和设计与代码格调也参差不齐。因而,为了对立业务组件的设计思路和实现形式,咱们实现了一套标准化的组件框架,以缩小新组件开发的重复性工作,并升高应用方的学习和接入老本。

上图右边展现了业务组件的整体框架,底层为对立的公共域和公共依赖,下层为业务组件规范的实现流程,切面能力则实现对业务逻辑的反对。左边为基于框架开发的智能出价组件示例。框架的作用是:

① 对立的公共域和依赖治理

  • 公共域是指在不同的业务组件中都会应用到的业务实体。咱们将业务上的专用域对象提取进去,作为根底组件提供给其余业务组件应用,以缩小域对象在不同组件反复定义。
  • 业务组件都有很多外部和内部的依赖。咱们对公共依赖进行了对立的梳理和筛选,同时衡量各方面因素,确定了正当的应用形式。最终造成一套残缺成熟的依赖框架。

② 对立的接口和流程

  • 咱们将业务组件形象为三个阶段:数据和环境筹备阶段 Prepare、理论计算阶段 Process 和后置解决阶段 Post。每个阶段都设计了形象的泛型模板接口,最初通过不同的接口组合实现组件中的不同业务流程。所有类在接口设计上都提供了同步和异步两种调用形式。

③ 对立的切面能力

  • 目前所有的服务模块均采纳 Spring 作为开发框架,咱们利用其 AOP 性能开发了一系列的切面扩大能力,包含日志采集、耗时监控、降级限流、数据缓存等性能。这些性能均采纳无侵入式代码设计,缩小切面能力与业务逻辑的耦合。新的业务组件通过配置的形式即可齐全复用。

智能出价组件即为基于以上框架开发的业务组件。智能出价组件是对广告出价策略的形象聚合,包含 PID、CEM 等多个算法。出价策略依赖的用户特色获取、试验信息解析等数据对立采纳 Prepare 模板实现;具体 PID、CEM 算法的施行对立采纳 Process 模板实现;对出价后果的校验、参数监控等后置操作则对立采纳 Post 模板实现。整个组件所应用的专用域对象和第三方依赖也对立托管于框架进行治理。

4.3.6 工具包 - 词典治理

在“4.2.2.1 性能的标准化”中也定义了工具包的含意,即单个的、简略的非业务功能模块形象为工具。工具包的建设是广告平台化工作提效的重要根底,其次要的作用是解决业务逻辑无关的辅助类通用流程或性能。例如:广告零碎中存在大量的 KV 类数据须要加载到内存中应用,咱们称之为词表文件。为了实现词表文件的全生命周期治理,广告平台化进行了词表管理工具的设计与开发,并在业务应用过程中积攒了很好的实际成果。

① 词表治理的设计

上图是词表治理平台的整体架构,词表治理平台整体采纳分层设计,自上而下别离五层:

  • 存储层 :次要用于数据的存储和流转。其中美团外部的 S3 实现在云端的词表文件存储,Zookeeper 次要用于存储词表的版本信息,在线服务通过监听的形式获取最新的版本更新事件。
  • 组件层 :每个组件能够视为独立的性能单元,为下层提供通用的接口。
  • 插件层 :业务插件的作用次要是提供对立的插件定义和灵便的自定义实现。例如:加载器主要用途为提供对立格局的词表加载和存储性能,每个词表能够动静配置其加载器类型。
  • 模块层 :模块层次要是从业务角度看整体词表文件不同流程的某一环节,模块之间通过事件告诉机制实现交互。例如:词表治理类模块蕴含词表版本治理、事件监听、词表注册、词表加 / 卸载、词表拜访等。
  • 流程层 :咱们将一个残缺词表业务行为过程定义为流程。词表的整个生命周期能够分为新增词表流程、更新词表流程、登记词表流程、回滚词表流程等。

② 词表治理的业务收益

平台化词典管理工具在业务实际中具备的次要劣势为:

  • 更灵便的服务架构 :词表流程的透明化。应用方无需关注词表流转过程,采纳对立 API 拜访。
  • 对立的业务能力 :对立的版本管理机制,对立的存储框架,对立的词表格局和加载器。
  • 零碎高可用 :疾速复原和降级能力,资源和工作隔离、多优先级解决能力等多重零碎保障性能。

4.4 产研新流程

上文中提到,因为广告业务线较多,且波及诸多上下游,工程与策略通过几年疾速迭代之后,现有业务逻辑已极为简单,导致在日常迭代中,一些流程性问题也逐渐凸显。

① PM 信息获取艰难

PM 在进行产品调研与设计时,对波及的相干模块以后逻辑不是很分明,往往通过线下征询研发人员的形式来解决,影响单方的效率,同时产品设计文档中纯以业务视角和流程来论述,导致每次评审时,QA 和研发人员很难直观获取到改变点和改变范畴,两头又会破费大量工夫来互相沟通,从而确认边界与现有逻辑的兼容性等问题。

② 研发人员的性能评估齐全依赖教训

研发人员在方案设计时,很难间接获取到横向相干模块是否有相似性能点(可复用或可扩大),导致复用率低,同时在我的项目排期时齐全依赖集体教训,且没有对立的参考规范,经常出现因工作量评估不准而导致我的项目延期的状况。

③ QA 测试及评估效率低

QA 在性能范畴评估时,齐全依赖研发同学(RD)的技术计划,且大多数也是通过口头交换的形式来确认性能改变波及的范畴和边界,在影响效率的同时,还会导致一些测试问题在整个我的项目周期中被后置,影响我的项目的进度。同时,平台化后根底 JAR 包的治理齐全依附人工,对一些 Action,尤其是根底 Action 也没有对立的测试规范。以上问题能够概括如下:

4.4.1 指标

借助平台化,对我的项目交付的整个过程(如下图所示),施行产研新流程,以解决产品、研发与测试人员在迭代中遇到的问题,赋能业务,从而晋升整体我的项目的交付效率与交付品质。

4.4.2 思考与落地

基于平台化施行产研新流程,即利用 Stage/Action 的形式来驱动整个我的项目的交付,如下图所示:

  • 对于 PM(产品):建设 Stage/Action 可视化能力,并在我的项目设计中利用。
  • 对于 RD(研发):对立采纳新的基于 Stage/Action 的计划,设计及开发排期模式。
  • 对于 QA(测试):对立沟通合作语言 -Stage/Action,并推动改良相干测试方法和测试工具

4.4.2.1 产品侧

下图所示的是产研性能建设后的利用与实际成果。前两张为建设的业务能力可视化,为 PM 提供一个理解各业务最新流程及具体 Action 能力的可视化性能,第三张图为产品设计中相干业务的调研与性能形容(出于数据安全起因,以下截图采纳非实在我的项目举例说明)。

4.4.2.2 研发侧

依据我的项目开发周期中研发工作的不同阶段,咱们制订了基于代码开发前后的流程标准,以保障整个开发周期中研发同学能充分利用平台的能力进行设计与开发提效。

  • 开发前

    • 技术设计:基于各业务波及的现有 Action 性能与 Action DAG 的可视化能力,进行横向业务的调研参考与复用评估,以及新增或变更 Action 性能的技术设计。
    • 我的项目排期:基于技术设计中 Action 能力的新增、变更、复用状况以及 Action 层级等,对开发工作量进行较为标准化的评估。
  • 开发后

    • Action 积淀:零碎对立上报并定期评估平台 Action 能力的复用度和扩大状况。
    • 流程反馈:追踪基于平台化的每个我的项目,并对交付流程中的相干指标做量化上报,同时收集我的项目人员反馈。

4.4.2.3 测试侧

  1. 采纳 Stage/Action 对立沟通合作语言 :在需要设计与评审、方案设计与评审、测试用例编写与评审等多方参加的我的项目环节,对立采纳 Stage/Action 为性能形容与设计的沟通语言,以便将后续流程中问题的发现尽可能前置,同时各参与方更加明确变更及测试内容,为 QA 更好的评估测试范畴提供撑持,进而更好的保障我的项目测试品质。
  2. 推动根底 Aaction UT 全笼罩 :针对根底 Action,构建单元测试,在 Merge 代码时主动触发单元测试流水线,输入执行单测的成功率和覆盖率,并评定指标基线,保障可继续测试的效率与品质。
  3. 改良 JAR 治理工具化与自动化剖析及测试:一级 Action 都集中写在平台 JAR 包中,对相似这种公共 JAR 包的治理,开发专属的治理与保护工具,解决降级公共 JAR 自动化单测笼罩问题以及每次降级 JAR 版本须要人工剖析人工保护的测试效率问题,买通集成测试自动化的全流程。

5 成果

① 产研效率的晋升

  • 零碎能力积淀

    • 外卖广告所有业务线曾经实现平台化架构降级,并在此架构上继续的运行和迭代。
    • 业务根底能力积淀 50+ 个,模块共用能力积淀 140+ 个,产品线共用能力积淀 500+ 个。
  • 人效的晋升

    • 研发效率晋升:在各业务线平台化架构迁徙后,大的业务迭代 20+ 次,业务迭代效率晋升相比之前总计晋升 28+%。特地是在新业务的接入上,雷同性能无需反复开发,提效成果更加显著:

      • 能力累计复用 500+ 次,能力复用比 52+%;
      • 在新业务接入场景中,Action 复用 65+%。
    • 测试的自动化指标晋升:借助于 JAR 自动化剖析、集成测试及流程笼罩建设,广告自动化测试覆盖率晋升了 15%,测试提效累计晋升 28%,自动化综合得分也有了显著晋升。

② 晋升交付品质及赋能产品

  • 基于 Action 的变更以及清晰的可视化业务链路,可能帮忙 QA 更精确的评估影响范畴,其中过程问题数量及线上问题数量均呈降落趋势,降落比例约为 10%。
  • 通过零碎能力的可视化透出页面,减少零碎的透明度,在产品调研阶段无效帮忙产品理解零碎已有的能力,缩小了业务征询、跨产品线常识壁垒等问题(详情可参见 4.4.2.1)。

6 总结与瞻望

本文别离从标准化、框架、产研新流程 3 个方面介绍了外卖广告平台化在建设与实际中的思考与落地计划。通过两年的摸索建设和实际,美团外卖广告平台化曾经初具规模、无力地撑持了多条业务线的疾速迭代。

将来,平台化会细化标准化的力度,升高业务开发同学老本;深入框架能力,在稳定性、性能、易用性方面继续进行晋升。此外,咱们在产研新流程方向也会继续优化用户体验,欠缺经营机制,一直晋升产研迭代的流程。

以上就是外卖广告针对业务平台化上的一些摸索和实际,在广告工程架构等其余畛域的摸索,敬请期待下一篇系列文章。

7 作者简介

乐彬、国梁、玉龙、吴亮、磊兴、王焜、刘研、思远等,均来自美团外卖广告技术团队。

招聘信息

美团外卖广告技术团队大量岗位继续招聘中,诚招广告后盾 / 算法开发工程师及专家,坐标北京。欢送感兴趣的同学退出咱们。可投简历至:yangguoliang@meituan.com(邮件主题请注明:美团外卖广告技术团队)

浏览美团技术团队更多技术文章合集

前端 | 算法 | 后端 | 数据 | 平安 | 运维 | iOS | Android | 测试

| 在公众号菜单栏对话框回复【2021 年货】、【2020 年货】、【2019 年货】、【2018 年货】、【2017 年货】等关键词,可查看美团技术团队历年技术文章合集。

| 本文系美团技术团队出品,著作权归属美团。欢送出于分享和交换等非商业目标转载或应用本文内容,敬请注明“内容转载自美团技术团队”。本文未经许可,不得进行商业性转载或者应用。任何商用行为,请发送邮件至 tech@meituan.com 申请受权。

正文完
 0