Facebook推出Spiral:通过实时机器学习自动调节服务
2018年06月29日 由 浅浅 发表
994877
0
对于使用Facebook的数十亿人来说,我们的服务可能看起来像是一个统一的移动应用程序或网站。公司内部的视角是不同的。Facebook使用数千种服务构建,功能从平衡互联网流量到转码图像再到提供可靠的存储。Facebook作为一个整体的效率是其个人服务效率的总和,每种服务通常都是以自己的方式进行优化,面对快节奏的变化,这些方法可能难以概括或适应。为了更有效地优化众多服务,灵活适应不断变化的互联内部服务网络,我们开发了Spiral。Spiral是一个系统,利用实时机器学习技术,为Facebook自我调节高性能基础设施服务,通过用Spiral取代手动启发式,我们可以在几分钟内优化更新的服务,而无需花费漫长的几周时间。
迎接规模挑战的新方法
作为我们持续部署过程的一部分,Facebook代码库每隔几个小时就会推出,例如新版本的前端。在这个充满活力的世界中,尝试手动微调服务以保持最高效率是不切实际的。手动重写缓存,准入,驱逐策略以及其他手动调整的启发式技术非常困难。我们必须从根本上改变对软件维护的看法。
为了有效应对这一挑战,系统需要进行自我调整,而不是依靠手动硬编码的启发式和参数。这种转变促使Facebook工程师以新的方式工作:工程师现在不用查看系统生成的图表和日志来验证正确和高效的操作,而是表达系统在代码中正确高效地运行的意义。今天,我们的工程师并没有详细说明如何计算正确的请求响应,而是编写了向自调整系统提供反馈的方法。
传统的缓存策略可能看起来像树状分支,考虑对象的大小,类型和其他元数据来决定是否缓存它。自调整缓存将以不同方式实现。这样的系统可以检查项目的访问历史记录:如果这个项目从未被访问过,那么缓存它可能并不好。在机器学习的语言中,一个使用元数据(特征)和相关反馈(标记)来区分项目的系统将相当于“分类器”。这个分类器将用于对进入缓存的项目做出决定,系统将被不断重新训练。即使在环境发生变化时,这种持续的再训练也能让系统保持最新状态。
从概念上讲,这种方法类似于声明式编程。SQL是这种方法的流行示例:工程师不必指定如何计算复杂查询的结果,而只需指定需要计算的内容,然后引擎找出最优的查询并执行它。
为系统使用声明性编程的挑战是确保目标正确完整地指定。与上面的自调整图像缓存策略一样,如果应该缓存的内容的反馈不准确或不完整,系统将很快学会提供不正确的缓存决策,这会降低性能。根据我们的经验,精确定义自调整所需的结果是使用Spiral加载最困难的部分之一。然而,我们也发现工程师在经过几次迭代之后倾向于在清晰和正确的定义上进行聚合。
Spiral:易于集成和实时预测
为了使Facebook的系统工程师能够跟上日益增长的变化步伐,Facebook波士顿办事处的工程师们构建了Spiral,这是一个小型的嵌入式C ++库,具有很强的独立性。Spiral使用机器学习为资源受限的实时服务创建数据驱动型和反应型启发式。与手动编码替代方案相比,该系统可以更快速地开发,自动维护这些服务。
与Spiral集成包括在代码中添加两个呼叫站点:一个用于预测,另一个用于反馈。预测调用站点是用于做出决策的智能启发式输出,例如“该项是否被允许进入缓存?”预测调用作为快速本地计算实现,并且在每个决策时执行。
反馈调用站点用于提供偶然的反馈,例如“这个项目在缓存中已过期,而且没有被击中,所以我们不应该缓存像这样的项目。”
该库可以在完全嵌入模式下运行,或者可以向Spiral后端服务发送反馈和统计信息,Spiral后端服务可以将有用的信息可视化以用于调试,将数据记录到长期存储以供日后分析,训练和选择在嵌入模式下资源密集型的模型。
发送到服务器的数据采样时反偏见,以避免样本中出现类不平衡偏差。例如,如果在一段时间内我们收到比正面例子多1000倍的负面例子,我们只需要在服务器上记录千分之一,,表明它的权重为1000。服务器对全局数据分布的可见性通常会导致比任何单个节点的本地模型更好的模型。这些都不需要任何设置,除了链接到库和使用上面的两个函数之外。
在Spiral中,一旦反馈进入,学习就会开始。随着更多反馈的产生,预测质量会逐步提高。在大多数服务中,反馈可在几秒到几分钟内完成,因此开发周期非常短。领域专家可以添加新功能并在几分钟内查看是否有助于提高预测质量。
与硬编码的启发式算法不同,基于螺旋的启发式算法可以适应不断变化的条件。例如,在缓存许可策略的情况下,如果某些类型的项目被请求的频率较低,则反馈将重新训练分类器,以减少接纳这些项目而不需要人为干预的可能性。
案例研究:自动化反应式缓存启发法
Spiral的第一个生产用例完全符合Phil Karlton的著名语句“计算机科学中只有两件棘手的事情:缓存失效和命名事物。”(我们已经为我们的项目准备了一个恰当的名称,所以我们实际上已经解决了高速缓存失效问题。)
在Facebook中,我们推出了反应式缓存,允许Spiral的“用户”(我们的其他内部系统)订阅查询结果。从用户的角度来看,这个系统提供了查询的结果和订阅结果。每当外部事件影响查询时,它都会自动将更新后的结果发送给客户端。这减轻了客户端的负担,并减少了计算查询结果的Web前端服务的负载。
当用户提交查询时,被动缓存首先将查询发送到Web前端,然后创建订阅,缓存并返回结果。与原始结果一起,缓存接收计算结果时触及的对象和关联列表。然后它开始监视数据库更新流,以查看访问的任何对象或关联。每当看到可能影响其中一个活动订阅的更新时,被动缓存就会重新执行查询并将结果与其缓存进行比较。如果结果确实发生了变化,它会将新结果发送给客户端并更新其缓存。
这个系统面临的一个问题是数据库更新量很大,但只有很小一部分会影响查询的输出。如果某个查询感兴趣的是“我的哪些朋友喜欢这个帖子?”,则无需持续更新,例如,当帖子最近被查看时。
这个问题类似于垃圾邮件过滤:给定一条消息,系统应该将它分类为垃圾邮件(不影响查询结果)还是有用信息(确实会影响查询结果)?第一个解决方案是手动创建静态黑名单。这是可能的,因为被动缓存工程团队认识到超过99%的负载来自一小组查询。对于小批量查询,他们只是假设所有更新都是有用信息并且重新执行查询,以查询每个引用对象的更新。对于一小批高容量查询,他们通过精心观察查询执行来创建黑名单,以确定每个对象中的哪些字段实际上影响查询的输出。这个过程通常需要工程师花几个星期时间处理每个黑名单。使事情进一步复杂化,大批量的查询不断变化,所以黑名单很快就过了时效。只要使用缓存的服务改变了它正在执行的查询,系统就必须更改垃圾邮件过滤策略,这就需要更多的工程工作。
更好的解决方案:Spiral垃圾邮件过滤
在重新执行查询之后,通过简单地将新的查询结果与旧的查询结果进行比较,可以很容易地确定观察到的更新是垃圾邮件还是有用信息。这种机制被用来向Spiral提供反馈,从而允许它创建更新的分类器。
为了确保无偏见的采样,被动缓存维护并仅提供来自一小部分订阅的反馈。缓存不会过滤对这些订阅的更新; 每当相关对象或关联被修改时,查询就会重新执行。它将新查询输出与缓存版本进行比较,然后使用该输出向Spiral提供反馈。
Spiral收集来自所有反应缓存服务器的反馈,并使用它来为每种不同的查询类型训练一个分类器。这些分类器会周期性推送到缓存服务器。为新查询创建过滤器或更新过滤器以响应Web层中的行为变化,不再需要工程团队的任何手动干预。随着新查询的反馈到来,Spiral会自动为这些过滤器创建一个新的分类器。
Spiral更快的部署和更多的机会
使用基于Spiral的缓存失效机制,在反应缓存中支持新查询所需的时间从数周减少到数分钟。在Spiral之前,反应式缓存工程师必须通过手动运行实验和收集数据来检查每个新查询的影响。然而,对于Spiral,大多数用例(映射到查询)都是在几分钟内自动获得本地模型,因此本地推断可立即使用。对于大多数使用情况,服务器可以在10到20分钟内使用来自多个服务器的数据来训练模型。一旦发布到所有单独的服务器,这个更高质量的模型可用于提高保真度推断。当查询被更改时,服务器能够适应变化并在收到更新的查询后重新学习新的重要性模式。
我们将继续致力于自动化后端服务和应用机器学习以获得更好的操作体验。Spiral潜在的未来应用包括使用贝叶斯优化的连续参数优化,基于模型的控制,针对高QPS实时服务以及离线(批量)系统的在线强化学习技术。我们将在未来的帖子中继续分享我们的工作和成果。