闲鱼推荐大规模应用背后的工程实践
讲师介绍
闲鱼技术部 | 吴白
万小勇(吴白),闲鱼服务端专家。 毕业于南京大学计算机系,目前负责闲鱼技术推荐架构。
推荐在闲鱼的应用
不同于搜索的确定性,推荐场景面临的问题往往是不确定的。但是正是因为这种不确定,带来了非常大的可能。所以推荐在闲鱼基本上遍地开花的状态
尽管如此,推荐在闲鱼仍然面临着非常大的挑战,而这些挑战和闲鱼C2C市场的定位和特性密切相关。总的来说,闲鱼有四个比较明显的C2C特性:
- • 浅库存。闲鱼的商品基本都是孤品单库存,售出即下架。这就需要推荐系统需要非常实时的感知到这种状态变化,对实效性要求非常高。
- • 轻发布。闲鱼中的卖家大部分都是个人卖家,为了简化发布成本,一直提倡轻发布。所以闲鱼商品的结构化信息非常少,这给推荐带来的挑战非常大。
- • 自由市场。闲鱼还是一个自由市场,在这个市场中有个人卖家,小B卖家,行业和专业卖家,同时也有各种黑灰产用户。这导致在闲鱼流量分发的难度非常高。
- • 快速成长。最后闲鱼是一个成长型业务,快速增长带来的规模对推荐的整个基线压力非常大。
闲鱼推荐的演进历程和这四个特性密不可分,所以闲鱼推荐大致可以分成四个阶段
- • 阶段一:圈品+离线打分。这个阶段推荐主要靠圈品+离线算分为主,无个性化,时效性天级。
- • 阶段二:少量算法。阶段二开始在首页核心场景引入算法,以天级的I2I为主,但推荐底池时效性已经到了秒级。
- • 阶段三:扩大应用。随着业务拿到算法第一波红利,越来越多的业务开始接入算法。特征和模型时效性也从天级提升至小时级,闲鱼首次引入招选搭投,应用大规模铺开。
- • 阶段四:随着业务快速成长,规模快速扩大,底层基建迎来大规模升级。全图化,模型自动压缩,通用推荐等实现从0到1的越跃变。
经历了上述四个阶段的演进,形成了如下所示的闲鱼推荐HLA
算法离线面临的挑战
闲鱼对实时数据的强诉求-公共实时数仓建设
闲鱼有非常多的场景需要消费实时数据,比如在生态治理方面,闲鱼上很多优质供给在很短时间被黄牛扫光,但是从平台角度看肯定更希望这些优质供给能被更多的用户消费;
因为这个原因,闲鱼长久以来有3个团队在做数据相关的建设:算法面向模型,需要非常实时的数据,所以会做很多定制化的链路;BI面向数据分析;工程面向应用。随着不断的演进叠加,其问题也逐渐暴露出来:
- • 数据时效性缺乏。除了算法,工程和BI对实时数据的诉求也越来越强。
- • 数据准确度问题。由于之前的数据都是烟囱式开发,其数据在使用之前无论是数据口径还是精确都需要做多轮check。
- • 成本浪费。存在大量的数据冗余存储和计算。
所以BI,工程,算法一起打造闲鱼的公共实时数仓,作为下游众多应用的数据来源。
特征需要被统一管控
在闲鱼,特征不仅应用广泛,而且影响非常大。无论是从沉淀服务更多场景还是成本的角度看,都需要统一管控起来。
我们期望通过特征中心的建设,实现以下几个目的
-
- 特征能以资产的形式沉淀下来。所以我们构建了特征写入和存储模块,结合特征管理模型,实现特征的低成本快读接入。
-
- 特征能够高效的对外输出。一方面性能足够好,另一方面能以不同的形式服务众多下游。
-
- 特征生命周期管控。在这以前,闲鱼的特征是不可迭代的。因为只上不下,线上哪些特征在用,这些特征的价值如何,没有人能回答。因此我们构建了特征质量模块,通过对特征重要性分析,对特征进行统一管控。
-
- 基于特征的样本构建足够高效。通过特征全埋点来自动构建在离线一致的实时样本流。
在离线模型的差异
一般来说,离线训练得到的模型并不能直接部署线上。这里有多方面的原因
-
- 模型网络结构的差异。典型的模型离线训练流程为:输入,预测,优化。在线预测阶段则只需要输入,预测 两个环节。
-
- 输入的差异。一方面数据结构的差异,模型离线训练阶段需要输入特征和label 共同组成样本。在线则只需要输入特征即可。另一方面数据源也存在着差异。训练阶段的数据大多来自于存储在某个地方的数据集,在线服务的输入则来自于请求入参和在线服务。
-
- 计算架构的差异。离线训练阶段由于对性能要求不高,模型可能运行在CPU之上。但在线阶段由于对性能要求较高,则有可能运行在更为复杂的如cpu+gpu环境之上。
模型自动裁剪
在模型Offline2Online过程中,我们首先需要对模型做一轮自动裁剪。
模型网络压缩
压缩过程中主要有几个策略
- • 模型计算图的拆分。将cpu和gpu拆开,计算密集型的任务放在gpu上完成。
- • 计算逻辑Online2Offline。部分计算逻辑从在线计算变为离线提前计算完,在线只需要IO读取。
- • 模型计算图压缩。这部分主要是算子的合并,减少数据传输和切换的开销。
除此之外,在GPU上也做了大量的优化工作,这些优化工作总结起来遵循两个原则
最后做一个总结,闲鱼推荐系统的离线架构如上所示,主要解决
-
- 数据研发效率 。如何快速拿到需要的数据。这里面会涉及到数据时效性如何,数据准确度是否满足要求,数据是否散落在各地等一系列问题。
-
- 特征迭代效率 。这里会面临的问题包括:特征在离线一致性;样本高效回刷;特征一致性解析(训练阶段和在线服务阶段,特征来源不一样)。
-
- 样本生产效率 。每次模型迭代机会都会涉及到样本的更改。一个比较典型问题如行存样本导致的重复计算和重复存储的问题。
-
- 模型开发效率 。可复用能力:有效的模型网络是否沉淀,以便新模型快速冷启;一些和模型无关的细节能否底层做掉,对算法屏蔽掉细节,比如滑动auc窗口时auc自动清零等;常用的脚手架代码能否通过框架完成等。
推荐在线服务部署方案
在线服务部署-兼顾性能和效率
闲鱼推荐整体流程采用业界通用的分阶段召回架构,主要包括召回、粗排、精排、上下文重排这几个大模块,如下图所示:
在讲在线部署方案的时候,我们需要回答两个问题
-
- 对业务来说,部署方式是否足够灵活。哪些因素会阻碍业务想要的灵活性?我们认为有以下几点:
- a)对算法是否足够轻量,让算法专注策略本身,屏蔽工程细节(性能,部署,资源调度等)。
- b)上线周期是否足够快。
- c)能不能进行低成本,大流量分层实验。
-
- 对算法来说,部署方式能否保证其有足够的迭代空间。比如是不是足够稳定,性能是不是足够好,资源利用率是不是足够高等等。
为了回答这两个问题,闲鱼推荐在线服务采用上面的部署方案,总体包括4个模块
- • 在线服务模块。面向业务的serverless层,将算法能力打包成在线服务对外输出。它有几个特点
- • serverless平台。对算法屏蔽了底层资源调度,部署等细节。足够轻量,一次发布只需要秒级即可完成。
- • dag引擎。采用全图化框架,底层运行在dag引擎之上。算法代码完成后天然高性能并发,业务逻辑可视化。
- • 实验平台。能够支持算法快速进行低成本,大流量的分层实验。
- • 召回&粗排。召回&粗排由于需要对万级别的数据进行计算,所以进行单独部署。在内部采用多行多列部署模式,增加灵活性的同时保障有足够的性能。
- • 打分引擎。精排环节由于数据已经收敛,所以优先保障迭代的灵活性,所以精排单独部署,同时会把模型和特征尽可能提前部署在一块儿,最大化性能表现。
- • 监控平台。屏蔽底层差异,无论是基于Java的在线服务还是基于C/Python的引擎层,都可以通过足够标准化的数据协议使用一套方案解决。
业务规模快速增长带来的挑战
这里不做展开讲解,之前有过详细介绍的文章。
可度量的策略解决方案
开放平台下的生态运营-混排策略层
闲鱼为什么需要单独的策略层?这和闲鱼自身的定位和特性强相关。
-
- 闲鱼是一个足够开放的平台,面临的问题非常多且复杂。
-
- 足够开放的平台之下闲鱼还是一个C2C市场,流量的分发需要回归C2C本质。
比如闲鱼面临着以下命题,因此在服务之上,架了一层策略层,来实现流量分发的全局最优。
生态治理解决方案
我们把闲鱼面临的一些问题从调控对象和范围两个维度划分来六个象限
基于这六个象限,设计了一套流量调控系统
分层架构下的置信实验体系
到现在,闲鱼推荐的分层架构基本就已经很清晰了,如下所示
这里面每一层都会进行独立的实验迭代,也就意味着每一层都可能对大盘产生影响,无论是正向的还是负向的。因此在闲鱼经常会面临着一些下面的灵魂拷问
为了回答这些灵魂拷问,我们对实验体系进行了重构,主要重构点包括
- • 新增空白层。每个实验域新增一层不做任何实验的空白层。由于每一层的流量都会均匀分布在空白层,因此该层的指标可以体现所有层的实验叠加后的效果。
- • 新增空桶。每个实验域新增一个贯穿每一层的空桶。空白层 vs. 空桶,可以得到每个域的实验叠加后对指标的提升效果。
- • 全局空桶。新增一个全局空桶贯穿每个实验域,用来衡量业务大盘的一些指标情况。
总结与展望
综上,未来仍有很多优化手段可以关注:指标自动归因,推荐链路白盒化;模型可解释;大规模负样本采样等。