在携程的搜广推业务中,Eagle技术生态扮演着核心角色,不断地应对业务扩展带来的新挑战。本文首先剖析了Eagle算法策略平台的架构创新,包括流程组件化、编排可视化和逻辑算子化,这些设计有效提高了开发效率并确保生产稳定性。进一步通过推荐信息流业务的实践案例,展示了策略平台在性能提升和资源优化方面的实际效益。最后,对平台的未来发展进行了展望,包括优化调度、增强编排、灵活部署、全链路监控和提升用户体验等,以持续引领技术创新,满足业务发展需求。
一、背景
目前Eagle(携程搜广推中台框架)技术生态在集团多个业务线搜广推业务中发挥了关键作用。它在模型训练/推理,特征生产/服务,在线策略服务、分层实验以及运维监控等方面提供了统一且易用的基础框架,显著提升了各业务团队在研发效率和业务效果上的表现。
在效率提升方面的核心点包括:首先它改变了传统的算法和开发协作模式,使得算法同学能够直接参与到线上召回和重排模块算法策略代码的开发,大幅降低了沟通成本和一致性问题。其次,通过分层实验平台实现了A/B实验参数化、配置化高效做实验。这在一定程度上提升了策略逻辑的透明性和实验效率。然而,随着业务场景的扩展、业务需求量和复杂度的增加,同时更多的算法和产品同学参与进来,在代码质量、参数管理以及沟通协作出现了一些新的问题。这些对工程质量、迭代效率和性能带来了新的挑战。主要体现在以下几个方面:
1)代码冗余、参数爆炸:由于各场景在召回和重排阶段存在策略逻辑的相似性、导致了大量的代码复制现象。这种状况不仅使得服务变得过于臃肿,也大幅增加了维护成本和迭代难度。
2)逻辑黑盒和沟通成本:业务逻辑的掌握仅限于开发者本人,其他人一般都是通过文档和口述同步逻辑。反之则需要投入大量时间来理解和掌握现有的代码逻辑,这无疑增加了团队的协作难度和沟通成本。比如,日常的case Debug和策略解释路径很长,产品找算法找开发一层层传递,效率和沟通成本问题严重。
3)迭代风险与难度:代码缺少流程和模块化设计,比如:某一个召回策略逻辑几十行甚至几百行代码都写在一个类里面。这样当需要更改这块逻辑时,无疑增加了出错的风险,也使得迭代过程变得更加困难和低效。
4)质量和性能问题:算法同学(包括一部分工程同学)工程能力层次不齐,算法同学更多的是关注策略逻辑的实现,在代码设计和质量没有太多的优化经验。导致上线运行时的各种问题逐渐显现,如:时空复杂度、频繁GC、潜在的代码漏洞,系统的稳定性、资源利用率以及性能瓶颈等问题等。
二、算法策略平台是什么?
Eagle 算法策略平台是一个高度配置化和透明化的算法策略开发和部署平台。平台专为搜索、广告和推荐系统业务领域设计,通过实现搜广推全流程的配置化和透明化,简化算法策略的迭代流程,使得算法团队能够更加专注于策略的效果优化和业务目标的实现。平台提供了视图和工具,使算法团队能够直观地理解和监控流程中的每个环节(数据召回、排序逻辑、模型预测等),同时集成了自动化测试、实时监控和告警、分层实验和问题排查功能,确保了平台服务的高稳定性和可靠性。
三、整体设计
策略开发平台为用户提供一套从算子开发,任务编排到策略上线的完整解决方案,实现了策略上线流程标准化平台化管理,沉淀策略通用能力。策略开发人员可以根据不同的业务场景对相应的业务流程进行编排和发布。相对于传统的策略开发上线流程,该方案具有以下优势:
流程组件化:将策略上线流程划分为三个阶段:算子开发,策略编排,任务运行;三阶段分别封装为完全解耦的三个组件,使方案整体具有高扩展性和低成本维护。
编排可视化:策略的编排采用标准的DAG模型,在页面直观的展现策略节点逻辑信息及节点间的逻辑关系,实现了策略逻辑完全透明。
逻辑算子化:框架提供一套统一的OP算子接口,实现了每个算子参数协议独立,功能单一,进一步减少策略代码的冗余度和提升代码的复用性。
因此,我们将整个开发平台划分为三部分:
1)OP-Organization:通过可视化的页面管理逻辑算子(OP-Lib)代码库,策略组件管理,策略逻辑编排(DAG)。执行策略标准化上线流程;
2)OP-Lib:实现统一OP接口的代码库。通过接口及注解定义了统一的OP代码开发规范,元数据声明,耗时及异常实时监控。大幅提高代码的开发效率和复用性;
3)OP-engine:实时监听策略配置(DAG)变更,支持DAG的自动优化(节点合并),动态裁剪,节点限流,熔断,实时监控,数据回流等功能,确保策略高效运行;
3.1 策略编排:简单,直观,安全,高效
策略逻辑作为支撑线上效果的主要逻辑,需要高效的迭代上线,不断的验证正向收益,在底层的框架支持上,已有分层实验平台和ABtest实验可以满足高效的实验和结果验证,但在涉及到逻辑执行层,没有统一的管理平台,以适应策略的高频迭代,为解决上述痛点,设计并开发了策略开发平台。在搜广推场景中,针对不同的调用阶段,将整体流程分为了召回,粗排,精排,重排几个阶段,下面就以召回阶段的视角来介绍策略开发平台的特点。
3.1.1 策略编排可视化,所见即所得
召回首先要解决的问题是如何将策略逻辑透明化,需要宏观视角去呈现线上服务运行的策略链路,它们之间的调用关系是什么?如何快速地调整不合理的策略逻辑。
3.1.1.1 应用场景可视化
进入BU下的策略首页,即可看见以卡片形式展示出的策略梗概信息(场景,上线状态,更新时间等),拥有权限人员可以编辑对应卡片。
3.1.1.2 策略组件可视化
进入具体策略,可以查看编辑该策略,同时可以追踪、回退历史版本。在当前页面中,为了增加策略逻辑的可读性,使用自定义组件将逻辑功能相同的策略节点封装在一起,使用户对逻辑策略的认识更加直观。例如下图中,在召回阶段按召回通道将策略封装成一个个并行组件,使用户直观了解到该策略下的所有召回通道。
3.1.1.3 策略节点可视化
组件中的策略节点是平台中的最小单元,是由策略OP算子(OP-Lib代码库)和策略参数组成。通过此页面不仅可以方便的选择一个OP来生成策略节点,同时可以以拖拽的方式编排各个节点的调用关系,通过OP算子上报了的元数据信息,平台确保节点调用关系的正确性,保证策略上线的安全。
3.1.2 标准化上线流程,提升上线效率
标准化上线流程在提升上线效率的同时,保证每次配置发布都按照规定的步骤和规范进行,降低人为错误的风险,并通过验证和测试来提高配置发布的质量和稳定性。
3.1.2.1 自动化测试
自动化测试工具将服务代码打包成Docker镜像并部署到k8s容器中。根据线上服务的历史请求数据,构建请求报文并发送到该服务。获取到结果后,对不同配置获取到的结果进行比较。最终生成的测试结果将作为策略开发人员判断配置变更对服务性能、功能、稳定性的影响的评估依据。如果测试结果不符合预期,策略开发人员可以及时调整配置,确保服务可以正常运行。
3.1.2.2 灰度发布
策略开发人员可以将新配置发布到镜像集群或者测试集群,在正式上线前尽可能发现并解决潜在的问题,确保基于新配置的服务能够稳定运行,功能和各项指标符合预期。当新配置通过测试和验证,即可发布到生产环境。
3.1.2.3 配置回滚
当配置发布到生产环境后不符合预期或者出现问题,可以通过回滚功能将配置回退到上一个稳定版本,降低配置对服务的影响。
3.1.3 先设计、再开发(Design First)
平台提供了在线编排可视化功能,极大降低了用户上线策略的学习成本,用户只需对策略OP进行编排,即可完成策略上线。这种开发模式的转变,要求用户更多的去思考如何合理编排策略OP,以及如何设计可复用的策略OP,避免了老的开发模式(边开发边设计)带来的需求演变、迭代时大量修改和补丁的问题。
同时,策略OP的动态组合也带来了一些问题:1)如何确保组合后的各个OP能正常调用,避免出现不合理的调用关系甚至参数类型不兼容,2)编排好的DAG图在运行时却找不到挂载的OP实例。在高并发流量的首页信息流场景中,每一个问题都足以致命,为了解决上线的安全性,这就需要依靠完善的OP元数据上报机制以及OP代码库的版本验证来保证。
3.1.3.1 OP开发流程和规范
为了保证用户在操作策略节点编排时的安全性,在设计OP时,首先定义元数据信息,包括但不限于:OP类信息,输入输出类型和校验逻辑、方法详细功能描述等。当OP设计完成后再是代码开发。
3.1.3.2 OP代码库版本验证
由于OP代码库在线上服务中为预加载方式,即线上OP实例在一个运行周期内是完全恒定且单例的,需要在配置平台在推送策略DAG异步上线时确保每个DAG节点挂载的OP实例在服务中是存在的,平台使用的方案是在推送策略变更前做一次版本验证,保证线上OP版本与配置版本完全一致。
OP代码版本验证流程图
i. 用户编排策略(DAG)时从OP池选定某一个OP-Lib代码版本构图,如选择最新版V3。
ii. 策略发布时进入版本验证流程(version check),该流程从在线服务中拉取当前线上OP代码版本与构图OP版本对比,版本相同时策略进入launch流程推送至配置存储系统(Config store)。
iii. 在线应用实时监听,将内存中的策略配置(DAG)更新,完成一次策略发布。
3.1.4 数据引擎
平台集成了数据引擎matrix,为在线策略提供线上数据访问能力。matrix负责管理数据上线流程和提供统一的类sql查询访问,对应用屏蔽底层存储,大大降低了策略开发成本,开发人员能够专注于业务实现。
3.2 OP-Lib:面向运行时的统一代码库
在敏捷开发模式下,开发人员更加关注的是每次迭代需求的快速交付,往往容易忽略新增代码与现有代码的统一风格规范,代码冗余度,整体运行效率等问题。容易出现不同功能代码间的强耦合,编码相互入侵,上下文运行环境不兼容等一系列问题。这些问题带来的最直接的后果就是代码维护成本不断提高,线上运行效率的不断下降,同时大量的补丁代码也增加了线上BUG出现的概率,因此我们需要提供一套标准的策略算子统一规范,在满足业务功能的前提下将异常的影响控制在最小的范围内。
3.2.1 OP-API:功能完善的OP接口
为了使策略逻辑代码和开发平台解耦,我们设计了一套完整的OP接口规范,通过这套接口的隔离,用户只需定义OP的输入输出并实现对应的OP接口,而请求上下文信息,参数验证,异常异常处理都由框架自动处理。
EagleOperations是OP算子的统一接口,作为OP与调用方的交互规范,为了增加OP的通用性,OP接口只有一个exec方法
AbtractEagleOp封装了对OP算子的通用处理逻辑,包括参数验证,上下文解析,运行时监控埋点以及异常处理。
AbtractNodeOp是OP接口对策略执行引擎的扩展,主要面向执行引擎的DAG节点实现,在OP接口的基础上扩展了节点相关参数
3.2.2 OP-Lib:开放的策略OP代码库
OP-Lib是所有策略业务实现的代码库,在OP接口的规范下,策略的实现可交由各个业务开发来完成,同时在发布代码时上报该策略OP的元数据信息,如逻辑说明,输入输出参数类型等。框架将在服务启动时以预加载的形式实例化这些OP算子,并在请求进入时根据DAG执行计划统一实现调度策略OP开发流程遵循:OP设计与实现、单元测试、(框架)集成测试、 Snapshot包、Release包。
3.2.2.1 OP定义与实现
策略OP作为DAG的执行图节点,包含图节点基本要素,同时作为逻辑单元,为提高策略复用性、策略上线效率,通过配置化驱动。同时为避免参数爆炸、策略实验等问题,引入“参数组”概念,OP代码提供了逻辑模板,配合参数组完成具体业务策略。
i. 元数据信息定义
开发OP前,首先定义OP元数据信息,将定义的OP元数据信息通过配置文件的形式保存,用于后续上报。
ii. 代码实现
框架提供了一套完整的OP开发接口,屏蔽了底层图执行相关实现细节,同时提供了异常、超时等机制,用户只需关心OP的内部的逻辑功能实现。
策略OP可继承的OP基类可分为两类:
1)NodeOp0<I,O,P>
表示接收多个同类型上游OP的输出结果集合作为入参,上游OP的数量不限制,并且接受的上游的输出是无序的。
I:输入类型,O:输出类型,P:参数类型
2)NodeOpN<I1,I2,....,IN,O,P>
表示接收N个不同类型上游OP的输出结果作为入参,N在这里是泛指多个,具体基类包括:NodeOp1,NodeOp2,NodeOp3.......等,实际执行时上游OP的数量要同该OP定义的数量保持一致,且有序。
I1,I2,....,IN:输入类型,O:输出类型,P:参数类型。
基类提供3个方法:
1)Opout<O> process():具体的功能逻辑
2)Opout<O> fallback():失败回调方法,用于异常处理,降级处理。当上游节点抛出异常、或者自身逻辑抛出异常时,会执行该方法,方法的返回即节点的输出。
3)Function<JsonNode,P> paramFn():定义策略参数解析器,用于将策略平台定义的json参数结构转化为OP定义的参数实体。
3.2.2.2 调试与监控
1)在线debug调试
为方便用户在线调试、排障,我们提供了debug模式,可以在线查看整个图中各节点的输出的结果,验证各节点结果的正确性,快速定位问题。
在构建DAG图的执行请求时,通过设置debug参数为true来开启debug模式。
同时考虑到某些节点的输出可能是函数、延迟计算等不可直接查看的对象,我们提供了SyncOpOutput接口,实现OP输出的自定义转换,同时不影响线上正常输出。
2)自动化测试
OP上线前,我们要保证对线上现有的策略和性能上无影响,可借助自动化测试完成。
目前平台已集成自动化测试功能,支持多种测试需求,包括:功能测试、回归测试、结果一致性测试、性能测试。上线前需要将测试包/分支上传至测试平台,同时设置样本用例、测试规则等参数即可开始自动化测试任务。
3)监控埋点
平台提供了丰富全面的监控埋点(流量监控,耗时监控,异常监控等等),帮助用户观测OP在线运行情况。
3.2.2.3 部署与注册
最后需要将包含OP元数据信息的配置文件跟随代码一起发布到代码仓库,发布一个正式的代码仓库包,然后在策略平台的OP管理库中升级版本,将刚创建的包注册进去,完成OP上线。
3.3 DAG执行器:高效的通用策略执行引擎
策略的执行引擎是一款基于有向无环图(DAG)的数据结构实现的策略节点调度框架,为了满足和覆盖搜广推全场景策略的编排,在引擎的设计上充分突出灵活易扩展的特点,既可以快速应用于现有的策略场景中,又可以实现快速扩展附加功能。该执行引擎具有如下特点:
标准的DAG规范:框架接收所有符合DAG规范的执行计划。具有高通用性
OP复用,为了增加OP的复用性,降低代码冗余,框架从设计上将OP实例作为单例模式预加载,并可以挂载到多个相同功能的节点上,通过执行节点参数来执行不同的逻辑分支
DAG嵌套:支持在DAG中将节点配置成另一个DAG子图,形成DAG嵌套结构。该功能在复杂的DAG中可避免节点平铺,具有更好的可读性,同时隔离资源及异常
动态图裁剪:支持根据请求动态裁剪DAG的边对象,满足节点维度的ABtest实验
可扩展的图优化器:框架监听到图配置变更后默认启动责任链模式的图优化器,用户根据应用场景扩展需要的节点优化规则
OP策略执行框架结构设计示例图
OP算子复用示例图
3.3.1 应对复杂场景的执行引擎多种实现
由于框架设计目标是可以执行任何标准的DAG图,为了保证各种简单或复杂的DAG能以最高的效率运行,我们在执行器引擎设计上采用了统一接口的多种运行策略实现,并支持动态切换,目前已实现了三种执行引擎:
3.3.1.1 广度优先串行调度
在广度优先(BFS)的访问策略下,执行器会以入度为0的顶点作为入口,直接使用请求线程以串行方式依次调用当前层的所有节点,如果同一层访问完毕,再调用下一层,直到所有节点访问完毕。该策略在执行周期内完全使用请求线程,没有线程切换开销,占用资源较少。但所有节点串行执行会增加执行器整体耗时,比较适用于对响应时间要求不高或无状态的纯计算场景。
3.3.1.2 广度优先并行调度
此调度实现同样使用BFS的算法访问节点,并绑定一个线程池资源,调度时会将同一层的节点打包提交到线程池并行执行,对于并行度较大的DAG,此策略可以有效提升DAG的执行效率。
3.3.1.3 全异步响应式调度
虽然并行调度的方式可以并发执行DAG中平行的节点,但仍然存在“短板效应”,由于提交批次间仍然是串行的,如果某一批次中的节点N执行耗时较大,则该批次所有节点都会阻塞等待,尽管下一批次中大部分节点不依赖节点N。为解决此短板,我们使用异步阻塞队列实现一个全异步响应式执行器,执行过程如下:
主线程逻辑:
1)主线程(请求线程)进入执行器,创建一个阻塞任务队列Q。并找出DAG的所有根节点(入度为0的顶点)作为任务队列的初始任务;
2)主线程进入事件队列开始调度:主线程尝试从任务队列等待可执行的节点,如果获取到节点则将节点提交给异步线程(子线程)执行(如果等待超时,则退出);
3)如事件队列还存有未执行事件则重复2)操作,如当前请求所有事件(任务)全部执行完成,则获取叶子节点的返回结果并退出DAG,执行后续的流程。
子线程逻辑:
1)子线程接收到主线程提交的任务后开始执行,并将返回值存入临时缓存区。
2)子线程在完成当前节点任务后,从DAG中找出当前节点所有可执行的下级节点集合,压入任务队列,(触发主线程步骤2)
3)子线程标记后被回收(如是虚拟线程则直接释放)
异步响应式调度的优势在于,在复杂DAG下,每个节点只要满足了前置条件(入度全部完成)即可触发运行,不受同层平行节点的耗时干扰,进一步提升了执行器运行效率。同时该策略下由于每个节点都是异步运行,在传统的平台线程池模式下,高并发意味着占用更多的线程资源,需要合理设置线程池规模和资源降级策略,另外框架支持在java21环境下将线程池配置为虚拟线程模式,该模式下节点将使用无池化的虚拟线程异步执行,关于虚拟线程相关概念可通过JDK官网了解
下图对比了分层调用和响应式调用的区别,可见响应式调用可明显减少调用时间:
3.3.2 执行效率提升:可扩展的DAG图优化器
在策略开发平台的策略编排(DAG构图)完全由用户自定义,这意味着推送到执行引擎中的DAG规模可能非常大,如果用户同时使用的是异步执行器,节点的并行规模可能会耗尽线程资源,因此,我们引入了一个异步图优化流程,执行引擎监听到DAG图变更后,会将此图的节点按照需要的规则进行合并,最终生成实际的物理执行计划;从设计上看,优化器采用了责任链的开发模式,除框架预设的优化器外,用户可以扩展实现自定义规则的优化器并设置顺序。合理的执行顺序能有效提高优化器的执行效率。
图:基于责任链的图优化器
目前框架预设的优化器为串行节点优化器,可以将关系唯一的两个相邻节点合并为一个包装节点,减少执行器的调度次数和线程资源。
在实际案例中证明,用户的DAG图越复杂,默认优化器的优化效率越高:
3.4 策略平台在推荐信息流中的实践
目前整个推荐策略已完成策略OP化改造工作,策略OP涵盖了召回和重排等多个阶段,已有80多个推荐信息流业务场景接入了策略平台,涵盖了多条业务线。
3.4.1 策略上线效率提升
以信息流召回阶段的策略上线为例,在原有开发模式下,需要重新定义一个新的通道,涉及代码逻辑定制,要经历开发、测试、发布的一个完整上线流程,至少两天时间。接入策略平台之后,完善的策略OP池基本覆盖了召回各种需求策略,一个新通道上线,只需添加配置,测试验收即可,简单的策略1小时内可以上线,复杂的策略半天时间,极大的提升了策略上线效率。
3.4.2 策略逻辑透明
策略逻辑通过DAG图化展现,根据每个节点所选择的OP以及定义的参数组能够快速了解该节点内部逻辑,策略整体逻辑清晰明了,大大降低了学习成本低,沟通成本。
下图为首页召回阶段平台视角,可以清楚看到线上生效的策略(SWI,LIVE,PN,LGC,SEA,GPR等),以及各策略使用的召回组件模板,可大致了解通道逻辑,比如SEA使用的是模型召回组件(ModelRecall),通过模型来召回产品;SWI使用的是trigger召回组件(X2I),通过指定条件召回产品。
点击通道可查看该通道具体的策略逻辑,下图是PN通道的策略逻辑,可以看出该通道由两路查询策略合并组成。
3.4.3 性能提升,资源优化
首页推荐信息流召回服务接入策略平台后,服务性能得到提升,资源利用率得到优化。
性能相关指标如下:
整体耗时提升30%左右,性能得到明显提升。
资源相关指标如下:
下图左边为老版召回应用核数变化,初始核数为2400,右边为新版应用核数变化,流量完全切至新版后核数为900,CPU核数从2400缩减至900,缩减比例60%。
同时策略平台底层框架引入了java21虚拟线程技术,对于召回这种重IO的业务场景,资源得到进一步优化。下图为新版召回服务使用虚拟线程前后资源对比,因虚拟线程切换,CPU核数从900缩减至600,缩减比例30%,CPU利用率由 20%提高至40% ,提升100%。
经过上述两次优化,召回服务的CPU总核数从2400缩减至600,缩减比例75%,资源得到优化。
3.5 未来规划
3.5.1 平台建设
平台未来会持续建设、优化,主要目标包括:
继续优化图执行引擎,提升图执行效率;
OP性能优化和组件沉淀:优化OP性能,沉淀业务组件、提升新场景构建效率;
全链路Debug:为全流程提供统一的Debug,帮助用户快速定位链路问题,提高问题解决效率;
平台易用性:为提升用户体验,进一步提升易用性;
3.5.2 平台推广
平台专为搜广推业务领域设计,目前首页推荐业务场景已接入策略平台,未来将继续推动和支持更多业务线搜广推业务场景接入。