打造算法在线服务领域极致开发体验与性能 — 阿里TPP图化框架技术实践 - 阿里技术

( 本文阅读时间:15分钟 )

TPP图化致力于打造一个算法在线服务领域易用、性能极致、迭代效率远超普通方式的产品。本文将介绍TPP图化以及2021年在性能、开发体验上的改进,并介绍未来TPP图化的规划。

01

背景

TPP是阿里个性化算法开发平台,依托阿里AI·OS引擎(特征、召回、打分等引擎)为众多的个性化业务(搜索、推荐、广告等)提供Serverless化的在线服务能力。用户在TPP平台上编写业务代码,做AB实验并对外提供服务,而无需关心机器资源、应用部署结构,不需编写服务框架。在TPP产品页面可管理业务代码的全生命周期,包括编译,调试、发布上线、监控报警、问题排查。结合AI·OS引擎套件接口和高性能图化开发框架,用户只需要实现自己的业务逻辑,即可拥有稳定、高性能的个性化在线服务。

TPP的主要用户是搜推广业务的算法同学,以推荐你喜欢的商品为例,来看服务的上线过程:算法同学训练好模型并部署到在线召回引擎、打分引擎,把用户和商品特征数据导入到特征存储,然后就需要让这套数据和模型在线对外提供服务。此时算法同学可以在TPP上创建这个业务场景,并用Java编写业务逻辑。常见的猜你喜欢推荐逻辑是:构建特征(调特征数据库) -> 召回商品(调召回引擎) -> 商品打分(调打分引擎) -> 商品排序 -> 补充商品详情(调详情数据库) -> 输出结果,可见TPP上的业务逻辑像胶水一样把各类引擎的数据和模型预测结果粘合起来,经过业务加工产出推荐结果。算法同学基于TPP图化框架实现引擎调用、数据加工,完成业务逻辑开发,在TPP平台上编译并调试,调试无误后发布上线,这时上游系统就可以调用这套推荐服务了。TPP平台在背后完成了容器的部署和拉起、服务的热部署、随着流量波动做机器资源的弹性扩缩。除了基础的在线服务能力外,算法同学可以对流量做分配、打标以完成不同配置的实验;可以利用TPP提供的监控报警、问题排查产品解决线上问题;可以利用TPP提供的分层降级、集群限流、流量兜底等能力保证服务稳定运行。TPP提供的算法业务快速迭代能力,稳定、高性能的服务能力,得到了阿里众多算法团队的认可,2021年TPP已经通过阿里云正式发布商业化版本,希望能把这套最佳实践推荐给更多算法团队。

在线服务的请求由用户动作触发,在线服务链路总响应时间一般在几百毫秒,留给链路中一个环节的时间一般不超过300毫秒,然而个性化算法链路有着大量数据读取、数据加工过程,是重CPU和重IO类型的服务。同时在线服务的性能与个性化算法效果相互制约,这体现在个性化算法效果越好就对数据的丰富度、模型复杂度要求越高,从而提高服务响应时长造成超时率增加,超时后的请求一般使用效果平平的兜底数据,从而制约总体算法效果。为此,TPP平台围绕算法在线服务的性能做了多方面工作,其中如何加速业务逻辑执行和业务数据加工是重要的一方面。

在构建特征 -> 召回商品 -> 商品打分 -> 商品排序 -> 补充商品详情 -> 输出结果流程中,需要调多次特征数据库,因为需要丰富的用户和商品特征,需要调多次召回引擎,因为需要多种类型的召回来源,显然,并发的去请求这些数据能显著缩短总处理耗时,然而算法同学并不专长于写并发代码,容易写出BUG或写的性能不高。另一方面,召回后的商品信息是以itemId为主键的多行多列数据,在送往打分、排序等后续流程中,需要根据业务需求做多次加工,例如数据合并、算分、排序、截断、去重等等,这些加工操作代码复杂,容易出错,且会产生大量内存碎片影响性能。基于上述并发需求和数据加工需求,我们推出了TPP图化框架和TPP DataFrame高性能数据集,目标是在提供极致开发体验的前提下,提供极致的性能。

TPP图化框架从19年开始研发,最初定位于利用可执行图结构解决并发性能问题,在图框架内提供数据集操作算子以优化数据加工性能,同时框架抽象层次得以提高从而获得更多优化空间。用户可以用stream api风格的接口构建业务执行图,这是一张数据流图,每个节点是一段业务逻辑,数据从上游节点流转到下游节点,在每个节点被加工处理,相互没有依赖的节点就可以并发执行。图引擎是一个全异步响应式执行引擎,同时对AI·OS引擎的接口均做了异步化改造,从而实现全异步、无阻塞、高并发的业务执行过程。当时改造为图化的业务普遍得到了20%~30%的性能提升。

在图化的推广中我们发现,数据流加工思路与用户熟悉的Java面向对象思路差异较大,学习成本高、调试困难、配套产品不完善,许多同学望而生退。为此TPP图化一方面推出依赖声明式构图、面向对象风格开发方式来降低学习成本,另一方面利用图可编排,有结构化信息的特点,推出了子图组件+在线编排开发方式和图执行过程可视化产品,同时跟一线的算法工程团队合作产出以TPP图化为基础的业务框架和产品,这些业务框架和产品更贴近自己的业务,同时也能利用图化的性能优势和图化公共产品。经过近三年的发展,TPP图化收获了诸多不同业务类型的用户,其中阿里云Saas智能推荐产品Airec就是基于TPP图化框架,Airec有效利用了图编排能力和性能优势帮助用户快速搭建高性能推荐服务。在阿里内部,TPP图化已经被几十个BU所使用,TPP图化日常承载了百万级的QPS,帮助业务普遍提升了30%的性能。

在当前的时间点上,TPP图化仍聚焦在优化性能和提升开发体验上,希望最终能把TPP图化打造成算法在线服务领域易用、性能极致、迭代效率远超普通方式的产品。
本文首先介绍TPP图化的内容,然后介绍在2021年在性能、开发体验上的改进,并介绍未来TPP图化的规划。

02

TPP图化概览

TPP图化包含两大部分:图化框架和TPP DataFrame高性能数据集。图化框架的内核是全异步图引擎,图引擎的运行方式与rxjava、reactor等响应式执行引擎相似,均是事件触发、非阻塞、全异步的。全异步引擎之上提供了一种依赖声明的构图方式,同时提供单步调试、图执行过程可视化、图化全链路trace、timeline并发性能分析、节点级监控等相关产品。TPP DataFrame是二维表格数据的高性能数据结构,内部数据结构已对接到搜索引擎、召回引擎、在线预测引擎等,并提供一套高性能数据操作接口(join、concat、groupby、filter、sort等)。图化框架和TPP DataFrame分别对业务逻辑执行过程和数据加工过程做加速,加速带来服务RT降低和吞吐量提升,意味着用户可以上更复杂的模型、加更多路的召回,同时节省更多的机器资源。

2.1 TPP图化

✪ 2.1.1 TPP图化的组成

下图展示了TPP图化框架的组成部分,包括图化框架和图化产品两大部分。图化框架运行于TPP容器内,借助AJDK Wisp2协程降低并发成本,提高并发性能。TPP容器还封装了AI·OS系列引擎的全异步接口以对接图化框架,并使用flatbuffers数据结构以对接TPP DataFrame。

图化框架部分分为执行层、算子层、语法层、适配层四部分,其中语法层支持依赖声明构图语法(新)和stream api构图语法(旧)两种,负责把用户描述的图结构翻译为由一系列算子组成的可执行图。算子层提供map、zip等基础算子,并提供AI·OS引擎的业务算子,算子内是具体可执行的代码逻辑。执行层的图执行优化器负责把语法层生成的图结构进行转换,例如节点合并、重排序,以得到更高执行效率的图结构。全异步执行引擎负责最终的图结构。子图管理模块负责创建和管理子图。控制流管理模块负责图上控制流的执行。

图化产品部分包含了开发调试类产品,监控报警类产品,跟踪排查类产品,组件化编排类产品四部分。其中开发调试类产品包含单步调试、实时查看图结构、图执行过程可视化,部分产品是IDE插件的形式。监控报警类产品可提供节点粒度的监控和报警。跟踪排查类产品额外提供了节点粒度执行情况、节点输入输出详情。组件化编排产品仍在规划中,目标是做图组件沉淀和共享,并支持可视化托拉拽方式做图编排。

✪ 2.1.2 图化的开发方式

图化框架里用户把业务逻辑描述为一张图,图中每个节点是一段业务逻辑,节点的输入和输出用注解或配置方式声明,这些节点执行后,其产生的输出数据可以被下游节点使用。

图化框架里节点业务逻辑的开发方式跟传统Java面向对象一样,唯一多出的是需要明确输入输出。以下面三个节点的图为例:

  1. RequestConfigModule这个类对应requestConfig节点,reqConf字段是它处理完业务逻辑后的一项输出数据。
  2. BeMatchModule的requestConfig字段(注意上面的注解)引用了RequestConfigModule的输出数据,并在执行完业务逻辑后产出了recallData作为它自己的输出数据。
  3. BizProcessModule也以同样的方式引用了上游两个节点的输出数据。

这三个类在声明了自己的输入输出的依赖关系后,图化框架可以据此构出右侧的图,这张图被图化框架解析后可以并发、高效率的执行。由此可以看到,TPP图化在开发方式上约等于Java面向对象+数据依赖声明。

✪ 2.1.3 图化在线编排

用图结构描述业务逻辑的另一好处是便于编排,因此除了注解方式构图外,图化框架还支持JSON配置和注解混合构图。JSON配置可以在线修改,在线生效。常见的是一套代码,用多套实验配置编排出不同的图,可用于不同的业务,或者做多个实验。图化在线编排加快了研发迭代效率,有助于业务组件的沉淀,也提高了构图的灵活性。

✪ 2.1.4 图化产品和工具

用图结构描述业务能将其白盒化,极大提高了业务执行过程的可观测性。图化产品充分利用了图结构信息,图执行可视化工具绘出了详细的图执行过程,让图化代码易于调试,也便于用户理解整体业务逻辑。图化监控拥有节点级的RT、RT P99、超时率、异常率,业务出现问题时能快速定位到节点。图化线上跟踪排查工具能记录节点的输入输出数据、异常栈、耗时等信息,是排查难复现问题的利器。图化性能分析可以看到节点级并发关系和耗时情况,易于发现影响耗时的瓶颈节点。

下图是图执行过程可视化产品,可以直观的看到图执行过程。

下图是图化监控,可以看到耗时、异常等指标细化到了节点粒度。

下图是TPP全链路追踪和排查工具的图化版本,可以看到回溯一个线上请求的现场时,可以看到节点级的耗时情况、节点的输入输出数据。

下图是图化性能分析工具,可以看到节点并发执行情况:

2.2 TPP DataFrame

在搜推广算法常见的特征->召回->打分->排序流程中,二维表结构的数据和对其的操作贯穿整个流程。常见的数据是约1000个商品信息,商品信息里有几十个字段,需要对这样的列表做补充信息、算分、排序、去重、跟其他数据合并等操作。经过多次业务迭代后,代码里充满了数据操作和业务逻辑的混合体,逻辑复杂且含义不清,修改时容易出错,运行时容易产生大量内存碎片而拖累整体性能。对这些数据操作分析后可以发现,大部分操作是SQL类操作,例如过滤、排序、合并、分组计算等,少部分是难以抽象的复杂业务逻辑,典型如商品混排。对二维数据的SQL类操作算法同学应该并不陌生,pandas DataFrame就是知名的python环境下的数据集工具。然而在Java线上服务环境并未有被众人所知的数据集工具。TPP图化在最初探索期推出了MatchRecords数据集操作算子,通过跟AI·OS引擎的flatbuffers结构对接实现了按需反序列化,并提供了基础的高性能数据操作接口,解决了数据集操作的性能问题。2021年我们把MatchRecords升级为TPP DataFrame,在接口易用性、功能丰富度、性能三方面做了提升。

TPP DataFrame是Java环境的高性能数据集,接口设计参考pandas DataFrame以降低学习成本,同时利用按需反序列化、延迟加载和计算、数据操作转索引操作、数据行包装为Java对象等方法提高数据操作性能。使用实际业务常见的操作序列(行列切片、行过滤、新增列、排序、join、concat、两次全量取值)对DataFrame工具进行的综合操作评测,结果显示,TPP DataFrame的性能是同为java环境的开源数据集tablesaw和joinery的3倍有余。

✪ 2.2.1 特性介绍

各类数据集工具的能力大同小异,更多的差别是所在领域不同,这里介绍下TPP DataFrame比较独有的特性。

数据集与Java对象互转

SQL方式适合批量操作数据,Java面向对象适合编写复杂的业务逻辑,搜推广在线服务中两者皆有之,有没有办法同时处理好这两类操作需求?有的,TPP DataFrame可以在不损失性能的前提下在两类操作方式中灵活转换。

下图是常见的商品数据,TPP DataFrame使用动态生成字节码技术,可以把每一行映射到Java对象上(反之亦然),这样使用时灵活方便,且仍然具备按需序列化、低内存复制的性能优势。

原地更新

为了达到最好的性能,对数据集的修改被分为了索引改动和数据改动,两者均是在当前数据集上原地更新,这样能尽量减少数据复制。如需保留源数据集,我们提供了深/浅克隆,索引类操作浅克隆即可,数据类操作需深克隆。

行索引和主键索引

TPP DataFrame同时支持按行取值和按主键取值。按行取值支持python风格的负数下标。按主键取值是可以设置一列为主键列,比如设置item_id为主键列,后续可按item_id取值,数据集表现的像一个以item_id为key的map一样。

列默认值

为方便处理缺失值和异常情况,每个列可设置一个默认值,在值为null、取值时类型转换失败、取值异常时返回默认值。

自动类型转换

在实际业务中常有数据类型转换需求,TPP DataFrame支持为一列设置一个类型,取值时会自动做兼容性转换,并视类型转换成本决定是否做缓存以优化性能。

✪ 2.2.2 内部数据结构和原理

下图是TPP DataFrame内部的数据结构,主要分为索引信息和数据两部分,行操作(过滤、排序、按行切片等)大多只操作行索引和主键索引,列操作(增删列,按列合并)大多只修改列索引,数据更新操作会写入列补丁,不会修改源数据,多数接口实现了延迟加载和延迟计算。

TPP DataFrame主要对接引擎端查回的flatbuffers结构数据,flatbuffers结构有按列反序列化、反序列化成本低的特点,结合广泛的延迟计算策略,可以实现按需反序列化。

03

过去一年的进展

3.1 产品和框架能力进展

✪ 3.1.1 图执行过程可视化

用图化开发时,原有的代码级函数调用换为数据依赖声明,直接看代码容易看不清数据流转过程,从而对整图没有直观印象,造成对图的理解和改造困难。另一方面,开发调试时如果能看到数据流转过程现场,定位问题会快很多。为此我们推出了图执行可视化产品,用户可以看到分阶段的图结构,看到节点耗时、输入输出、异常、用户日志等执行情况,同时可看到耗时最长的路径(用于优化RT)。

第一层,业务阶段视角的执行情况:

进入一个阶段内部,可以看到具体执行情况:

✪ 3.1.2 子图组件编排模式

较大的图理解、维护、图上控制流都会比较难。回想Java传统方式开发时,一般会做模块划分,模块之间的调用是有层次的。为解决此问题,我们推出了子图组件+编排的开发模式,例如把特征生成、一路召回封装为子图组件,封装后可像函数一样灵活的调用。同时,组件内部是一张更小的图,更容易理解和维护。子图对框架能力的另一个重要补充是图上控制流,一张节点平铺的大图的并发度/性能是最高的,但想灵活的控制走哪些路线比较难,如果封装成子图则可以用if-else,for-loop等常规编码方式灵活调用。总体而言,图上的业务逻辑也有分阶段,分层次的管理需求,这可以用子图组件和业务分组实现。

3.2 框架性能进展

图化经常被问到性能上和手写并发有什么区别,在图化早期,正确的全异步并发写法能取得跟图化一样的并发性能,但现实中很少有人能把全异步并发写对,更别说写的干净整洁可维护了。现在,即使能把全异步并发写对,性能依然比TPP图化有差距。其原因在于图化可以利用图结构信息,给出更合理的并发分组,还可以剪掉不必要执行的节点,这些都是手写并发可望不可及的能力。

✪ 3.2.1 图上并发控制

每次异步执行会有额外的线程切换成本,包括ThreadLocal传递成本、线程调度成本、CPU cache miss成本。因此是否异步执行应综合考虑异步成本和对RT的收益。图化里较大的业务普遍有100+个节点,如果这些节点全部并发执行将会有不必要的异步成本,一种方式是让用户指定哪些节点同步哪些异步,但一方面用户很少会关注和理解并发度问题,另一方面这是个运行时动态的优化问题,开发阶段没法给出最优的并发策略。为此,我们尝试了不让用户指定节点类型,而是分场景设置节点并发分组参数,把多个原本异步执行的节点合并为一个并发分组,多个并发分组之间异步并发执行,并发分组内串行同步执行,无需线程切换。起到了控制并发度,降低异步成本的效果。今年双11此项优化在头部的推荐场景上开启,在保持RT不变或轻微上涨的情况下,CPU使用率平均降低13%。

✪ 3.2.2 图动态剪枝

特征加工和多路召回是搜推广业务流程里最常见的环节。特征加工环节一般需要取多种数据,基于数据做多层次的特征加工,特征与数据、特征与特征之间存在复杂的依赖关系。特征加工之后,特征数据将分头流向多路召回节点。多路召回的路数一般由当前业务的类型,是否降级执行等决定,那么如果业务决策某一路召回不需要了,如何把相关节点关闭以节省计算资源?

这就引出了图动态剪枝功能,图动态剪枝优化是一种图上控制流,它允许用户动态关闭一个节点,动态剪枝可以从被关闭节点向上反推,关闭所有仅被被关闭节点依赖的节点,是一种利用图结构信息精益执行的典型功能。如下图案例中,在菱形节点判断这次请求可以关闭红色节点,动态剪枝功能在图结构上回溯,把仅为红色节点服务的橙色节点都关闭,从而节省当前机器和下游的计算资源。

04

未来展望

4.1 图任务调度的精细化

图化并发控制是对图任务执行优化的初次尝试,由于我们拥有图结构化信息,图任务的执行可以有更高效的安排。例如根据节点类型、节点历史执行统计数据、节点所在路径重要度等信息,可以计算得出更优的执行路径。例如可以根据当前机器CPU水位决定降RT还是拉水位,也可为日常态和大促态区分不同的配置。以上都依赖于对图任务的精细化控制,在这方面图化框架应借鉴数据库、分布式计算框架的任务调度思路。

4.2 图的分布式部署

用户发起的一次请求常由多个TPP业务场景处理,业务场景之间通过相互调用传递数据。这个处理过程是一张更大的图,可以站在大图的视角对图节点做调整分配,对整条链路做统一的编排、部署、监控。从编排上看,多个业务场景间更容易沉淀和复用业务组件,减轻现在一份代码多次复制维护的成本问题。从部署上看,图节点在哪里执行可以按需调整,例如日志埋点类节点可以跟主链路节点隔离部署。从监控上看,通过全链路监控,链路问题的定位一目了然。

4.3 开发阶段易用性改进

图化节点之间的依赖关系跟数据流转方向是相反的,这不利于开发阶段对代码结构的掌握。同时图化鼓励组件+编排的开发模式,编排部分放在JSON配置里,在缺乏IDE工具的支持下,无法做到配置跟代码的关联、配置正确性校验。理想中的图化IDE能对每种构图配置展示图结构,图可以关联到配置和类,配置有代码提示、可跳转、可校验。这类本地开发的体验应当和开发普通Java应用的体验对齐。

05

总结

TPP图化经历3年的发展,从19年高性能图引擎,到20年更易用的依赖构图开发模式,再到21年受益于图结构产出的产品、性能、编排能力。在发展过程中我们感受到图化作为新的开发方式,其学习成本、易用性、产品配套对其真正发挥价值的重要性。图化的易用性和性能是两个不同的方向,中间需要用更深入细致的技术改造将其粘合起来。未来我们会首先解决尚存的易用性问题,在此基础上利用图化的结构化信息、易编排的特点,在性能和产品化上深挖。最终目标是把TPP图化打造成算法在线服务领域易用、性能极致、迭代效率远超普通方式的产品。

最后,TPP在阿里云已经正式发布商业化版本。与此同时,TPP图化也被SaaS产品智能推荐Airec以业务框架形式集成,对外输出解决方案。商业化版本的TPP适用于对性能、稳定性要求高且追求快速迭代的业务场景。

欢迎大家把文章转发给你身边有需要的技术同学,也欢迎点击文末阅读原文进行体验。

产品体验

TPP商业化版本体验:

https://tpp.console.aliyun.com/

SaaS产品智能推荐Airec体验:
https://airec.console.aliyun.com/airec/