Netflix TechBlog | Medium 中文 笔记

笔记线程

Netflix 旨在通过个性化的视觉资产(如海报和视频预览)将会员与其喜爱的内容连接起来。对于新上线的标题,由于缺乏足够的交互数据,难以实现有效的个性化,这一问题被称为“冷启动”问题。传统上,模型将资产视为不透明的 ID,依赖流行度启发式方法,直到积累足够的数据。这意味着新内容的个性化被推迟,影响了内容发现体验。Netflix 的解决方案是利用多模态嵌入,使模型能够“看见”和“听见”这些资产。通过使用 CLIP(一种预训练的图片 - 文本模型)对海报进行编码,资产获得了视觉理解能力。该 CLIP 嵌入与资产的 ID 嵌入拼接,形成更丰富的表示,能够捕捉视觉主题和人才信息。这使得即使在没有交互历史之前,也能根据会员对视觉风格的偏好进行个性化,并促进不同标题之间的知识迁移。该方法还实现了模型整合,将针对不同海报画布的独立模型合并为单一统一模型。由于 CLIP 嵌入对裁剪和缩放具有高度不变性,近乎相同的海报渲染会映射到相似的向量。这种跨画布的交互信号聚合,尤其有利于低数据画布,使得单一模型能够为所有海报放置位置实现个性化。为解决不同画布间的数据不平衡问题,采用基于奖励的加权策略,依据交互的长期价值而非展示量进行优先级排序。该方法的成效通过离线评估(使用逆倾向得分)和大规模 A/B 测试得到验证。将图像嵌入与统一模型(V3)相结合,显著优于仅包含其中一项改进的模型。这种组合方法在 Netflix 主页重大改版期间发挥了关键作用,当时引入了一个历史数据极少的优势画布。带有 CLIP 嵌入的统一模型成功为该新布局实现了内容个性化,在发现指标和流媒体时长上均显示出具有统计显著性的提升,凸显了多模态嵌入在克服冷启动问题方面的强大能力。
Netflix 构建了一个实时分布式图,以支持其内部合作伙伴的实时洞察,本博客系列的第三部分聚焦于高效查询该图。该图是一个包含数十亿节点和边的复杂网络,对其进行查询需要一个快速且灵活的 serving 层。作者讨论了查询该图所面临的挑战,包括处理广泛的访问模式,并支持浅宽型(shallow-wide)和深窄型(deep-narrow)查询。他们阐述了如何设计一个 serving 层以高效查询该图,采用广度优先(breadth-first)方法和异步组合(asynchronous composition)来最小化延迟。作者还讨论了缓存、按需增强(opt-in enrichments)以及最终一致性(eventual consistency)在查询层设计中的重要性。查询层由三个层级组成:图查询服务(Graph Query Service)、存储抽象层(Storage Abstraction Layer)和增强层(Enrichment Layer),它们协同工作以高效执行查询。作者通过一个示例查询演示了查询层在实际中的运作方式,强调了读取和解析请求、高效从存储读取、以广度优先层级执行遍历、并行运行多个操作、智能过滤,以及利用缓存加速重复查询的重要性。查询层的目标是在 100 毫秒内完成查询,作者展示了其设计如何实现这一目标。查询层旨在每秒处理数万次查询,每次查询可能各不相同,作者讨论了在设计查询层以实现该性能水平时所做出的权衡。总体而言,作者提供了查询层设计与实施的详细概述,突出了构建大规模分布式图的高性能查询层所涉及的挑战与权衡。查询层是实时分布式图的关键组件,作者的设计与实施使 Netflix 能够为内部合作伙伴提供实时洞察。
CdXz5zHNQW_1lL53FS8TQ.png
推荐是 Netflix 体验的关键组成部分,该公司一直使用复杂的生成模型,这些模型依赖数千个手工 crafted 特征和专用架构。然而,这些模型维护与更新成本高昂,公司正寻求更高效、更有效的解决方案。大型语言模型(LLM)在此领域展现出潜力,但尚未达到生产就绪状态,且常存在局限性,例如过度推荐热门内容而忽视业务约束。为此,Netflix 构建了 GenRec,这是一个基于 LLM 的推荐排序器,通过在 Netflix 特定数据和目标上对内部基础 LLM 进行后训练来实现。GenRec 将用户历史、项目元数据和上下文 verbalize 为文本,并利用 catalog-aware 评分头对项目进行排序。该模型采用多目标损失函数进行训练,结合排序、语言和奖励信号,以对齐业务目标和长期会员满意度。与经过良好调优的生产级排序器相比,GenRec 在短期和长期在线指标上均展现出具有统计学意义的提升,同时仅使用少量标注数据和输入信号。该模型部署于 Netflix 内部 LLM 栈,使用 vLLM 进行服务,公司还实施了控制推理成本的策略,包括使用更小模型、激进的上下文压缩以及仅 prefill 推理。总体而言,GenRec 代表了 Netflix 推荐系统迈向更以 LLM 为中心未来的重要一步,其成功有望改变公司处理推荐与个性化方式。该模型从自然语言输入中学习并生成个性化排序的能力,有望提升用户体验并增加参与度。通过利用大型语言模型的力量,Netflix 能够构建更高效、更有效的推荐系统,从而推动业务成功。
CdXz5zHNQW_VHtw7eOaqU.png
Netflix 在其内部运行整个大型语言模型(LLM)栈,直接管理部署与推理。他们将此集成到现有的生产环境中,而非构建独立的机器学习孤岛。该方案涉及精心选择推理引擎、决定模型打包方式、设计 API 接口、定义部署策略以及强制输出约束。所选的推理引擎为 vLLM,因其操作适配性、支持加载自定义架构、可扩展性、可调试性以及从业人员的熟悉度而被选中。模型采用基于 Triton 的 vLLM 后端进行打包,以支持动态 I/O 张量规格,从而促进模型与前端端的独立演进。此外,在其现有的 gRPC 接口旁增加了一个兼容 OpenAI 规范的 HTTP 前端,以增强与更广泛生态系统的兼容性。在部署方面,Netflix 采用版本化(Versioned)策略来处理不同模型版本之间可能出现的模式(schema)变更,使消费者能够独立更新。当模型接口保持稳定时,则采用成本较低的蓝黑部署(Red-Black)策略。一个关键的操作挑战是模型启动时间过长,他们通过在 Amazon FSx 上预置大型模型来解决这一问题,以实现更快的访问速度。可观测性通过创建一个统一的 /metrics 端点得到提升,该端点聚合来自 vLLM 和 Triton 的数据。一个显著特性是大规模受限解码(constrained decoding),通过 vLLM 的自定义 logits 处理器实现。这使得模型能够直接生成合规输出,避免了推理后的修正步骤。受限解码的初始纯 Python 实现因全局解释器锁(GIL)以及 CPU 上的顺序处理而在扩展性上遇到困难。这一问题仅在高度并发下显现,导致显著的尾部延迟。该系统依赖 Java 控制平面来管理部署、版本控制和自动扩缩容。其服务系统同时支持实时推理和缓存的批量推理路径。这一统一系统处理完整的下游消费者流程,包括路由、候选生成和日志记录。
CdXz5zHNQW_CmjJjU7Bih.png
Netflix 开发了一项实时服务依赖图谱,以协助工程师排查问题并理解其分布式架构。该系统将 eBPF 网络流、IPC 指标和分布式追踪整合为独立的图层。初始版本虽在本地运行正常,但在生产环境中暴露出显著的扩展挑战,包括 Kafka 消费者延迟和内存问题。核心架构决策是采用以流式处理为首的方法,提供近乎实时的拓扑更新,而非每小时一次的批处理。这对于事件响应和实时事件监控至关重要。为每秒处理数百万条流记录且无数据丢失,系统采用带背压机制的反应式流,当下游系统过载时,向上传组件发出信号以减缓处理速度。这确保了优雅降级,而非崩溃或数据丢失。该架构采用多层设计,对网络、IPC 和追踪层实施物理存储隔离,从而实现独立优化。网络层的摄入依赖一个三阶段分布式聚合管道:第一阶段从 Kafka 执行初始聚合;第二阶段将网络中间件(如负载均衡器)解析为直接的应用层依赖;第三阶段负责最终聚合、与外部数据融合以及持久化到图数据库。三阶段管道是从初始两阶段设计的关键演进。初始设计因在中间件解析和富集过程中数据集中而导致“热点节点”问题。通过将职责分散到三个阶段,可均衡工作负载,避免瓶颈。此外,由于 gRPC 在大规模场景下存在性能开销,消耗过多 CPU 和内存,各阶段间的通信改用服务器发送事件(SSE)替代了 gRPC。
CdXz5zHNQW_FXxC4JJL7E.png
CdXz5zHNQW_XlipK7GYZj.gif
Netflix 正将其计算基础设施向 Kubernetes 原生模型过渡,并将 Kueue 等组件集成到其 Titus 平台中。作为一款云原生任务队列系统,Kueue 已基本取代了其自研批处理解决方案 Compute Managed Batch(CMB)中的自定义逻辑。 此次迁移的动因包括 CMB 系统已使用多年、Kubernetes 的不断演进,以及在现有系统中添加预抢占等功能日益困难。最终选择 Kueue 而非其他替代方案,是因为它与现有的 Titus 调度配置文件兼容,采用势头强劲,并且原生支持预抢占等功能。此次迁移项目名为“Netflix Batch”,旨在实现对用户零影响且不降低吞吐量。该过程涉及将作业提交重定向至已启用 Kueue 的 Titus 单元,并由 Titus 联合机制负责作业分发。 运维调整非常有限,主要涉及一个简单的 UI 开关,用于将租户注册到 Kueue 中。此注册过程将 CMB 现有的租户层次结构和容量配置转换为 Kueue 中的“Cohorts”、“ClusterQueues”和“LocalQueues”概念。关键经验教训包括:保持与旧系统的 API 兼容性以确保用户体验顺畅,以及尽早迁移复杂用例以建立信心。对 Kueue 进行负载测试以确保其能够满足 Netflix 的高吞吐量要求也至关重要,这需要对默认配置进行调整。 目前,Kueue 已全面投入运行,管理着数百万个批处理工作负载,并实现了增强的公平共享和抢占功能。这些改进有助于更好地利用预留容量、减少作业饥饿现象,并加快关键工作负载的周转速度,从而显著提高了平均资源利用率。
CdXz5zHNQW_CNU9jjDeMi.png
Netflix 的 TimeSeries Abstraction 利用 Apache Cassandra 作为存储,以毫秒级延迟摄入和查询 PB 级的时序事件数据。宽分区(即单个分区随时间累积大量事件)对时序工作负载构成重大挑战,导致 Cassandra 集群中出现高读取延迟、超时、CPU 利用率上升以及垃圾回收停顿。为此,TimeSeries 数据被划分为离散的时间块,形成可管理的段。初始的预配策略依赖用户指定的工作负载特征和蒙特卡洛模拟来确定最优的基础设施和分区配置。然而,当工作负载未知、估算不准确、随时间演变或包含数据异常值时,该方法证明不足。为自动化调整,引入了后台工作进程,用于监控分区直方图,并根据观测到的数据密度动态重新划分未来的时间片。这种时间片重划分策略在大多数数据表现出类似宽分区行为时,能有效降低读取延迟和超时。然而,该策略并未解决仅少数 ID 在表中呈现宽分区的场景。针对此类情况,以及当调用方即使面临较高延迟也需要获取全部数据时,开发了按 ID 的动态分区。该异步流水线在读取操作期间检测宽分区,并将其透明地分割为最优大小。该过程包括检测、规划与分割,以及通过重定向查询至分割后的分区来服务读取请求。检测发生在读取操作超过配置的字节阈值时,此时会向 Kafka 发出事件。系统最初专注于不可变分区以简化实现。规划阶段读取整个分区以生成分割计划,并利用检查点机制处理故障。分割涉及将数据划分委托给特定策略,例如将更多事件桶分配给时间桶。验证分割至关重要,通过校验和确保数据完整性后再标记分割完成。最后,TimeSeries 服务器使用内存中的布隆过滤器高效地将读取查询重定向至分割后的分区,使得该重定向对调用方而言几乎不可见。
CdXz5zHNQW_JhVMWuRvRR.png
Netflix 在个性化、制片厂制作、支付和广告等多个业务领域广泛采用机器学习。随着机器学习(ML)应用的扩展,一个挑战随之出现:模型与数据分散在孤岛中,阻碍了协作与发现。机器学习从业者难以理解模型血缘、特征来源及其在不同系统中的影响。这种碎片化使得关于现有特征、数据来源、管道依赖以及变更影响的查询难以获得便捷答案。核心难点在于连接生成元数据的异构机器学习基础设施组件。从管道编排器到实验平台和特征存储,数十个系统以各种格式产生数据。解决这一问题需要收集异构元数据,将其转换为统一模型,并构建一个用于探索的连接图。解决方案是元数据服务(MDS),它在 Netflix 内部构建模型生命周期图(Model Lifecycle Graph),以互联机器学习实体。MDS 实时摄入机器学习元数据,支持跨域查询,例如识别使用特定模型的实验,或共享某些特征的模型。其愿景是使公司内所有机器学习资产均可被发现、可理解且可复用。MDS 基于以下核心抽象构建:组件(Component),每个拥有唯一的 AIP URI;实体(Entity),即具有属性的机器学习专用资产;实体类型(Entity Type),定义数据形状;域(Domain),用于分组相关的实体类型;以及提供者(Provider),即来自源系统的域的具体实现。这种基于 URI 的地址机制允许任何服务以通用方式引用任何机器学习资产。构建该图的过程包含多个阶段。首先,MDS 通过 Kafka 和 AWS SNS/SQS 与源系统集成,消费表示变更的轻量级事件。专用的事件处理器处理来自管道编排、模型注册表、特征存储、实验平台和身份平台等系统的事件。其次,MDS 实现水合契约(hydration contract),验证事件并调用源系统 API 获取完整状态,随后将其转换为标准化实体。这种“变更通知”模式确保了针对事件顺序问题的鲁棒性,但会将读取负载施加到源系统上。第三,原始事件被转换为具有标准化字段的统一实体模型,为下游消费者提供一致接口。标准化实体统一字段名称和格式,并将平台特定 ID 转换为全局 AIP URI。最后,标准化实体被持久化到 Datomic 用于缓存和关系存储,同时也在 Elasticsearch 中建立索引。Datomic 凭借其不可变事实模型,支持复杂的图遍历和实体关系查询,使得跨多域查询无需低效的 N+1 查询模式。
CdXz5zHNQW_EXeyjNVmx8.png
该博客文章深入探讨了 Netflix 机器学习(ML)模型服务基础设施如何在多个领域以大规模方式支撑个性化体验的技术见解。中央 ML 模型服务平台向多个领域特定的微服务暴露了与领域无关的 API 抽象和流量路由能力,用于模型推理。这一统一的 API 加快了现有 ML 体验新版本的迭代创新速度,并支持通过 ML 实现新产品体验。ML 模型服务基础设施的成功取决于使研究人员能够快速验证新假设,并安全地将模型发布到生产环境。该平台服务于数百种模型类型和版本,每秒处理 100 万次请求,其运作层级为工作流,而不仅仅是单个评分函数。模型定义包含一组用于计算特征的必要事实,并依赖模型服务平台在推理时通过调用其他微服务来提供这些事实。调用服务仅需提供标准请求上下文和相关领域上下文,模型即可在执行流程中自行计算特征并执行推理。该平台作为快速 ML 创新的推动者,同时将 ML 模型迭代对客户端应用的暴露降至最低。平台的关键原则包括:模型创新与客户端应用解耦、客户端与模型分片解耦,以及灵活的流量路由规则。该平台使用一个名为 Switchboard 的自定义服务,作为所有流量的灵活代理层,每秒处理超过 100 万次请求,同时保持高可用性和高可靠性。Switchboard 为所有客户端的模型需求提供单一接入点,并可根据丰富的上下文特征集对请求进行路由。平台还引入了"Objective"的概念,这是由服务平台定义的一种枚举,系统中每个进入的请求都必须提供该 Objective。Objective 将客户端与具体模型解耦,并指导平台的流量路由和模型选择决策。Switchboard Rules 是一种 JavaScript 配置,允许研究人员在不修改客户端代码的情况下,将模型变体、实验和流量拆分绑定到 Objective 上。这些规则规定了给定 Objective 的默认模型、为一系列 Objective 配置的 A/B 实验,以及逐步将流量迁移到新模型的自定义策略。这些规则由 Switchboard 和模型服务集群共同消费,服务平台组件可基于这些规则采取各种操作。总体而言,该平台为 Netflix 提供了一套可扩展且灵活的 ML 模型服务解决方案,在最小化对客户端应用影响的同时,实现了快速创新与实验。
CdXz5zHNQW_XdCPf6klQA.png