大规模实时机器学习处理架构简介


Netflix 是迈向实时数据基础设施的公司的典范 ,这使得 Netflix 能够通过多种方式改善用户体验,例如改进“Trending Now”主屏幕上的推荐、快速测试生产中的更改以及最大限度地减少 Netflix 服务的停机时间。

数据处理领域的一个趋势是从批量处理数据转向连续处理流数据 ,尽管流处理带来了新的挑战,但团队还是进行了转型以获得实时洞察并做出实时决策。反过来,这可以带来更好的用户体验并创造竞争优势。

与此同时,机器学习领域在过去十年中也取得了巨大的发展。机器学习模型已成为许多领域公司提供的服务不可或缺的一部分,包括自动驾驶、动态定价和欺诈检测。然而,有效部署这些模型会带来复杂的工程挑战。

这篇文章位于实时数据基础设施和机器学习这两个领域的交叉点,这篇文章主要面向希望更好地了解底层数据管道以提供实时预测功能的数据科学家和机器学习工程师。特别是,这篇文章解决了三个主要问题:

  1. 什么是实时机器学习?
  2. 为什么实时机器学习很重要?
  3. 我们如何计算实时预测的特征?

什么是实时机器学习?
实时机器学习的关键组成部分是使用机器学习模型进行实时预测。具体来说,预测是通过同步请求进行的,并且响应预计会立即返回——大约数百毫秒,通常更短。

将此与批量预测进行对比,批量预测是一次性对大量数据点进行预测 [11,*]。预测是通过批处理作业进行的。我听说过“批处理机器学习”一词来描述这个概念,尽管它似乎并不十分流行 。 

让我们来看一个欺诈检测示例。在此示例中,消费者在线购买笔记本电脑。Visa 等信用卡网络试图检测交易是否存在欺诈行为。

使用批量机器学习范例,批量进行预测。这是可能发生的情况:

  1. 白天,交易会累积到数据仓库中。
  2. 编排器会定期(例如每晚)启动处理数据的异步批处理作业。这项工作包括从数据仓库中提取原始数据、清理数据并将其转换为特征,以及批量进行预测[ 13]。
  3. 对于预测为欺诈的交易,会发出警报。但请注意,这些交易已经被处理,因此撤销它们可能并不容易。

使用实时机器学习范例,实时进行预测。这可能如下所示:

  1. POS 系统上的交易会触发对预测服务的请求,该服务可预测交易是否欺诈。
  2. 为了进行预测,预测服务首先需要检索模型的所有相关特征。A。某些特征将使用事件本身的信息实时计算。b. 其他特征将从在线特征存储中查询。
  3. 检索到的特征被传递到模型端点以进行预测。如果预测交易是欺诈性的,则会标记该交易并阻止其进行。

为什么实时机器学习很重要?
在我们深入准备实时预测的功能之前,让我们首先了解为什么实时机器学习很重要。

实时机器学习的强大之处在于它能够帮助获得实时洞察并做出实时决策。这些信息和这些选择对于某些应用程序至关重要,可以改善其他应用程序的用户体验,并可以在其他应用程序中实现主动响应。

在我们的示例中,实时将交易标记为欺诈性交易并阻止该交易进行,比在处理欺诈性交易后尝试逆转交易要有效得多,后者可能很复杂。鉴于欺诈检测是一个价值 3850 亿美元的行业,任何财务损失的减少都可能是巨大的。

以下是受益于实时机器学习的一些应用程序的简短但绝不全面的列表:

  • 用于欺诈检测、网络安全、医疗保健监控和质量控制的异常检测。
  • 营销、电子商务、媒体和娱乐的个性化推荐。
  • 自动驾驶、高频交易和机器人技术的实时决策。

如何在实时机器学习管道中进行计算?
预测服务负责将特征传递到模型端点以执行预测。其中一些特征可以从在线特征存储中检索,而其他特征可能需要实时计算。

为实时预测准备特征的工程挑战取决于我们将使用的特征类型。

  • 我们将首先了解什么是在线特征商店,并举例说明它的外观。
  • 然后,我们将特征分为 4 组,并讨论哪些特征适合实时计算。
  • 最后,对于每个功能组,我们提出了用于计算的基本系统设计。

特征类型
对特征进行分类的最常见方法是离散(分类)与连续(数字)。然而,作为一篇专注于使功能易于实时预测的工程挑战的帖子,我想提出两个新的分类轴:

  1. 无状态与有状态
    1. 无状态特征可以使用仅基于当前事件中的信息的无状态操作来计算。计算不涉及先前请求的信息。(形式)
    2. 有状态功能需要有关先前事件或实例的知识,并且需要有状态计算。他们维持着过去的“状态”。(内容)
  2. 缓慢变化与快速变化
    1. 快速变化的特征是指即使在时间上接近的事件之间也可以快速变化的特征
    2. 缓慢变化的功能是指随着时间的推移不会改变或变化非常缓慢的功能

人们可能很容易将快速变化视为无状态,将缓慢变化视为有状态。然而,情况并非一定如此。

  1. log(交易金额):无状态且快速变化的特性。计算交易金额的日志随每笔交易而变化,并且仅需要当前请求中存在的信息。
  2. customer_age:无状态且缓慢变化的功能。顾客的年龄增长缓慢。尽管“customer_age”属性可能不在预测请求中,但我们可以使用事件中的信息(例如 customer_id)检索此特征的值。此操作被视为无状态,因为检索此功能不依赖于先前的请求。
  3. 过去 10 分钟内的交易数量:有状态且快速变化的功能。为了计算此功能,我们需要维护过去 10 分钟内客户的交易计数。此外,随着每笔新交易或当交易超出 10 分钟窗口时,计数可能会迅速变化。
  4. 过去3个月的平均交易金额:有状态且缓慢变化的特征。计算该特征需要记录客户过去3个月的交易金额。尽管新交易和时间的流逝可能会影响此特征,但特征值的大小可能会缓慢变化。这意味着可能不需要为每个传入事件更新此功能。

下面是四种类型范式,(banq注:DDD建模可借助这四个概念)

无状态且快速变化
计算无状态和快速变化的特征需要我们单独处理每个事件。对于我们的“日志(交易金额)”功能,这涉及从事件中提取交易金额并运行计算数字对数的函数。

这可以通过事件驱动的计算服务(例如 AWS Lambda)来完成。

无状态和快速变化的特征也称为实时特征,因为它们是实时动态计算的。

无状态和快速变化的特征的独特之处在于它们不是从特征存储中获取的,特征存储仅存储预先计算的值。这也意味着该实体与这些功能无关。

无状态且缓慢变化
与无状态和快速变化的特征类似,我们可以在预测时实时计算无状态和慢变化的特征。然而,由于这些特征变化缓慢,预测请求可能没有用于计算的完整信息。

以“customer_age”特征为例。由于客户的年龄每年仅变化一次,因此在每个预测请求中包含此信息可能没有意义。相反,客户年龄可能存储在数据库中的某个位置,我们需要使用预测请求中的“customer_id”来获取此信息。

因此,预先计算无状态和缓慢变化的特征并在预测时间之前将它们加载到特征存储中是有意义的。最适合此类别的功能包括那些涉及结果很少变化的常见数据库查询的功能。将预先计算的特征存储在特征存储中作为缓存查询结果可能很有用。

无状态和缓慢变化的特征也可以被视为批处理特征,因为它们通常是在批处理过程中计算的。

计算无状态和缓慢变化的特征可能涉及检索该数据仓库中的数据子集,并在必要时进行任何无状态数据清理和转换。这可以通过批处理作业来完成,批处理作业可以由编排器定期启动,并将计算出的特征值写入我们的在线特征存储。

计算可以通过Apache Spark 等批处理引擎完成。使用批处理引擎在稳健性和效率方面具有优势。Spark 具有容错能力,这意味着它可以从故障和错误中恢复,而不会丢失数据或功能。Spark 作业还可以水平扩展,即使数据大小增长也能确保及时处理

  • 然而,批处理过程中预计算功能的一个缺点是需要过多的计算和存储。因为我们不知道在运行时会遇到哪些实体值,所以我们需要计算所有可能的实体值的特征值。根据流量模式,许多计算出的特征值可能不会被使用,从而浪费计算量和特征存储中的空间。

    在我们的示例中,我们需要将所有客户的年龄加载到我们的特征存储中。但是,如果我们的功能基数很高(有许多唯一的客户 ID),那么这样做可能不切实际。

    另一种方法是在运行时查询特征值,减少特征存储中存储的特征数量,但代价是增加预测延迟。实用的解决方案可能是预先计算最常用的实体值的特征,并实时计算不太常用的实体值的特征值。

    有状态且快速变化
    计算有状态且快速变化的特征需要流处理引擎,例如Apache Flink。这将有助于我们在处理连续的信息流时进行状态管理。

    流处理引擎有助于对传入数据流进行实时数据处理。虽然批处理对于处理大型静态数据集非常有效,但它并不是为了处理有状态和快速变化的特征的动态特性而设计的

  • 对于我们的有状态且快速变化的特征“过去 10 分钟内的交易数量”[18],我们还需要更精确地计算该特征的时间。这引出了窗口的概念,它是流处理的关键组成部分。以下是三个不同的选项 [19, 20]:

    1. 翻滚窗口:每10分钟计算一次特征(与特征的窗口大小相同)。
    2. 滑动(跳跃)窗口:指定另一个持续时间,少于十分钟,用于我们计算特征的频率。例如,我们可能想每分钟计算一次特征。这意味着该特征更新更频繁并且计算窗口重叠
    3. 。翻滚窗口是滑动窗口的特殊情况,其中滑动大小与窗口大小相同。
    4. 每个事件:计算每个传入事件的特征。

    如果使用翻滚或滑动窗口计算有状态且快速变化的特征,则它们也可以被视为接近实时特征,因为它们是在预测时间之前不久计算的。但是,如果该特征是在预测时计算的,如计算每个事件时,则该特征将被视为实时特征。

    当特征的实体值不经常出现时,按事件计算就有意义。
    例如,如果特征的信用卡号很少出现,那么使用滑动窗口可能会导致计算结果不变。相反,使用滑动窗口计算特征会导致预测时的延迟较低,并且当实体值频繁出现时可以提高计算效率,但代价是特征稍微不准确。

    让我们回顾一下我们的例子。写入数据库的事务通过称为更改数据捕获 (CDC) 的过程转换为消息代理中的事件。该事件以及来自其他数据源的事件由一组流处理作业进行处理。计算出的特征值被写入我们的在线特征存储中。

    与批处理相比,由于事件时间偏差、状态管理和无界数据等方面的挑战,流处理可能更加复杂

    另一种选择是微批处理(基本上是小而离散的块的批处理),尽管它可能不实用。以下是几个原因:

    • 资源消耗和效率:由于小作业的不断创建和销毁,微批处理通常比流处理具有更高的资源开销
    • 。此外,如果多个批次包含相似的数据或需要相似的处理步骤,则使用流处理维护长时间运行的有状态作业实际上可能会更高效。我们将在下面的部分中介绍一个示例。
    • 延迟:虽然与传统批处理相比,微批处理可以减少延迟,但它无法与 Apache Flink
    • 等真正的流处理引擎提供的低延迟相匹配。
      • 例如,使用微批处理对每个事件执行计算需要为每个事件启动一个新作业,这对于实时预测来说并不可行。

    有状态且缓慢变化
    有状态和缓慢变化的特征在计算方式方面具有最大的灵活性。

    由于这些特征变化缓慢,因此批量计算它们可能是有意义的。然而,这并不是说这些特征不能用流处理引擎近实时甚至实时地计算。

    需要考虑的因素之一是该功能的新鲜度要求。如果该特征的稍微陈旧和过时的值是可以接受的,那么批处理就足够了。在这种情况下,“陈旧性”是指相对于事件时间计算特征的时间。差距越大,特征值越陈旧。
    陈旧性很重要有两个原因:
    [list=1]

  • 排除近期数据。如果最近的信息对于如何计算特征和模型性能很重要,那么拥有新数据可能至关重要。
  • 列车预测不一致。如果模型使用事件发生时计算的特征进行训练,但在预测时使用过时的特征,则可能会导致模型性能下降。确保列车预测的一致性是一个微妙的问题,将在下一篇文章中更深入地探讨。
    另一个考虑因素是每个批次期间将执行多少重复计算。例如,如果我的特征是根据过去三个月的数据计算的,那么每天晚上重新运行批处理作业来计算该特征可能会很浪费[22]。在这种情况下,有状态、长时间运行的流作业实际上可以降低成本。

    在批处理引擎和流引擎之间进行特征计算的选择可能取决于当前的用例。
    就我个人而言,我认为流处理是批处理的更通用版本,因此从长远来看转向流处理是有意义的。然而,围绕流处理和实时机器学习的数据基础设施仍然是一个发展中的领域,因此使用已建立的批处理引擎和工具可能是一个更实际的选择。

    详细点击标题