
做推荐系统做得久了总会遇到一个灵魂拷问模型线上指标还涨得动吗如果答案是“涨不动了”一半是因为模型本身到瓶颈另一半是整个数据链路、训练资源和在线服务已经跟不上你了。这时候就需要认真聊一聊推荐系统 Scaling Up 这件事。它不是单纯加几台服务器、加几张显卡就能解决的而是一整套技术路线的重新设计与取舍涉及数据、特征、训练、服务、平台治理等各个环节。这篇文章是我在做推荐系统规模扩展调研时沉淀下来的一手笔记既包含技术路线对比也包含实际踩坑后的复盘适合正准备给推荐系统做扩容的算法工程师、工程团队和架构师参考对刚接触推荐系统、想把系统往大规模方向搭的同学同样有价值。1. 推荐系统遇到规模瓶颈时到底在瓶颈什么1.1 规模突破的三个信号数据、特征、流量同时膨胀我见过很多团队一开始推荐系统都能跑得挺好几千万样本、几十个特征、一台 GPU 服务器模型训练一个晚上出结果线上接口响应速度也还过得去。但业务做到一定阶段突然发现哪里都不对劲了。首先是样本量翻了几倍甚至几十倍离线训练从“睡一觉就好”变成“跑一天都跑不完”其次是特征数量暴涨用户画像、行为序列、上下文特征、商品属性全堆进来之后单机的内存直接被 Embedding 表撑爆最后是线上流量和候选集同时变大召回要扫的商品池从几十万变成上千万精排模型的推理 QPS 也跟着翻番服务开始频繁超时。这三个信号往往同时出现但多数团队一开始只会笼统觉得“机器不够用了”。我建议第一步先别急着采购资源而是把整条链路拆开做一次性能压测搞清楚自己到底卡在哪一环。真实情况常常是训练集群利用率不高但数据预处理任务排队排了几个小时线上服务 CPU 没跑满但向量检索的索引更新把磁盘 IO 打满了。如果连瓶颈环节都没定位清楚后面的技术路线选择就会变得非常盲目。1.2 先分清 Scale-Up 和 Scale-Out再谈选型做 Scaling Up 调研时很多文章会把 Scale-Up 和 Scale-Out 混着说但我个人觉得这两条路线背后是完全不同的思维模式。Scale-Up 是纵向扩展就是提升单台机器的能力换更大内存、加更好 CPU、上更贵的 GPU、上 NVMe 固态盘让单机扛住更大的数据量和计算量Scale-Out 是横向扩展就是加机器用集群的方式把数据和计算分摊到多台节点上。我在调研中得出一个核心结论现代推荐系统的正确路线不是二选一而是“纵向提升底层单机能力 横向扩展集群规模”同步推进。举例来说GPU 训练场景里单卡 A100 显存比 V100 大了两倍多batch size 可以直接翻倍训练吞吐明显提升这是 Scale-Up 的价值但数据总量大到单机根本存不下时再好的单机也没用就必须做数据分片、参数分片、多机多卡这就是 Scale-Out 的主场。更麻烦的是推荐系统独有的稀疏大模型用户 ID 特征、商品 ID 特征的基数可以上亿Embedding 表动辄几百 GB这类参数天然需要横向分布到多台 PS 节点上。所以我的调研结论很明确两条路线都要走只是在不同阶段有不同的侧重。1.3 把推荐系统全链路图景画出来才能做路线规划推荐系统规模化本质上是对整个链路的容量扩展。我在做调研时习惯先画一张全链路图数据埋点经过消息队列进入离线数仓和实时链路再加工成训练样本样本进入训练框架产出模型模型发布到在线服务后接收请求完成召回、粗排、精排、重排最终返回结果线上反馈日志再次回流到数据链路形成闭环。这张图看起来简单但它揭示了 Scaling Up 一个容易被忽视的事实任何一段都是独立的扩展单元可以单独扩容单独优化。数据量大就优化数据管道的并发和存储特征维度高就做特征平台化模型参数多就做分布式训练在线流量大就做服务分级和推理优化。我见过一个团队花了大量预算扩展 GPU 集群结果发现数据预处理每天跑不完训练集群只能干等着这种“单点扩容”就是没把全链路图景吃透。2. 数据与特征层面的扩展路线是整个 Scale 的地基2.1 样本数据流水线从 T1 离线到实时特征的演进推荐系统的数据管道一开始基本都是离线 T1当天凌晨把昨天的行为日志从数仓抽出来做特征拼接、清洗、采样生成训练样本。这个方案简单可靠但样本延迟决定了模型对用户当前兴趣的感知永远滞后一天。业务发展之后大家会开始引入实时链路用户行为写入 KafkaFlink 消费并做窗口计算实时产出行为特征和实时样本再和离线特征拼接成最新训练数据。这里有几个实操细节值得补充。第一Kafka 的分区数要和下游 Flink 并发度匹配否则数据倾斜会非常严重。我遇到过一种情况某个热门商品的日志流量占了一半但它的 key 刚好集中在少数分区上导致其他分区处理完任务在空等整体吞吐上不去。第二Flink 做窗口特征时滚动窗口和滑动窗口的选择要谨慎滑动窗口能捕捉更细的短期兴趣变化但窗口重叠会带来额外的计算和存储成本。第三实时样本和离线样本的拼接要约定好时间对齐口径行为时间、样本生成时间、曝光时间这三者不能搞混否则训练数据里会出现大量“未来信息”模型在线效果直接崩掉。数据规模上去之后还要重视数据质量监控。我曾吃过一个暗亏某个上游特征因为日志字段调整连续三天产出为空离线训练没报警直到模型指标肉眼可见地下降才发现。后来我们给关键特征的缺失率、均值、分布漂移都做了自动化监控阈值触发就立刻告警这类事故基本绝迹了。2.2 特征规模化与特征平台让特征与模型解耦当特征数量从几十个涨到几百上千个时“模板代码式”的特征工程方式就不行了。每个模型把自己的特征逻辑写死在训练代码里上线新特征要改代码、发版本、重新训练协作成本极高。所以规模化的推荐团队几乎都会走向特征平台化。特征平台的核心思想是把特征的生产、存储、发布和消费统一管理起来。特征以标准化格式注册进平台标明特征来源、口径、更新频率和数据类型平台统一负责特征计算、近线存储和在线读取所有下游模型从平台订阅特征而不是各自维护一套。这个做法最直接的价值是“让特征与模型解耦”模型不再关心特征怎么来的只关心怎么用特征工程团队可以独立迭代新特征通过 AB 实验验证效果后再开放给更多模型。做特征平台时还会面对一个常见误区把所有特征都做成实时特征。实际上大部分用户长期属性性别、年龄、城市、会员等级一天更新一次就够了短期行为特征最近点击、最近收藏才需要分钟级甚至秒级更新。实时特征成本高、稳定性要求也高盲目全量实时化只会徒增系统压力。我在调研中比较认可的做法是“分层更新”静态特征走离线批更新中度活跃特征走分钟级近线更新强时效特征走实时计算。2.3 稀疏特征与 Embedding 表的横向扩展算力消耗的大头推荐系统和 CV、NLP 模型最大的不同在于输入特征大部分是稀疏的 ID 类特征。每个用户 ID、商品 ID、品类 ID、行为序列中的每个 item ID都要映射成一个稠密向量也就是 Embedding。这里的规模计算很简单Embedding 表大小 特征基数 × Embedding 维度 × 4 字节。举个例子用户 ID 做到 1 亿Embedding 维度 32光这一张表就需要 12.8 GB真实系统里往往还有商品、商家、品类、标签等多个特征加起来上百 GB 非常常见。这么大规模的稀疏参数单机内存是放不下的于是横向扩展变成了刚需。工程上常见的做法包括两类。第一类是参数服务器架构把不同特征的 Embedding 表分片放到多台 PS 节点上训练节点通过拉取和推送远程参数完成更新。第二类是纯数据并行加本地 Embedding如果单机内存还能承受也可以把全部特征表复制到每台训练节点上只对稠密参数做梯度同步这种方案在中小规模场景下实现成本更低。Embedding 规模失控时还需要做特征准入控制。比较实用的有频控过滤出现次数过低的 ID 直接丢到一个 fallback 桶统一学习“低频默认向量”还有 Hash 分桶把高基数特征哈希到固定大小的桶里牺牲一些精度换来稳定的内存占用。这两招在资源受限时优先级很高不要等到内存告急了才做。3. 模型训练层面的扩展路线从单机到分布式3.1 训练框架选型TensorFlow 生态、PyTorch 生态与深度推荐框架做技术路线调研绕不开框架选型。我的观察是推荐系统领域TensorFlow 生态仍占据很大份额原因不是 TF 比 PyTorch 更好用而是它的数据管道TFRecord、tf.data、模型导出SavedModel和在线服务TF Serving在工业推荐链路上沉淀了很多成型的工具链。PyTorch 在学术界和大型语言模型方向更活跃但很多团队表示它在超大稀疏模型上需要更多自研工作。更值得关注的是深度推荐框架的成熟度。阿里开源的 DeepRec 针对稀疏模型训练做了大量优化包括特征动态维度、Embedding 变量并发更新、混合精度支持比较适合中文互联网的海量稀疏场景Meta 的 TorchRec 则是 PyTorch 生态里做大规模推荐模型训练的利器它的 Embedding 分片策略和并行模式设计比较现代化。对于中小团队我建议不要一开始就上这类分布式框架先用通用框架把单机训练跑到极致确认规模阈值真正触到天花板后再引入专业框架迁移成本会更低。3.2 分布式训练路线PS 架构、AllReduce 与混合并行推荐分布式训练的两条技术路线是参数服务器PS和 AllReduce它们的取舍值得单独说。PS 架构下模型参数存储在一组专门的 server 节点上worker 节点负责计算梯度并与 server 通信。它的核心优势是天然适合稀疏 Embedding每个 worker 只更新它本地 batch 中出现的 ID 对应的特征参数通信量远小于全量参数同步。推荐模型的特征 ID 服从长尾分布某个 batch 的样本只会命中一小部分特征PS 架构对这种场景几乎是量身定做的。缺点是异步训练容易产生参数不一致问题需要容忍模型的“脏读”。AllReduce 架构则是把模型参数复制到每个 worker每轮迭代后通过 Ring AllReduce 做全量梯度同步。对稠密模型来说这种同步训练收敛性更好可扩展性也强但对推荐模型动辄百 GB 的 Embedding 表每轮都全量同步通信代价太高所以纯 AllReduce 并不适合大规模稀疏推荐。业界更常见的做法是混合并行稠密参数用 AllReduce 同步稀疏参数交给 PS 分布式存储各取所长。3.3 训练关键参数batch size、学习率、混合精度与数据管道训练从单机切到多机多卡时最先遇到的坑是超参变化。大批量训练有一个经典经验法则batch size 翻 N 倍学习率也要相应调整常用做法是按线性缩放比如 batch 从 1024 涨到 4096学习率从 0.001 调到 0.004 左右再配合学习率预热来稳住训练早期阶段。这个规律不是绝对的但可以作为起点然后针对自己的数据和模型做实验校准。混合精度训练能直接显著提升吞吐。稀疏 Embedding 参数用 fp32 保存稠密层的正向反向用 fp16 或 bf16 计算显存占用和计算开销都能降下来。不过要注意fp16 的精度有限某些乘法累加过程可能溢出工程上通常配合 loss scaling 使用bf16 的指数范围和 fp32 一致被很多人认为更适合训练场景。大训练集群的瓶颈往往不在计算而在数据管道。IO 侧的经验是训练样本统一转成 TFRecord 格式并且控制单个文件大小避免大量小文件导致随机 IO 飙升tf.data 里用并行读、并行 map、预取和内存缓存若 CPU 线程被数据预处理占满还要单独评估是否需要把特征预处理挪到在线侧。我曾经优化过一个训练任务把数据读取平均耗时从 300 毫秒压到 80 毫秒整体训练时间缩短了三分之一这个收益完全不需要加卡。3.4 模型结构本身的 Scale从浅层模型到多塔多模态很多人以为 Scaling Up 只是数据和算力的扩展其实模型结构本身的演进也是重要路线。早期推荐模型从 LR、FM 这类浅层模型起步特征交叉能力有限深度时代的主流路线是 DeepFM、DCN、xDeepFM 这类能够让低阶和高阶特征充分交互的模型再到 MMoE、PLE 这类多任务模型让一个系统同时优化点击、时长、转化等多个目标。序列建模的方向也值得注意。用户行为序列越长越需要 Transformer 这类能够建模长期依赖的结构这和 CV 界从 CNN 转向 ViT 的“结构 Scale”思路是相通的。推荐系统同样可以沿着“模型容量扩大、表达可更强、特征交互更充分”的路线演进。不过要提醒一句结构升级必须同步考虑推理开销一个参数量翻倍的精排模型如果线上 RT 压不住再好的离线指标都白搭。4. 在线系统的 Scaling Up召回、排序与重排的容量规划4.1 向量召回规模化双塔模型加上 ANN 索引当候选商品池达到百万甚至千万级别时精排模型已经不可能对全部候选逐一打分召回阶段的价值就凸显出来。目前最主流的规模化召回路线是双塔模型用户侧塔和商品侧塔分别把特征编码为固定维度向量离线把商品向量全量建索引线上用用户向量去检索最相似的 TopK 商品。向量检索的索引选型我调研下来最常用的是 Faiss其中 IVF 和 HNSW 两类索引很典型。IVF 先把向量空间聚类成若干个簇检索时只搜索最近的几个簇HNSW 构建多层跳表结构的邻近图检索准确率高但内存占用偏大。工程上需要在召回质量和检索速度之间找平衡nprobe 参数控制搜索簇的数量efSearch 控制图的搜索范围参数调大召回更准但延迟更高。索引更新是大规模向量召回里容易翻车的一环。新商品需要尽快进入可召回状态全量重建索引的周期往往太长业界通常采用“主从双索引”或者“全量重建 增量更新”的方式全量索引用于日常检索增量索引每几分钟或每小时更新一次定期再触发一次全量重建保证数据不会陈旧到不可接受。4.2 排序服务的性能扩展粗排、精排、重排的漏斗漏斗结构是在线推荐系统规模化的标准设计召回阶段先保证覆盖面粗排模型从几万候选里快速筛出几千精排模型对几千候选做深度打分最后重排阶段再对最终 Top 几十件做多样性和业务规则调整。这套漏斗存在的意义很简单把算力集中在最有价值的部分避免计算资源随候选量线性膨胀。粗排模型的选择很有意思。有些团队用双塔模型做粗排因为它可以复用召回的向量表示速度快有些团队直接用精排模型的蒸馏版本精度更高但代价是复杂度增加。我调研到一个比较普遍的实践是粗排尽量保持极简因为粗排阶段候选数量最大哪怕每个候选多算 1 毫秒总体延迟和吞吐都会大受影响。精排侧的算力扩展通常有两个方向一是升级 GPU 推理通过 batch 推理把多条请求打包成一个 batch充分利用 GPU 并行度二是模型量化把 fp32 模型转成 int8线上推理延迟能降到原来的三分之一甚至更低代价是几个点的精度损失需要实际评测。CPU 部署也不是不能选在低 QPS 场景、或者模型规模可控的情况下CPU 结合 AVX512 指令集优化也能跑出不错的性价比。4.3 重排与多样性的在线开销重排环节在大规模推荐场景中容易被低估。制造个比喻召回和精排负责从大海里捞出一批“好物”重排负责把这些好物摆出让人觉得舒服、不腻的货架。货架上的商品不能全部是同一种类型、同一个作者、同一个店铺否则用户刷几屏就没兴趣了。常用的 MMR 和 DPP 算法都是希望在这一步同时提升相关性和多样性。但当商品池巨大、实时点击反馈又多时重排的计算量也不可忽视。MMR 的贪心迭代时间复杂度会随着候选数和已选集变大而升高DPP 涉及矩阵分解更是计算密集。实操层面我会建议先做业务规则层面和轻量级启发式策略比如同作者限流、同品类打散、已曝光商品降权只有在规则已经不满足优化目标时再引入 DPP 这类更重的算法。重排也需要注意“用户感知体验”连续刷出极其相似的商品会让用户困惑而过度的打散又会让推荐感觉不精准这个度要靠线上指标和用户体验评测一起把握。5. 平台化与闭环让 Scaling Up 可持续运转5.1 特征、训练、上线与回流的全链路闭环推荐系统规模大了以后最怕的不是单点性能不行而是整个迭代节奏被拖垮。算法团队每天要实验新特征、新模型、新超参任何一个环节靠手工操作都撑不住。所以平台化建设不是锦上添花而是规模化的必要保障。平台化的核心目标是把“特征注册、样本生成、模型训练、离线评估、线上部署、AB 实验、日志回流”串成一条自动化的流水线。算法工程师提交一个实验配置系统自动分配资源、启动训练、产出评估结果通过评审后自动灰度上线。这里一个非常关键的工程细节是“模型签名和版本管理”线上每个部署的模型都要记录训练样本版本、特征版本、模型代码版本、数据时间范围一旦线上效果异常还要能一键回滚到上一个稳定版本。没有这套治理机制团队规模乘以模型迭代速度之后出问题根本定位不到源头。5.2 冷启动、增量学习与在线学习模型更新节奏是推荐系统规模化后必然面对的问题。传统全量训练 T1 已经无法满足实时兴趣变化而每次全量训练在超大数据集上的代价又高得吓人。增量训练因此成为一条主流路线每天基于前一天的模型继续训练只处理新增样本而不是把历史数据全部重算一遍。增量训练需要注意学习率的调整和过拟合问题否则容易在新样本上剧烈震荡。冷启动是另一个规模化后会被放大的痛点。新商品刚上线时没有反馈数据双塔模型里它的向量是随机初始化的召回基本不会命中。常用的解法包括用商品属性提前生成内容向量在向量检索时给新商品加少量探索流量以及用 bandit 算法在一部分流量上做探索。在线学习进一步打通了反馈回路点击日志实时产出训练样本近线更新模型让系统在几分钟内就能感知到用户最近的动作。但在线学习对数据质量的要求更高脏数据会在几分钟内污染线上模型必须有完善的样本校验和自动回滚机制。5.3 成本资源治理Scale 不意味着无限加机器Scaling Up 到了后期真正拉开差距的不是谁堆的机器多而是谁的单位资源产出更高。GPU 集群的利用率管理是实际痛点很多团队训练任务和推理任务混部在同一批 GPU 上互相干扰严重。常见的解法是给推理任务做资源隔离和弹性伸缩训练任务按优先级排队调度。模型侧的压缩也有很大空间。Embedding 维度压缩、hash 分桶、低频特征截断、模型蒸馏和结构化剪枝都可以让模型体积变小推理延迟降低。另一个容易被忽略的维度是“预算治理”每一次线上请求系统会在召回、粗排、精排、重排上消耗不同的算力预算超大业务量下哪怕每个请求省 1 毫秒 CPU折算成集群规模都很可观。建议团队定期做一次全链路耗时分析逐阶段看看预算花在哪里、哪些环节存在浪费。6. 常见问题与排查技巧实录6.1 一张速查表从症状到方案我把调研和实践中高频出现的故障场景整理成下表按症状、可能原因、排查动作、解决建议四列排列可以当成排查手册用。症状可能原因排查动作解决建议训练 loss 不降或发散学习率过大、特征数值范围异常检查 loss 曲线、打印特征统计分布降低学习率、做特征标准化或归一化训练吞吐上不去数据读取慢、IO 瓶颈观测 CPU 利用率与等待时间看 TFRecord 文件大小合并小文件加大 prefetch、并行 map在线 RT 突然升高推理 batch 被打散、服务排队看 P99 延迟曲线检查服务线程池打开 batch 推理、扩容、降级非核心召回路向量召回质量下降索引未更新、Embedding 版本不一致检查索引更新时间和模型版本号调整全量增量索引更新节奏离线指标好但线上差特征离线在线不一致对比离线样本与线上请求原始特征建立特征一致性校验统一特征口径大量特征缺失上游字段变更或管道断裂查数据血缘看 Kafka 消费 lag加特征质量监控配置缺失率告警这个表不可能覆盖所有问题但可以提供一个排查思路先看数据、再看模型、最后看服务这个顺序能帮你快速缩小问题范围。6.2 我最想强调的几条 Debug 经验第一永远把“离线在线一致性”放在第一位。推荐系统里很多模型上线后效果和离线评估差距巨大大部分问题都不是模型代码 BUG而是特征在离线样本和在线请求里的取值对不上。我们的做法是为每条样本保留一份特征快照线上推理时把请求特征也落一份日志定期抽样对比偏差超过阈值就报警。第二扩容的顺序要合理。我见过一个团队先把模型换成超大版本结果线上 QPS 直接被打满不得不连夜回滚。我的建议是先数据链路再训练集群最后才动在线服务每一步都要留出缓冲容量。先把地基打牢再盖高楼。第三全链路 trace 比猜更有效。当线上推荐接口变慢时与其凭感觉在召回、精排、重排之间猜不如接入一个全链路追踪系统把一次请求从网关到召回、到特征读取、到模型推理、到重排的每一段耗时都记录下来。有了数据讨论才有方向。6.3 如何选择自己团队的第一条 Scaling Up 路线技术路线调研做完了最终还是要落地。我认为选型取决于三个因素当前规模、团队技能栈、业务增长预期。如果你的团队目前是几十万级候选、几个 TB 级训练数据那最优解往往不是上分布式框架而是把单机训练优化到极致加显存、调 IO、用混合精度、优化数据管道这套打法投入小、见效快。如果数据已经到百亿级样本、模型参数过百 GB那就必须引入分布式训练框架和向量检索引擎同时开始建特征平台和数据闭环。如果你们已经在做实时推荐、在线学习、多路召回的精细运营那就是平台化建设的阶段要在实验平台、监控体系、自动回滚机制上重点投入。我在调研中反复体会到一个道理Scaling Up 不是拍脑袋做技术选型而是一次对推荐系统全链路的重新审视。与其到处收集框架和工具不如先花几天时间把数据流、训练流、服务流画清楚测出真实瓶颈在哪再带着问题去选技术路线。这个过程没有捷径但走完之后你会对推荐系统各个模块的容量边界和依赖关系有完全不一样的理解。后续的每一次升级都会更像是在一个有规划的地图上稳步推进而不是到处救火。