随着小程序业务的飞速发展,也诞生了很多垂直形态的搜索推荐场景。由于业务场景和内容形态的双向增长,给现有搜索推荐架构带来了较大压力,每一个场景每一类形态都需要完整走一遍数据采集、特征处理、索引构建、召回、粗/精排、异构混排等全流程,在架构上形成了一定的冗余,各个场景、形态之间的策略、规则长期堆积,也增加了架构的负担。因此,我们构建了统一排序服务,将排序能力算子化,与整体搜索推荐的架构进行解耦,在追求业务敏捷迭代的同时,也保证了架构的稳定性、扩展性和服务能力。
一般而言,算法工程师在构建开发与优化迭代业务模型或者业务特征,通常需要经历下面的流程:
[图为阿里RTP]
数据是算法之源。无论是特征、样本、训练数据都需要从业务的实际数据中进行采集、清洗、预处理、存储。针对不同场景不同形态的业务,我们已经构造了一套完整的全量、批量、实时、近实时等各类数据流程,经过中间一系列的组合处理,最终依据使用的场景,用不同的存储方式来存储。
对业务已有特征来说,通常,预处理过后的数据还需要进行特征抽取和变换,才能转变为业务特征。同时,算法工程师基于业务理解、数据分布、模型测试,也会不断地开发新特征、迭代已有特征的计算方式。
通常模型构建和特征构建是同时进行,模型依赖特征情况,特征也依赖模型定义,两者密切相关。在构建好模型、特征之后,算法工程师基于业务理解、数据分布构造样本集用于训练测试。实践表明,样本构造没有模型设计那么引人注意,但往往对在/离线的效果一致性有关键作用。
正所谓毕其功于一役,之前所做的工作最终要落到线上服务才能发挥作用。因此这里也相对较为复杂,需要考虑特征的线上线下一致性,样本在线构造、模型前向服务、性能、与其他业务逻辑的融合、监控运维等各个方面。
由于篇幅所限,本文主要探讨第4点在线服务的部分。
整体搜索推荐架构是基于微信内部RPC框架(可参考对外开源版本phxrpc)来搭建,因而之前的排序模块也是基于该框架搭建的PRC服务。算法工程师在进行模型与特征上线的时候,需要手动用C++转写离线部分的特征算子及模型前向服务,需要导出能为C++能够加载的模型文件,需要手动转写线上实时样本拼接的处理逻辑,以及其他业务逻辑、上下游逻辑。除此之外,算法工程师还需要考虑线上模型inference性能、模型过大带来的内存问题、服务监控和日志上报等跟业务关系不太紧密的逻辑。另外,由于之前的排序模块跟着业务场景和形态走,架构中存在若干个不同的排序服务,各自叠加了很多策略,底层共用的部分比较少,整个架构耦合的比较多。本身从线上到线下再到线上是一个比较长的链路,我们希望构建统一的rankingsvr,让框架的事情回归框架,算法工程师更聚焦业务效果本身,不仅提高效率,也减少了出bug的概率。
由于线上服务和线下建模使用的是多套语言(线下:python、scala/java,线上:c++),为了保证线上线下的特征一致,有必要先考虑将特征算子进行统一。因此,我们考虑了两套方案:
具体而言,我们约定好的统一的特征表达,每一个特征由
<特征名、特征属性、特征算子、特征来源>
唯一表示。每一个特征算子是一个具体的计算函数,所有的特征算子编译成公用的特征算子的动态链接库,无论线上线下,通过同一套动态链接库保证算子的一致性。
这个方案是优先兼顾了线上处理的逻辑和性能,线上改造成本低。但对线下建模有侵入性,而且需要较多的精力来维护特征算子的动态链接库,并且对运行平台有一定的依赖,在实操中容易出现各种小问题。
首先来看下什么是Service Mesh:
简单来说,Service Mesh把业务逻辑和服务框架进行分开,通过sidecar proxy来处理网络交互,业务逻辑再转发给instance处理。
微信内部也提供了Mesh的支持,并且兼容内部原有的RPC框架,具体细节不在本文展开。同时,对于python,内部也提供了python mesh的基础库,包括对异步协程asyncio服务的支持。
这个方案对线下建模较为友好,主要需要关注线上服务性能及部署成本。
确定了mesh方案之后,我们将rankingsvr拆解成为三个模块:mesh模块、模型打分模块、业务逻辑模块,其中mesh模块负责接管所有的网络IO以及提供路由、负载均衡等框架服务能力,模型打分模块主体采用tfserving实现,所有对模型inference性能优化也都在这个模块进行,业务逻辑模块包含特征计算、样本拼接、后置处理等。
分离成三个模块的好处在于,三者可以各自独立进行变更和升级。例如在业务逻辑不变的情况下,可以单独优化模型的inference耗时、大小;在不变更模型服务的情况下,可以调整不同的调权策略;在业务模块不受影响的情况下,可以单独升级mesh的框架。同时,三个模块跑在同一个Pod内,也减少了对资源的消耗。
微信内部有传统的后台发布变更系统,以二进制为主。近期也开始逐渐提供基于对容器的发布变更支持。类似下图所示。
简单来说,Kubernetes是一个容器管理平台,提供了一系列诸如负载均衡、服务发现、编排、部署和回滚等服务运维能力。在微信,我们使用腾讯云TKE作为基础容器服务。
大致的部署流程如下:
部署完成后,可以在内部TKE管理端查看pod情况,也可以通过内部rpc调用工具进行调用测试,压测表明,mesh服务的性能和纯C++线上服务没有显著差异。
我们针对业务飞速发展带来的多形态多垂直场景的搜索推荐需求,构建了统一的排序打分服务模块,并且由于考虑保持线上线下特征处理、模型训练的一致性,我们采用了Mesh方案,提供了对多语言的支持。由于搜索推荐从建模到上线的链路很长,Mesh化的统一排序服务,不仅提高了算法工程师和业务模型迭代的效率,也降低了各类小问题的机率,有助于系统的稳定性和扩展性。
由于篇幅所限,本文仅仅只涉及了在线服务mesh化较为粗略的过程,对于在线服务所涉及的模型推理加速(多batch、剪枝蒸馏等)、特征表示(query、user、item、context单侧及组合特征)、排序算法(ctr预估、相关性、多目标、强化学习)、多路召回等内容,以及甚至全链路的数据处理(流、批处理)、索引构建、内容理解等部分,即将陆续分享,请继续关注公众号哦。