当前位置: 首页 > 科技观察

Netflix应用程序架构:用于个性化和推荐的系统架构

时间:2023-03-12 11:09:43 科技观察

在本文中,我们探讨了如何创建能够交付和支持快速创新的软件架构。提出一个可以处理大量现有数据、响应用户交互并轻松试验新推荐方法的软件架构并非易事。在这篇文章中,我们描述了我们如何解决Netflix面临的一些挑战。首先,我们在下图中展示了推荐系统的整体系统图。该体系结构的主要组件包含一种或多种机器学习算法。我们可以对数据做的最简单的事情就是存储它以供以后离线处理,这导致了管理离线作业的架构部分。但是,可以离线、近线或在线进行计算。在线计算可以更好地响应最近的事件和用户交互,但必须实时响应请求。这会限制所用算法的计算复杂度以及可处理的数据量。离线计算对数据量和算法计算复杂度的限制较小,因为它以批处理方式运行,对时间要求相对宽松。但是,由于它不包含最新数据,因此在更新过程中很容易变得陈旧。个性化架构中的一个关键问题是如何以无缝方式组合和管理在线和离线计算。近线计算是这两种模式的折衷,我们可以进行类似于在线的计算,但不要求它们是实时的。模型训练是另一种计算形式,它使用现有数据生成模型,稍后在实际计算结果时使用该模型。该架构的另一部分描述了事件和数据分发系统需要如何处理不同类型的事件和数据。一个相关的问题是如何组合离线、近线和在线系统所需的不同信号和模型。最后,我们还需要弄清楚如何以对用户有意义的方式组合中间推荐结果。本文的其余部分将详细介绍此体系结构的这些组件及其交互。为此,我们将把总图分解成不同的子系统,并详细讨论每个子系统。当您继续阅读本文时,请记住我们的整个基础设施都在公共AmazonWebServices云上运行。离线、近线和在线计算如上所述,我们算法的结果可以在线实时计算、离线批量计算或介于两者之间的近线计算。每种方法都有其优点和缺点,每个用例都需要考虑这些优点和缺点。在线计算可以快速响应事件并使用最新数据。例如,为使用当前上下文的成员组装一个动作电影库。在线组件受可用性和响应时间服务水平协议(SLA)的约束,该协议规定了在我们的会员等待建议出现时响应客户应用程序请求的最大延迟。这使得用这种方法来适应复杂和计算密集型算法变得更加困难。此外,纯在线计算在某些情况下可能无法满足其SLA,因此考虑快速回退机制(例如恢复到预先计算的结果)始终很重要。在线计算还意味着所涉及的各种数据源也需要在线可用,这可能需要额外的基础设施。另一方面,离线计算在算法途径上有更多的选择,比如复杂的算法,对使用的数据量的限制也更少。一个简单的例子可能是定期汇总来自数百万电影播放事件的统计数据,以编译推荐的基线流行度指标。离线系统也有更简单的工程要求。例如,可以轻松满足客户强加的宽松响应时间SLA。可以在生产中部署新算法,而无需在性能调整上付出太多努力。这种灵活性支持敏捷创新。在Netflix,我们利用这一点来支持快速实验:如果新的实验算法执行缓慢,我们可以选择简单地部署更多AmazonEC2实例来达到运行实验所需的吞吐量,而不是将宝贵的工程时间花费在算法优化上性能,可能没有什么商业价值。然而,由于离线处理没有很强的延迟要求,它不会对上下文或新数据的变化做出快速反应。最终,这会导致过时和会员体验下降。离线计算还需要基础设施来存储、计算和访问大型预计算结果集。近线计算可以看作是前两种模型之间的折衷。在这种情况下,计算的执行与在线情况完全相同。但是,我们不再需要在计算结果时立即提供结果,并且可以存储它们,从而允许它是异步的。近线计算是基于用户事件执行的,因此系统可以在请求之间更快地响应。这为可能对每个事件进行更复杂的处理打开了大门。例如,更新建议以反映在成员开始观看电影后立即观看了电影。结果可以存储在中间缓存或后端存储中。近线计算也是应用增量学习算法的自然环境。无论如何,在线/近线/离线处理的选择不是一个非此即彼的问题。所有方法都可以而且应该结合起来。有很多方法可以组合它们。我们已经提到了使用离线计算作为备份的想法。另一种选择是使用离线过程预先计算部分结果,将算法中成本较低或上下文敏感的部分留给在线计算。甚至建模部分也可以离线/在线混合方式完成。在传统的监督分类应用中,分类器必须从标记数据中批量训练,并且只能在线应用于对新输入进行分类,这不是天作之合。然而,矩阵分解等方法更适合在线/离线混合建模:一些因素可以离线预先计算,而其他因素可以实时更新以创建更新鲜的结果。其他无监督方法,如聚类,也允许离线计算集群中心并在线分配集群。这些示例表明,一方面,可以将我们的模型训练划分为大规模、可能复杂的全局模型训练,另一方面,可以将更宽松的特定于用户的模型训练或更新阶段在线进行。离线作业在运行个性化的机器学习算法时,我们需要做的大部分计算都可以离线完成。这意味着可以安排作业定期执行,并且它们的执行不需要与结果的请求或表示同步。此类任务主要分为两类:模型训练和中间或最终结果的批量计算。在模型训练工作中,我们收集相关的现有数据,应用机器学习算法生成一组模型参数(我们称之为模型)。这个模型通常会被编码并存储在一个文件中以备后用。虽然大多数模型都是离线以批处理模式训练的,但我们也有一些在线学习技术,其中增量训练确实是在线进行的。批量计算结果就是上面定义的离线计算过程,我们使用已有的模型和对应的输入数据来计算结果,用于后续的在线处理或者直接呈现给用户。这两项任务都需要处理精炼数据,这些数据通常是通过运行数据库查询生成的。由于这些查询在大量数据上运行,因此以分布式方式运行它们是有益的,这使得它们非常适合通过Hive或Pig作业在Hadoop上运行。查询完成后,我们需要一种机制来发布结果数据。我们对这个机制有几个要求:首先,它应该在查询结果准备好时通知订阅者。其次,它应该支持不同的存储库(例如,不仅是HDFS,还支持S3或Cassandra)。最后,它应该透明地处理错误,允许监控和警报。在Netflix,我们使用一个名为Hermes的内部工具来提供所有这些功能,并将它们集成到一个一致的发布-订阅框架中。它允许向订阅者提供近乎实时的数据。从某种意义上说,它涵盖了一些与ApacheKafka相同的用例,但它不是消息/事件队列系统。信号和模型无论我们是在线计算还是离线计算,我们都需要考虑算法将如何处理三个输入:模型、数据和信号。模型通常是先前离线训练的小参数文件。数据是已经存储在某种数据库中的预处理信息,例如电影元数据或受欢迎程度。我们使用术语“信号”来指代我们输入算法的新信息。此数据来自实时服务,可以包含与用户相关的信息(例如成员最近观看的内容)或上下文数据(例如会话、设备、日期或时间)。事件和数据分发我们的目标是将会员互动数据转化为可用于改善会员体验的见解。因此,我们希望Netflix的各种UI应用(智能电视、平板电脑、游戏机等)不仅能提供愉悦的用户体验,还能收集尽可能多的用户事件。这些动作可以与点击、浏览、查看,甚至随时查看的内容有关。然后可以聚合事件以为我们的算法提供基本数据。在这里,我们试图区分数据和事件,尽管边界肯定是模糊的。我们将事件视为时间敏感信息的小单元,需要以尽可能短的延迟进行处理。这些事件被路由以触发后续操作或流程,例如更新近线结果集。另一方面,我们将数据视为更密集的信息单元,可能需要对其进行处理和存储以备后用。在这里,延迟不如信息的质量和数量重要。当然,一些用户事件可以同时作为事件和数据处理,因此可以发送到两个流。在Netflix,我们近乎实时的事件流通过称为曼哈顿的内部框架进行管理。曼哈顿是一个分布式计算系统,是我们推荐算法架构的核心。它有点类似于Twitter的Storm,但它解决了不同的问题并响应了一组不同的内部需求。数据流主要通过从Chukwa到Hadoop的日志记录来管理,以完成流程的初始步骤。后来,我们使用Hermes作为发布订阅机制。推荐结果我们的机器学习方法的目标是进行个性化推荐。这些推荐结果可以直接从我们之前计算好的列表中得到,也可以通过在线算法动态生成。当然,我们可以考虑同时使用这两种方法,离线计算大部分推荐内容,并使用实时信号在线算法对列表进行后处理,从而增加一些新鲜感。在Netflix,我们将离线和中间结果存储在各种存储库中,以供日后需要时使用:我们使用的主要数据存储库是Cassandra、EVCache和MySQL。每种解决方案都有其优点和缺点。MySQL允许存储将来可能需要通过常见查询处理的结构化关系数据。然而,这种普遍性是以分布式环境中的可扩展性问题为代价的。Cassandra和EVCache都提供键值存储的优势。当需要分布式和可扩展的无SQL存储时,Cassandra是一个众所周知的标准解决方案。Cassandra在某些情况下运行良好,但在我们需要密集和持续写入操作的情况下,我们发现EVCache更适合。然而,关键问题不是将它们存储在何处,而是如何以在每个用例的最佳点满足相互冲突的目标(例如查询复杂性、读写延迟和事务一致性)的方式来处理需求。结论在之前的文章中,我们强调了数据、模型和用户界面对于创建世界级推荐系统的重要性。在构建这样一个系统时,还必须考虑部署该系统的软件架构。我们希望能够使用可以增长到任意复杂度并能够处理大量数据的复杂机器学习算法。我们还需要一个允许灵活和敏捷创新的架构,可以轻松开发和插入新方法。此外,我们希望我们的推荐结果是新鲜的,并对新数据和用户操作做出快速响应。找到这些需求之间的最佳平衡点并非易事:它需要对需求进行深思熟虑的分析、谨慎选择技术以及对推荐算法进行战略性分解,以便为我们的会员实现最佳结果。