第十三章 数据处理管道

数据处理属于一个复杂的技术领域,为了满足越来越大的数据集的处理需求,以及密集的数据转换和快速,可靠和低成本获得结果的需求。当前广泛需要处理的数据源有很多——从移动使用统计到集成传感器网络,再到Web应用程序日志等。数据处理管道目标是将这些无限、无序、全球规模的数据集转换为结构化的索引存储,来帮助关键业务决策或解锁新产品功能。除了提供对系统和用户行为的深入了解之外,数据处理对业务而言也是至关重要。在面向用户的功能中,可能会出现管道延迟或不正确的数据。这些问题的排查成本昂贵,且需要很长时间才能修复。 本章首先使用产品示例来研究大数据处理管道的一些常见类型的应用程序。然后,我们将探索如何识别管道需求和设计模式,并列举在整个开发生命周期中管理数据处理管道的一些最佳实践。我们将介绍可以权衡优化管道和检测管道健康信号的技术。为了使服务在部署后保持稳定和可靠,SRE(以及开发人员)需要能够应对所有这些任务。理想情况下,SRE应该从早期阶段就参与这项工作:Google的SRE团队定期与开发数据处理管道的团队协商,以确保管道可以轻松发布,修改和运行,而不会给客户带来问题。

最后,Spotify案例研究概述了其事件交付处理流程,该流程管理使用内部Google Cloud和其他第三方解决方案的组合来管理复杂的业务关键型数据处理管道。无论你是直接拥有管道,还是拥有依赖于管道产生的数据的其他服务,我们希望你可以利用本章中的信息来帮助你的管道(和服务)更可靠。

有关Google数据处理管道理念的全面讨论,请参阅我们的第一本SRE手册的第25章。

管道应用

有各种各样的管道应用程序,每个应用程序都有自己的优势和使用范例。管道可以涉及多个阶段,每个阶段都是一个独立的过程,并依赖于其他阶段。一个管道也可能包含多个阶段,这些阶段使用高级规范进行抽象。云数据流就是一个很好的例子:用户使用相对高级的API编写业务逻辑,管道技术本身将这些数据转换为一系列步骤或阶段,其中一个输出是另一个的输入。为了让你了解管道应用程序的广度,接下来我们将介绍几种管道应用程序及其推荐用途。我们使用具有不同管道来实现要求的两个示例公司来演示满足其各自数据需求的不同方式。这些示例说明了特定用例如何定义项目目标,以及如何使用这些目标来明智地决定哪种数据管道最适合你的产品。

事件处理/数据转换为订单或结构数据

收集处理标准化(ETL)模型是数据处理中的常见范例:数据从源数据源中收集起来,这些数据可能是非规范化的,然后经过处理成专用格式。站在现代机器学习的角度,这可能看起来像一个认知过程:从某种传感器(实时或回放)获取数据,然后进行选择和编组,然后是“训练”特定数据结构(如机器学习网络)。

ETL管道也是以类似的方式进行工作的。数据从单个(或多个)源提取,转换,然后加载(或写入)到另一个数据源。转换阶段可以服务于各种用例,例如:

  • 更改数据格式以添加或删除字段
  • 跨数据源聚合计算功能
  • 对数据应用索引,使其具有更好的服务于基于数据的作业的特性

通常,ETL管道会存储你的数据以供进一步分析或提供给其他服务。如果使用正确,ETL管道可以执行复杂的数据操作,并提高系统的效率。 ETL管道的一些示例包括:

  • 机器学习或商业智能用例的预处理步骤
  • 计算,例如计算给定事件类型在特定时间间隔内发生的次数
  • 计算和准备账单报告
  • 索引管道,例如为谷歌网络搜索提供支持的管道

数据分析

商业智能(BI)指的是收集、集成、分析和呈现大量信息以进行更好决策的技术、工具和实践。无是零售产品,移动游戏还是物联网传感器,在多个用户或设备之间聚合数据都可以帮助进行问题定位或状态判断。

为了说明数据分析用例,让我们来看看一个虚构的公司和他们最近推出的手机和网络游戏Shave the Yak。所有者想要了解他们的用户如何在移动设备和网络上与游戏互动。作为第一步,他们生成游戏的数据分析报告,处理有关玩家事件的数据。该公司的业务负责人要求每月报告最常用的游戏功能,以便他们规划新的功能开发并进行市场分析。游戏的移动和网络分析存储在Google CloudBigQuery表中,Google Analytics每天会更新三次。团队设置了一个作业,每当新数据添加到这些表时运行。完成后,该作业将在公司的每日汇总表中进行记录。

机器学习

机器学习(ML)可用于各类领域,例如帮助预测癌症,对垃圾邮件进行分类以及为用户个性化产品推荐。通常,ML系统具有以下阶段:

  1. 数据特征及其标签是从较大的数据集中提取的。
  2. ML算法在提取的特征上训练模型。
  3. 在一组测试数据上对模型进行评估。

为了展示ML管道的实际运作,让我们看一个虚构公司Dressy的例子,该公司在网上销售服装。该公司希望通过向用户提供有针对性的建议来增加收入。当新产品上传到网站时,Dressy希望他们的系统在12小时内开始将该产品合并到用户推荐中。最终,Dressy希望在用户与网站互动时,为他们提供近乎实时的推荐,并对服装进行评分。作为推荐系统的第一步,Dressy研究了以下方法:

共同点
显示彼此相似的产品。

聚类
显示类似用户喜欢的产品。

基于内容的推荐
显示与用户查看或喜欢的其他产品类似的产品。

作为一个在线商店,Dressy拥有一组用户个人资料信息和评论,因此他们选择使用聚类过滤器。上传到他们系统的新产品没有结构化数据或一致标签(例如,一些供应商可能包括关于使用不同类别和格式的服装的颜色,尺寸和特征的额外信息)。因此,他们需要实现一个管道,将数据预处理为与TensorFlow兼容的格式,该格式连接产品信息和用户配置文件数据。 ML系统包括用于预处理来自训练模型所需的多个源的数据的管道。使用培训数据,Dressy的开发团队创建了TensorFlow模型,以便向客户提供适当的建议。图13-1显示了完整的ML解决方案。我们将详细介绍了每一步。

图13-1 ML数据处理管道

  1. 开发团队选择使用流数据流管道Google CloudDataflow,通过向返回特征列表的图像分类服务发送图像,将数据预处理为带标签的dress格式。
  2. 该团队对来自多个来源的数据进行预处理,这些数据将用于训练一个模型,该模型将返回最相似的前5条裙子。其工作流程–根据存储在BigQuery的客户资料中的服装产品数据和购买历史生成ML模型。
  3. 他们选择使用流数据管道将数据预处理为客户个性化配置文件。这些配置文件用作训练TensorFlow模型的输入。经过TensorFlow模型训练的二进制文件存储在Google云端存储(GCS)存储桶中。在部署到生产之前,团队确保该模型在对经过预处理的测试数据进行评估时满足其准确性。
  4. 服务为给定客户提供推荐内容,网络和移动设备前端进行调用。该团队使用TensorFlow和Cloud ML在线预测服务。
  5. 面向客户的前端购物服务根据预测服务提供的最新推荐为用户提供数据。

Dressy注意到,一个新模型偶尔会在24小时内无法发布,而这些推荐会引发间歇性的错误。这是第一次部署新模型时常见的问题; 然而,有一些简单的步骤可以解决这个问题。如果你发现决策、分类或推荐内容要么没有显示,要么陈旧或不正确,请问自己:

  • 在对数据进行预处理以训练模型之前,数据是否会进入管道?
  • 是否因软件错误而导致ML模型不佳?是否有很多垃圾邮件?用于训练模型的特征选择是否恰当?
  • ML模型的新版本是最近生成的,还是生产环境中仍在运行旧版本的模型?

幸运的是,Dressy有一套工具可以在客户遇到任何问题之前监控和检测问题。如果发生中断,这些工具可以帮助他们快速修复或回滚任何违规代码。有关实施监控和警报的更多详细信息,请参阅第4章。

管道最佳实践

以下管道最佳实践适用于其他作为服务运行的管道(即,负责及时正确处理数据以供其他系统调用的管道)。一套管道的部署需要多个步骤。这些步骤包括通过SLO定义和预测客户需求,优雅地故障响应和降级,编写文档以及创建在问题到达生产之前捕获问题的开发生命周期。

定义和衡量服务水平目标

自动检测管道何时不健康以及是否未能满足客户的需求非常重要。当您面临超出错误预算的危险时,接收通知(有关错误预算的详细信息,请参见第2章)有助于最小化客户影响。同时,在可靠性和特性发布之间取得一个适当的平衡是很重要的——客户会关心这两点。本节的其余部分将提供管道SLOs的示例以及如何维护它们。

数据延迟

大多数管道数据延迟SLO采用以下格式之一:

  • 以Y [秒,天,分钟]处理的X%数据。
  • 最旧的数据不早于Y [秒,天,分钟]。
  • 管道作业在Y [秒,天,分钟]内成功完成。

例如,Shave the Yak手机游戏可以选择一个SLO,要求所有影响用户分数的99%的用户动作在30分钟内反映在记分牌上。

数据正确性

为数据正确性创建SLO可确保您收到有关管道中潜在数据错误的警报。例如,计费管道中的一个正确性错误可能导致客户收取的费用过多或过少。正确性目标很难度量,特别是在没有预定义的正确输出的情况下。如果没有访问这些数据的权限,则可以生成这些数据。例如,使用测试帐户来计算预期的输出。一旦有了这个“黄金数据”,就可以比较预期输出和实际输出。从那里,您可以创建错误/差异的监控,并在测试数据流经实际生产系统时实现基于阈值的警报。

另一个数据正确性SLO涉及向后分析。例如,您可以设置一个目标,即每个季度不超过0.1%的发票是错误的。您可以为管道输出数据提供的坏数据或错误的小时/天数设置另一个SLO目标。数据正确性的概念因产品和应用而异。

数据隔离/负载均衡

有时您将拥有优先级更高或需要更多资源来处理的数据段。如果您承诺对高优先级数据进行更严格的SLO,那么务必知道,如果资源受到限制,将在低优先级数据之前处理这些数据。这种支持的实现因管道而异,但通常表现为基于任务的系统或不同作业中的不同队列。Pipeline workers可以配置为执行最高可用优先级任务。可以有多个管道应用程序或workers作业在不同配置的资源(如内存、CPU或网络层)下运行,如果在较低配置workers上失败,可以在较高配置的workers上重试。在资源或系统受限的情况下,当不可能快速处理所有数据时,这种分离允许优先处理高优先级的项,而不是低优先级的项。

端到端测量

如果您的管道有一系列的阶段,那么很容易测量每个阶段或每个组件的SLO。然而,以这种方式度量SLOs并不能捕获客户的体验或系统的端到端健康状态。例如,假设您有一个基于事件的管道,如谷歌Analytics。端到端SLO包括日志输入收集和在数据到达服务状态之前发生的任意数量的管道步骤。您可以单独监视每个阶段,并为每个阶段提供一个SLO,但是客户只关心所有阶段的总和。如果您正在为每个阶段测量SLOs,那么您将被迫加强percomponent警报,这可能会导致更多不模拟用户体验的警报。

此外,如果只在每个阶段测量数据的正确性,则可能会遗漏端到端数据损坏bug。例如,管道中的每个阶段都可以报告一切正常,但是其中一个阶段引入了一个字段,它期望下游作业处理该字段。此上游阶段假设额外的数据已被处理并用于向用户提供请求。下游作业不期望有额外的字段,因此会删除数据。两个作业都认为它们是正确的,但是用户看不到数据。

依赖服务故障的预案

一旦您定义了您的SLO,最好确认您没有过度依赖其他没有实现其产品承诺的SLOs/ sla。许多产品,如谷歌云平台,在其网站上列出了SLA承诺。一旦您确定了任何第三方依赖项,至少要为它们所宣传的sla中出现的最大故障进行设计。例如,在定义SLO时,将数据读写到云存储的管道的所有者将确保所宣传的正常运行时间和保证是适当的。如果单区域正常运行时间保证低于管道满足其数据处理时间SLO的要求,管道所有者可以选择跨区域复制数据,以获得更高的可用性

当服务提供者的基础设施破坏其sla时,结果可能会对依赖管道产生负面影响。如果您的管道依赖于比服务提供者宣传的更严格的保证,那么即使服务提供者仍然在其SLA中,您的服务也可能失败。有时候,实际规划依赖性失败可能意味着接受较低的可靠性级别,并向客户提供较宽松的SLA。

在Google,为了鼓励在管道开发时考虑到依赖故障,我们会计划中断演练。例如,Google的许多管道都依赖于运行数据中心的可用性。我们的灾难恢复测试(DiRT)经常针对这些系统,模拟区域中断。当发生区域中断时,已计划失败的管道会自动故障转移到另一个区域。其他管道被延迟,直到故障管道的操作员通过监控警告并手动做故障转移。手动故障转移成功的前提是管道可以获得足够的资源来在另一个区域中启动生产堆栈。在最佳情况下,不成功的手动故障转移会延长中断时间。在最坏情况下,处理作业可能会继续处理陈旧数据,这会在任何下游管道中引入过时或不正确的数据。此类事件的恢复策略因您的设置而异。例如,如果使用不正确的数据覆盖了正确的数据,则您可能必须从先前的备份版本还原数据并重新处理丢失的数据。

总之,为您所依赖的系统不可用的那一天做好准备是一种很好的做法。即使是最好的产品也会失败并经历不可用时期。定期执行灾难恢复方案,以确保您的系统能够适应常见和不常见的故障。评估您的依赖关系并尽可能自动化您的系统响应。

创建和维护管道文档

在编写和维护良好的情况下,系统文档可以帮助工程师可视化数据管道及其依赖关系,理解复杂的系统任务,并尽可能缩短中断时间。我们为您的管道推荐以下三类文档。

系统图

系统图(类似于图13-2)可以帮助值班的工程师快速找到潜在的故障点。在Google,我们鼓励团队绘制系统图,显示每个组件(管道应用程序和数据存储),以及每个步骤发生的转换。图中显示的每个组件和转换都有可能卡住,导致数据停止流入系统。每个组件还可能引入影响数据正确性的软件或应用程序配置bug。

系统图应包含指向不同管道阶段的其他监视和调试信息的快速链接。理想情况下,这些链接应从实时监控信息中提取,显示每个阶段的当前状态(例如,等待从属作业完成/处理/完成)。显示历史运行时信息还可以指示流水线阶段花费的时间是否超过预期。这种延迟可以预示性能下降或中断。

最后,即使在复杂的系统中,系统图也可以使开发人员更容易分析在功能启动期间应该注意的数据依赖性。

图13-2 管道系统图(PII:个人身份信息)

流程文档

记录如何执行常见任务非常重要,例如发布新版本的管道或引入数据格式的更改。理想情况下,您还应记录不太常见(通常是手动)的任务,例如新区域中的刚开始的服务启动或最终的服务关闭。在这些任务写成文档后,研究使任何手动任务自动化的可能性。如果任务和系统是自动化的,请考虑直接从源生成文档,以便保持同步。

Playbook条目

系统中的每个警报条件都应具有相应的playbook条目,该条目描述了恢复的步骤。在Google,我们发现在发送给值班的工程师的任何警报消息中链接此文档很有用。关于Playbook条目的更多信息可以参考第一本书的第11章。

管道开发生命周期

如图13-3所示,管道的开发生命周期(或对管道的更改)与其他系统的开发生命周期没有太大差别。本节遵循管道开发生命周期每个阶段的典型发布流程。

图13-3 管道开发生命周期与发布工作流程

原型

第一阶段的开发涉及管道原型设计和语义验证。原型设计可确保您表达执行管道所需的业务逻辑。您可能会发现,一种编程语言可以让您更好地表达业务逻辑,或者特定语言更容易与现有库集成。特定的编程模型可能适合您的特定用例(例如,Dataflow与MapReduce,批量与流式传输)。有关已完成的编程模型比较的示例,请参阅我们的博客文章“Dataflow / Beam&Spark:A ProgrammingModel Comparison”。如果要向现有管道添加功能,我们建议在原型阶段添加代码并运行单元测试。

用1%的适运行进行测试

完成原型后,使用生产数据在完整堆栈上运行小型设置会很有帮助。例如,使用一组实验来运行管道,或在非生产环境中运行1%的生产数据。逐步扩大规模,跟踪您的管道性能,确保您不会遇到任何瓶颈。当您的产品发布给客户时,请运行性能测试。这些测试是一个不可或缺的开发步骤,有助于预防新功能推出导致的中断。

分期

在部署到生产环境之前,在预发(或临时)环境中运行系统很有用。暂存环境中的数据应尽可能接近实际生产数据。我们建议保留生产数据的完整副本或至少保留代表性子集。单元测试不会捕获所有管道问题,因此让数据在端到端流经系统以捕获集成问题非常重要。

集成测试还可以识别错误。使用单元测试和集成测试,比较新生成的数据与先前生成的已知良好的数据。例如,在测试通过并准备好发布到生产环境之前,请检查先前版本是否存在预期或意外的差异。

金丝雀发布

与无状态作业相比,管道测试和验证需要更多的时间和精力 - 数据被持久化并且转换通常很复杂。如果您的生产版本出现问题,尽早发现问题非常重要,这样您就可以控制影响。管道使用金丝雀可以帮助降低影响!金丝雀是一个流程,您可以部署部分服务(在本例中为管道应用程序)并监控结果。有关金丝雀的更详细讨论,请参阅第16章。金丝雀与整个管道相关联,而不是与单个流程相关联。在金丝雀阶段,您可以选择处理与实时管道相同的实际生产数据,但跳过写入生产存储;两相突变等技术可以提供帮助(参见第279页的“幂等和两相突变”一节)。通常,在发现任何影响客户的问题之前,您必须等待完整的处理周期完成。在测试运行(或两阶段突变)后,将您的金丝雀管道的结果与您的实时管道进行比较,以确认其健康状况并检查数据差异。

有时可以通过金丝雀发布,逐步更新作业任务或先更新一个区域然后再更新另一个区域,但管道并不总是这样。使用复制数据的管道(例如Dataproc和Dataflow)支持区域端点并阻止这种金丝雀流程 - 您无法将一个单元格与另一个单元格隔离进行重新加载。如果运行多宿主管道,则可能无法像使用服务作业那样部署到单个区域(或一定比例的服务器)。相反,首先对一小部分数据执行首次展示,或者如前所述,首先在测试模式下推出。

在验证您的金丝雀或预发环境时,评估管道的健康状况非常重要。通常,您可以使用用于跟踪SLO的相同指标。验证您的金丝雀是一项非常适合自动化的任务。

执行分级部署

除了改变您的变更之外,您可能还希望执行分级部署,尤其是在涉及主要功能启动或更改的情况下,这些情况会可能会影响到系统和资源使用。如果不首先对实例的变更进行小范围内的测试,,就很难预测这类启动的影响您可以在管道中将分级部署实现为接受允许的数据子集的标志或配置选项。考虑首先在一个或两个帐户上处理新功能,然后逐渐增加数据量(例如,~1%,~10%,~50%,最后是100%的样本数据)。

分级部署在多个方面都可能出错:输入数据不正确或延迟,您的数据处理有错误,或者您的最终存储有错误。任何这些问题都可能导致中断。避免向低延迟前端提升损坏的数据集。目标是在这类错误被用户感知前发现并解决这类问题。

部署到生产

一旦您完全升级了新的管道二进制文件和/或配置到生产,您应该有理由相信您已经审查了任何潜在的问题(如果确实发生了问题,您的监控将提醒您)。如果部署出错,能够从已知良好状态快速恢复(例如,回滚二进制文件)并将任何可能损坏的数据标记为错误(例如,使用先前备份版本中的数据替换错误数据,请确保不要读取受影响的数据,和/或在必要时重新处理数据。

减少瓶颈点和平衡工作负载

当资源因过度访问而过载时会发生热点,从而导致操作失败。管道易受工作负载模式的影响 - 通过读取和写入 - 可能导致隔离的数据区域延迟。一些常见的热点示例包括:

  • 抛出错误,因为多个管道工作者正在访问单个服务任务,从而导致过载。
  • 由于并发访问仅在一台计算机上可用的数据而导致的CPU耗尽。通常,数据存储的内部具有最低级别的粒度,如果大量访问可能会变得不可用(例如,即使大多数数据存储都很好,Spanner平板电脑也会由于数据部分有问题而变得过载)。
  • 由于数据库中的行级锁争用导致的延迟。
  • 由于并发访问硬盘驱动器而导致的延迟,这超出了驱动器头移动速度足以快速定位数据的物理能力。在这种情况下,请考虑使用固态驱动器。
  • 需要大量资源的大型工作单元。

热点可以被隔离到数据子集。要打击热点,您还可以阻止细粒度数据,如单个记录。如果该数据被阻止,则管道的其余部分可以进行。通常,您的基础结构可以提供此功能。如果一大块处理工作消耗了不成比例的资源,那么管道框架可以通过将工作分成更小的部分来动态地重新平衡。为了安全起见,最好在客户端逻辑中建立紧急关闭,以允许您停止处理并隔离以大量资源使用或错误为特征的细粒度处理工作块。例如,您应该能够快速设置标志或推送允许您跳过与特定模式或有问题用户匹配的输入数据的配置。

其他减少热点的策略包括:

  • 重构数据或访问模式以均匀分布负载
  • 减少负载(例如,静态分配部分或全部数据)
  • 减少锁定粒度以避免数据锁争用

自动弹性伸缩和资源规划

工作量的峰值很常见,如果您没有准备就绪可能导致服务中断。自动伸缩可以帮助您处理这些峰值。通过使用自动伸缩,您无需在100%的时间内关注峰值负载(有关自动缩放的更多详细信息,请参阅第11章)。对持续运行峰值容量投入工作人员是昂贵且低效的资源使用。自动缩放会降低闲置工作人员的数量,因此您无需支付不需要的资源。此策略对于流式传输管道和可变工作负载尤为重要。批处理管道可以同时运行,并将消耗尽可能多的资源。

预测系统的未来增长并相应地分配容量可确保您的服务不会耗尽资源。权衡资源成本与提高管道效率所需的工程工作量也很重要。在进行资源规划并估算未来增长时,请记住,成本可能与运行管道工作无关。您可能还需要支付数据存储和网络带宽成本,以跨区域或跨区域写入和读取复制数据。此外,一些数据存储系统比其他系统更昂贵。即使单位存储成本很低,这些成本也会迅速增加非常大的数据集或昂贵的数据访问模式,这些模式使用存储服务器上的大量计算资源。通过定期检查数据集和修剪未使用的内容来帮助降低成本是一种很好的做法。

虽然应根据其端到端SLO来衡量一系列管道阶段的有效性,但应在每个阶段测量管道效率和资源使用情况。例如,假设您有许多使用Big-Query的作业,并注意到发布后BigQuery资源使用量的显着增加。如果您可以快速确定哪些工作负责,您可以将工作重点放在这些工作上以降低成本。

访问控制和安全策略

数据流经您的系统,并且通常会持续存在。管理任何持久数据时,我们建议您遵守以下隐私,安全和数据完整性原则:

  • 避免将个人身份信息(PII)存储在临时存储中。如果您需要临时存储PII,请确保数据已正确加密。
  • 限制对数据的访问。为每个管道阶段仅授予读取前一阶段输出数据所需的最小访问权限。
  • 为日志和PII设置生存时间(TTL)限制。

考虑一个与GCP项目相关联的BigQuery实例,该项目的访问权限可以通过Google CloudIdentity and Access Management进行管理(例如,前面描述的Dressy示例)。每个函数创建不同的项目和实例允许更细粒度的范围来限制访问。表可以具有主项目和客户端项目之间的交叉创建视图,以允许它们进行受控访问。例如,Dressy限制访问包含来自特定项目角色的作业的敏感客户信息的表。

管道升级

将管道设计为弹性非常重要,这样系统故障(如机器或区域中断)永远不会触发SLO违规页面。当您被分页时,您需要手动干预,因为所有自动化措施都已用完。如果您有明确定义的SLO以及可靠的指标和警报检测,那么在您的客户发现或报告问题之前,您会收到警报。违反SLO时,快速响应并向客户发送主动通信非常重要。

管道需求设计

今天的市场提供了许多管道技术和框架选项,并且确定哪一个最适合您的用例可能是压倒性的。一些平台提供完全托管的管道。其他人为您提供更多灵活性,但需要更多实际管理。在SRE中,我们经常在设计阶段花费大量时间来评估哪种技术最适合。我们根据用户需求,产品要求和系统约束来比较和对比各种设计选项。本节讨论可用于评估管道技术选项和改进现有管道的工具。

你需要什么功能?

表13-1提供了我们建议您在管理数据处理管道时进行优化的功能列表。其中一些功能可能已经存在于您现有的管道技术中(例如,通过托管管道平台,客户端应用程序逻辑或操作工具)。您的应用程序可能不需要某些功能,例如,如果您的工作单元是幂等的,并且可以针对相同的结果执行多次,则您不需要“仅此一次”语义。

幂等和两相突变

管道可以处理大量数据。当管道发生故障时,必须重新处理一些数据。您可以使用幂等突变设计模式来防止存储重复或不正确的数据。幂等突变是一种可以多次应用并具有相同结果的突变。实现此设计模式允许使用相同的输入数据单独执行管道,以始终产生相同的结果。

在测试或管道化管道时,您需要根据预期的输出知道管道所有者是否可以接受您应用的突变。两阶段突变设计模式可以在这里提供帮助。通常,从源读取数据并进行转换,然后应用突变。通过两阶段突变,突变本身存储在临时位置。可以针对这些潜在的突变运行单独的验证步骤(或管道)以验证它们的正确性。只有在突变通过验证后,后续管道步骤才会应用经过验证的突变。图13-4显示了两阶段突变的示例

图13-4 两相突变

检查点

通常,管道是长时间运行的进程,用于分析或改变大量数据。没有特别考虑,提前终止的管道将失去其状态,需要再次执行整个管道。对于创建AI模型的管道尤其如此,因为模型计算的每次迭代都依赖于先前的计算。检查点是一种技术,可以使管道等长时间运行的流程定期将部分状态保存到存储,以便以后可以恢复该过程。

虽然检查点通常用于故障情况,但是当作业需要被抢占或重新安排时(例如,更改CPU或RAM限制),它也很有用。工作可以干净地关闭,重新安排后,它能够检测到哪些工作单元已经处理完毕。检查点具有额外的优势,即允许管道跳过可能昂贵的读取或计算,因为它已经知道工作已完成。

代码模式

一些常见的代码模式可以使您的管道更有效地进行管理,并减少进行更改或更新所需的工作量。

重用代码

如果您运行多个类似的管道并希望实施新的监控功能或指标,则必须检测每个单独的系统。如果您使用正确的策略,这种常见的工作流程并不困难。通过实现可重用代码库,您可以在一个位置添加监控指标,并在多个管道或阶段之间共享。共享库允许您:

  • 以标准方式获取所有数据管道的洞察力。
  • 为每个管道重用其他数据分析系统(例如,适用于所有管道的流量报告)。
  • 针对多个作业提供相同的度量标准,例如通用数据新鲜度警报。

使用微服务方法创建管道

使用微服务时,让服务执行单个任务并做得很好很重要。操作一组使用相同核心库的微服务(仅在其业务逻辑上有所不同)比操作许多自定义服务更容易。类似的模式可以应用于管道。而不是创建一个单片管道应用程序,创建较小的管道,您可以单独释放和监视。这样,您将获得与微服务架构相同的好处。

管道生产准备

如第18章所述,PRR(生产准备审核)是Google SRE团队用于登录新服务的过程。本着同样的精神,我们在咨询管道技术的选择或设计时使用管道成熟度矩阵。

管道成熟度矩阵

表13-2中的矩阵测量了五个关键特征(但您可以扩展矩阵以测量您希望优化或标准化的其他特征):

  • 容错性
  • 可扩展性
  • 监控和调试
  • 透明度和易于实施
  • 单元和集成测试

成熟度矩阵代表了Google许多管道专家的集体知识。这些人员负责跨多个Google产品运行管道并生成相关系统。

每个特征的测量范围为1到5,其中1表示“混乱”(计划外,临时,有风险,完全手动),5表示“持续改进”。要对系统进行评分,请阅读下面每个特征的说明,并选择最匹配的里程碑。如果适用多个里程碑,请使用中间的分数(即2或4)。完整的评分表将为您提供系统需要改进的清晰图像。

我们建议您花时间在矩阵识别的任何薄弱区域进行改进。检测矩阵推荐的监测,警报和其他工具可能需要大量时间。在进行改进时,您可以首先查找符合您需求的现有产品或开源工具,而不是创建自己的产品。在Google,我们鼓励团队使用现有的管道技术或工具,提供开箱即用的管道支持和功能。可以重用的工具和流程越多越好。

管道故障:预防和响应

导致管道故障的原因很多,但最常见的是数据延迟和数据损坏。在Google,当发生服务中断或SLO违规时,我们会跟踪MTTD和MTTR这两个指标来进行故障定位,实践证明这两个指标在检测和修复问题方面效果显著。本节介绍一些常见的故障模式,帮助防止未来管道故障的策略。

潜在的故障模式

数据延迟

如果输入或输出延迟,管道服务是故障的。如果没有适当的预防措施,下游作业要具备可以正常运行的能力,因为陈旧数据也比不正确的数据好。如果您的管道处理不完整或数据损坏,这会将错误传播到下游。恢复或重新处理不良数据需要的时间可能会很长。相反,如果您的管道服务停止,等待数据,然后在数据可用后再恢复起来,则数据仍然是高质量的。创建所有阶段都尊重的数据依赖关系非常重要。

根据管道的类型,延迟数据的影响范围可以从陈旧的应用程序数据到停滞的管道。在批处理管道中,每个阶段等待其前任在开始之前完成。流系统更灵活:使用事件时间处理(例如Dataflow),下游阶段可以在相应的上游部分完成时立即开始一部分工作,而不是等待所有部分完成。当发生此类性质的中断时,您可能需要通知任何相关服务。如果中断是用户可见的,您可能还需要通知您的客户。

在调试管道中断时,查看当前和过去管道运行的进度以及直接链接到日志文件和数据流图表是有帮助的。在分析其计数器和统计数据时,能够通过系统跟踪工作单元也很有用。

数据损坏

如果未检测到,损坏的管道数据(输入和/或输出)可能会导致面向用户的问题。 您可以通过使用可识别损坏数据的测试,并使用可提醒您潜在损坏的逻辑来规避许多面向用户的问题。例如,管道系统可以实施阻止策略和滥用/垃圾邮件检测,以自动或手动过滤掉不良数据源。

损坏的数据可能有多种原因:软件错误,数据不兼容,不可用区域,配置错误等。修复损坏的数据涉及两个主要步骤:

  1. 通过防止进一步损坏的数据进入系统来减轻影响。
  2. 从先前已知的正常版本恢复数据,或重新处理以修复数据。

如果单个区域正在提供损坏的数据,则可能需要从该区域中耗尽服务作业和/或数据处理。 如果软件或配置错误有问题,您可能需要快速回滚相关的二进制文件。 通常,数据损坏会导致数据窗口不正确,并且一旦修复了基础问题就需要重新处理,例如修复管道二进制文件中的软件错误。要降低重新处理的成本,请考虑选择性重新处理 - 读入并仅处理受数据损坏影响的用户或帐户信息。 或者,您可以保留一些可用作检查点的中间数据,以避免从端到端重新处理管道。

如果管道的输出已损坏,则下游作业可能传播损坏的数据,或者服务作业可能会提供不正确的数据。即使有最好的测试,开发和发布实践,软件或配置错误也可能导致数据损坏。 我们建议您计划此可能性,并能够快速重新处理和恢复您的数据。 从这种数据中恢复损坏是劳动密集型的,并且难以自动化。

可能的原因

管道依赖性

当您尝试确定中断的原因时,调查管道依赖性(例如存储,网络系统或其他服务)很有用。这些依赖关系可能会限制您的请求/流量,如果资源不足,则拒绝任何新数据。 由于各种原因,输入/输出速率可能会变慢:

  • 输出接收器或存储器可能拒绝写入一段数据。
  • 可能存在无法完成的特定热点数据范围。
  • 可能存在存储错误。

某些管道依赖性问题无法自行解决。 提交故障单或错误,并留出足够的时间来添加更多资源或解决流量模式非常重要。实施负载平衡和丢弃低优先级数据可能有助于减轻影响。

管道应用程序或配置

管道故障可能是瓶颈,管道作业中的错误或配置本身的错误(例如,CPU密集型处理,性能退化,内存不足故障,易于热点的滥用数据,或者 配置指向不正确的输入/输出位置)。根据原因,有几种可能的解决方案:

  • 回滚二进制文件/配置,挑选修复程序或修复任何权限问题。
  • 考虑重组导致问题的数据。

应用程序或配置错误可能会导致数据不正确或导致数据延迟。这些错误是导致中断的最常见原因。 我们建议花时间进行流水线开发,并确保新的二进制文件和配置在非生产环境中完好无损部署。

意外的资源增长

系统负载突然和意外跳转可能导致管道故障。您可能需要其他未计划的资源来保持服务正常运行。 自动扩展应用程序作业可以帮助满足新负载的需求,但是您还应该意识到管道负载的增加也会对下游依赖性造成压力 - 您可能还需要规划更多的存储和/或网络资源。

良好的资源规划和准确的增长预测可以在这些情况下提供帮助,但这种预测可能并不总是正确的。我们建议您熟悉申请其他紧急资源的过程。 根据管道部署的性质和所需资源的数量,获取这些资源所需的时间可能很长。 因此,我们建议您准备临时解决方案以保持服务正常运行 - 例如,通过管道确定不同类别数据的优先级。

地区级中断

区域性中断对所有管道都不利,但单独的管道特别容易受到攻击。如果您的管道在突然变得不可用的单个区域中运行,则管道将停止,直到该区域重新启动。 如果您拥有具有自动故障转移功能的多宿主管道,您的响应可能就像从受影响区域中排放处理或提供服务一样简单,直到中断结束。当某个区域出现故障时,数据可能会滞留或延迟,从而导致管道输出错误。 结果,可能损害来自任何从属作业或服务的数据输出的正确性。

案例研究:Spotify

Spotify是全球领先的音乐流媒体公司。 每天,数以万计的人使用Spotify收听他们喜欢的歌曲,与朋友分享音乐,并发现新的艺术家。 本案例研究描述了我们的事件传递系统,该系统负责可靠地收集Spotify应用程序生成的数据。该数据有助于我们更好地了解最终用户,并在适当的时间为他们提供合适的音乐。 活动交付 我们将最终用户交互称为事件。每当用户收听歌曲,点击广告或跟随播放列表时,我们都会记录一个事件。 Spotify每天捕获并向我们的服务器发布数千亿个事件(多种类型)。这些事件在Spotify中有很多用途,从A / B测试分析到播放计数,为个性化发现播放列表提供支持。最重要的是,我们根据交付的活动向艺术家支付版税。我们必须拥有可靠的事件存储和交付方式。 在我们处理事件数据之前,需要收集这些数据并将其传递到持久化存储中。我们使用事件传递系统来可靠地收集和保留所有已发布的事件。事件传递系统是我们数据基础架构的核心支柱之一,因为几乎所有数据处理都直接或间接地依赖于它提供的数据。 所有传递的事件都按类型和发布时间进行分区。如图13-5所示,在任何给定时间内发布的事件被组合在一起并存储在指定的目录中,称为传递小时桶。然后将这些存储桶分组为事件类型目录。此分区方案简化了Spotify的数据访问控制,所有权,保留和使用。

图13-5 保存传递数据的小时桶 小时存储桶是我们的数据作业与事件传递系统唯一的接口。因此,我们根据每个事件类型每小时桶的运行情况来衡量性能并为我们的事件交付系统定义SLO。 事件传递系统设计和架构 我们的每小时数据库部署在Google云端存储(GCS)上。 在设计初期,我们决定将数据收集与系统内的数据交付分离。为实现这一目标,我们使用全球分布式持久化队列Google Cloud Pub / Sub作为中间层。 解耦后,数据收集和交付成为相互独立的故障域,限制了生产问题的相互影响,从而获得更具弹性的系统。图13-6描述了我们的事件传递系统的体系结构。

图13-6 事件传递系统架构 数据采集 生成的事件按事件类型分组。 每种事件类型都描述了Spotify应用程序中的用户操作。 例如,一种事件类型可以指代订阅播放列表的用户,而另一种事件类型可以表示用户开始播放歌曲。为确保单独的事件类型不会相互影响,系统具有完整的事件类型隔离。 来自不同事件类型的各个事件将发布到Google CloudPub / Sub中分配的主题。 发布由我们的微服务执行,这些微服务在Spotify数据中心和Google Compute Engine(GCE)上运行。 交付过程中,每个发布的事件流由ETL过程的专用实例处理。 提取变换加载 ETL过程负责将已发布的事件传递到GCS上正确的小时桶。 ETL过程有三个步骤/组件: 1.专用的微服务使用事件流中的事件. 2.另一个微服务将事件分配给它们的每小时分区。 3.在Dataproc上运行的批处理数据作业从其每小时分区中重复删除事件,并将它们持久保存到GCS上的最终位置. 每个ETL组件都有一个单一的职责,这使组件更易于开发,测试和操作。

数据传递

我们的客户(Spotify的其他工程团队)直接动态启用或禁用事件类型交付。 通过简单的配置控制交付。 在配置中,客户定义应交付的事件类型。当打开或关闭某种事件类型的传递时,微服务动态地获取并释放运行ETL的GoogleGCE资源。 以下代码显示了客户可以启用/禁用的示例事件类型: events: -CollectionUpdate -AddedToCollection -RemovedFromCollection 当客户能够提供新的事件类型时,我们事先并不知道需要多少资源来保证交付。因此,很难手动确定必要的资源。 为了达到最佳效果,我们使用GCE Autoscaler用于交付不同事件类型的资源利用率。

事件传递系统操作

为我们的事件传递系统定义和沟通SLO,在以下三个方面有帮助。 设计和开发 在开发我们的系统时,清晰的SLO可以为我们提供工作目标。 这些目标有助于我们做出务实的设计选择,并简化我们的系统。 确定性能问题 一旦我们的系统部署在生产环境中,SLO就可以帮助我们确定系统的哪些部分表现不佳以及我们需要集中注意的地方。 设定客户期望 SLO使我们能够管理客户期望并避免不必要的支持请求。 当客户很明确我们系统的限制时,他们有权决定如何设计,构建和运行依赖于我们数据的自己的系统。 我们为客户提供三种SLO类型用于我们的活动交付系统:及时性,完整性和偏斜(下文讨论)。 这些SLO是基于GCS提供的每小时数据桶。 为了尽可能客观,并避免使用与其无关的功能进行膨胀事件传递,我们使用独立的外部系统(例如,Datamon,下一节中介绍的数据可视化工具)测量所有SLO。 时间线 我们的及时性SLO定义为每小时数据传输的最大延迟。 交货延迟计算为铲斗交付时间与铲斗可能关闭的最早理论时间之间的时间差。 图13-7提供了此传递延迟的示例。 该图显示了12,13和14小时的桶。如果13小时的桶在14:53关闭,我们会说关闭延迟是53分钟。

图13-7. 事件时间分区 数据交付的及时性是我们用来评估数据管道性能的指标。为了测量和可视化及时性,我们使用了一个名为Datamon的工具,我们的内部数据监控工具是围绕每小时桶的概念构建的。图13-8显示了典型的Datamon UI。 每个绿色矩形(灰度,绝大多数矩形)代表按时每小时桶。灰色矩形(在右侧聚集在这里)表示尚未交付的桶,而红色矩形(最上面的3个黑色矩形)表示未在所需SLO内交付的桶。 成功交付所有小时的天数显示为单个绿色矩形。

图13-8 Datamon for Spotify的数据监控系统 下游数据作业只有在它们依赖的小时桶交付后,才能开始作业。在处理数据之前,每个数据作业都会定期检查其依赖项的传递状态。 交货延迟会影响下游工作的及时性。 我们的客户非常关注及时交付数据。 为了帮助我们确定事件发生时事件的优先顺序,我们的事件传递系统的及时性SLO分为三个优先级:高,正常和低。 我们的客户为其事件类型配置了适当的等级。 偏态 我们将偏态SLO定义为每天可能错位的最大数据百分比。偏斜(和完整性)是特定于我们的事件传递系统的概念,并不存在于我们的其他数据管道中。在我们设计事件传递系统时,为这些概念定义SLO是一个关键要求,因为它处理(以及其他事件类型)财务承载事件。对于所有其他事件,尽力而为地交付是足够好的,我们不公开相应的SLO。事件是否为财务承担由客户配置决定。 为了确定何时应该交付每小时桶,我们的事件传递系统使用启发式方法。根据定义,启发式方法并不总是完全正确的。因此,以前交付的存储桶中未传递的事件在以后可能会传递到不正确的每小时存储桶。这种错位的事件被称为倾斜。偏差可能会对工作产生负面影响,因为他们可能会首先报告偏差内容,然后在一段时间内报告价值。图13-9显示了倾斜数据传送的示例。

图13-9. 交付偏斜数据 完整性 事件在分布式系统中的多个方面丢失 - 例如,我们软件的新版本可能包含错误,云服务可能会关闭,或者开发人员可能会意外删除某些持久性事件。为确保我们收到有关数据丢失的警报,我们会衡量完整性。 我们将完整性定义为在成功发布到系统后交付的事件的百分比。我们每天报告偏度和完整性。为了衡量这些价值,我们使用内部审计系统来比较所有已发布和已交付事件的计数。报告任何不匹配,我们采取适当的措施。 为了获得SLO保证的及时性,偏斜性和完整性,我们在我们的服务器上接收时将事件分配给我们的每小时桶,而不是在客户端生成它们。如果我们的用户处于离线模式,则生成的事件可以在发布之前在客户端上缓存最多30天。此外,用户可以修改其设备上的系统时间,这可能导致时间戳不准确的事件。出于这些原因,我们使用Spotify服务器的时间戳。 我们不会通过我们的活动交付系统提供有关数据质量或事件准确性的任何SLO。我们观察到,在大多数情况下,质量取决于每个事件的内容,这些事件由我们客户的业务逻辑组成。为了使我们的系统能够根据客户数量进行扩展,我们将其专注于提供数据。在这方面,我们使用类比,事件传递应该像邮政服务:您的邮件应该按时交付,完整和未打开。我们有责任为拥有业务逻辑的内部团队提供高质量的SLO,从而了解数据的内容。 客户整合与支持 许多Spotify团队每天都与事件传递系统进行交互。 为了鼓励采用并减少学习曲线,我们采取了以下步骤来简化用户与事件传递系统的交互: 事件交付作为完全托管服务 我们希望避免将系统的复杂性暴露给客户,使他们能够专注于他们试图解决的具体问题。我们努力隐藏定义明确且易于理解的API背后的任何系统复杂性。 功能有限 为了简化API,我们仅支持一组有限的功能。事件只能以特定的内部格式发布,并且只能使用单个序列化格式传递到每小时桶。这些简单的API涵盖了我们的大部分用例。 需要明确启用每个事件的传递 当客户启用事件交付时,他们会定义事件是否为财务承担及其相关的及时性要求。此外,事件所有权需要明确定义为启用流程的一部分。我们坚信,让我们的内部团队对他们生成的事件负责会带来更高的数据质量。明确事件所有权也为我们在事件传递期间提供了明确的沟通渠道。 文档 无论与系统的交互多么简单,都需要良好的文档来提供良好的客户体验。 Subspar和陈旧文档是Spotify等快节奏公司的常见问题。 为了解决这个问题,我们将文档视为任何其他软件产品:我们团队的所有支持请求都被视为文档问题或实际产品问题。大多数支持请求都与系统的公共API相关。 我们在编写文档时尝试回答的一些问题示例包括: •如何启用事件类型的传递? •数据在何处交付? •数据如何分区? •我们的SLO是什么? •我们的客户在事故中应该得到什么样的支持? 我们的目标是在客户群增长时尽量减少我们收到的寻求支持次数。 系统监控 监控我们的SLO可以显示我们系统总体健康状况。可靠的全能监控解决方案可确保在出现问题时始终会发出警报。使用SLO违规作为监控标准的主要问题是:我们收到报警往往是在我们的客户受到影响之,为避免这种情况,我们需要对系统进行完全的监控,以便在SLO中断之前解决或缓解问题。 我们分别监控系统的各个组件,从基本系统指标开始,然后构建到更复杂的系统。例如,我们将CPU使用率监视为健康状况的信号。 CPU使用率并不总是最关键的资源,但它作为基本信号很有效。 当我们试图定位和修复生产问题时,有时系统监控是不够的。为了补充我们的监控数据,我们还维护应用程序日志。这些日志包含与其描述的组件的操作和运行状况相关的重要信息。我们非常小心,以确保我们只收集正确的记录数据的数量,因为有用的日志很容易被没有用的日志淹没。例如,错误实现的日志记录可能会记录组件中所传入的所有请求。假设大多数请求都相似,那么记录每个请求并不会增加太多价值。此外,当记录的请求太多时,很难找到其他日志条目,磁盘填满速度更快,并且我们服务的整体性能开始下降。更好的方法是对记录的请求进行速率限制,或者仅记录异常的请求(例如导致未处理异常的请求)。 通过阅读应用程序日志来调试生产中的组件是一项挑战,应该是最后的选择。 容量规划 事件传递系统的可靠性需要正确数量资源来保证,特别是因为组件被部署到单个GCP项目中并且它们共享公共配额池。我们使用容量规划来确定每个系统组件需要多少资源。 对于我们的大多数系统组件,容量规划基于CPU使用率。我们在高峰时段为每个组件配置50%的CPU使用率。该条款充当安全边际,允许我们的系统处理意外的流量突发。当Spotify运行自己的数据中心时,我们为每个组件提供了静态资源。这导致在非高峰时段浪费资源并且无法处理突增的请求。为了提高资源利用率,我们将GCE Autoscaler用于我们的一些无状态组件。 在实施Autoscaler的早期,我们有一些痛苦的经历;在某些情况下,Autoscaler会导致故障。例如,我们使用CPU使用率作为度量来执行自动缩放。自动缩放器本身依赖于CPU使用率与每个组件实例执行的工作量之间的强相关性。如果关系被破坏 - 通过向每个组件实例添加CPU的守护进程,或者由于组件实例在没有做任何工作的情况下大量使用CPU,Autoscaler将启动太多实例。 当Autoscaler的CPU使用率不断增加且与执行的工作量无关时,它将无限扩展,直到它使用它可以找到的所有资源。为防止Autoscaler耗尽我们的所有配额,我们实施了一些解决方法: •我们限制Autoscaler可以使用的最大实例数。 •我们严格限制在实例上运行的所有守护程序的CPU使用率。 •一旦检测到没有完成任何有用的工作,我们就会积极地限制组件的CPU使用率。 即使使用Autoscaler,我们也需要进行容量规划。我们需要确保我们有足够的配额,并且Autoscaler可以使用的最大实例数设置得足够高,以便在峰值期间提供流量,但又足够低以限制“失控”自动缩放的影响。

发展进程 为了快速发布新功能和改进,我们在持续集成和持续交付(CI / CD)流程之后开发了事件交付系统(如图13-10所示)。根据此流程,一旦完成,就会部署有效、经过验证或已审核的系统变更。拥有足够的测试覆盖率是每个变更成功部署的先决条件,而不会对我们的SLO产生负面影响。 我们按照“测试金字塔”的理念编写测试。这意味着对于我们的每个组件,我们都有大量的单元测试,专注于组件的内部工作 - 除了少量的集成测试,专注于组件的公共API。在测试金字塔的最高级别,我们进行了系统范围的端到端测试。在此端到端测试中,所有组件都被视为黑盒子,因此测试环境中的系统尽可能类似于生产中的系统。 在最初的开发之后,每个变化都经过同行评审。作为审核过程的一部分,所有测试都在共享CI / CD服务器上执行,结果将呈现给开发人员。只有在审阅者批准更改并且所有测试都已成功通过后,才能合并更改。合并更改后,将立即触发部署过程。 事件传递系统是Spotify基础架构中的关键组件。如果它停止提供数据,Spotify中的所有数据处理都会停止。出于这个原因,我们决定采用更保守的方法进行部署,并分阶段部署每个变更。在部署可以从一个阶段到达到另一个阶段之前,我们需要手动批准。

图13-10 发展进程 在第一个部署阶段,更改将部署到测试环境。这种低风险的分期系统无法处理生产流量。 出于测试目的,生产流量的代表性部分在临时系统中进行镜像,该系统是生产中运行的系统的副本。 在第二个部署阶段,将更改部署到生产实例或金丝雀的一小部分。只有在我们确保一切顺利进行后,我们才能执行完整的生产部署,包括分段和金丝雀(参见第16章)。 事件处理 在处理事故时,我们的首要任务是止损并恢复系统的稳定性。为避免使情况变得更糟,我们禁止在事件发生期间对我们的组件进行任何重大更改。此规则的例外情况是,如果得出结论,事件是由最近的变更引起的。此时,我们立即将系统回滚到以前的正常版本。 现在,我们遇到的最常见的操作故障是由系统故障引起的(例如,我们引入了软件错误或性能回归)或者我们所依赖的外部服务失败(例如,服务API的更新不向后兼容或服务中断其SLO)。我们使用许多经过实战考验的Google Cloud和内部Spotify服务,如Cloud Pub / Sub和Helios,以加快我们系统的开发并减少我们的运营负担。如果由外部服务引起事故,我们会有专门的随叫随到的团队提供支持。使用外部服务的一个缺点是我们自己无法解决问题。此外,将问题传达给第三方会在事件中花费宝贵的时间。即使问题出现再第三方上,但依旧会感到无能为力。 。 重负载下意外的系统行为是操作失败的另一个常见原因。在准确的生产条件下测试服务是不可能的,因此很难预测可能发生的所有边缘情况。模拟生产中组件面临的负载也很困难。重负载与无法预料的边缘情况相结合可能会导致不可预料的故障情况,例如前面“容量规划”(第295页)中介绍的Autoscaler示例。 操作系统故障可能导致我们的SLO中断。如果我们的数据新鲜度SLO被破坏,则不需要客户操作;客户必须等待他们的数据到达。但是,如果我们的偏差或完整性SLO被破坏,我们可能需要让客户参与,因为数据质量会受到影响。当我们检测到完整性或偏斜问题时,受影响的事件需要正确传递重新处理: •为了处理不完整性,需要从已知良好的最后一个检查点重新传递事件。 •为了应对过度偏斜,已经交付的事件将重新分配到正确的每小时桶中。 事件的重新传递和重新调整都是手动完成的。在交付事件被修改后,我们强烈建议客户重新处理它们以生成足够质量的数据。

总结

Spotify的事件传递系统多年来不断发展。由于之前的迭代不太可靠,我们的工程师每隔几晚都会被寻找。我们将大部分的开发时间用于事件补救和事后调查。在设计当前的版本时,我们专注于构建一个模块化的系统,它可以很好地完成一项核心任务:提供事件。此外,我们希望将事件交付作为产品提供给Spotify的其余部分。为实现这一目标,我们需要定义和满足SLO,以便为客户设定明确的期望。 我们采用一系列策略来保持服务的正常运行 - 从详细记录的通话程序到使用久经考验的外部服务(例如Goo-gle CloudPub / Sub)。此外,一个团队负责在整个生命周期内开发和运行系统。这种开发结构使我们能够利用我们从维护系统中获得的团队经验来不断改进它。 通过这些努力,我们现在拥有了一个可靠的系统,使我们能够将时间集中在满足更加雄心勃勃的完整性,偏斜性和及时性SLO上。这样可以提高可用性并改善整体客户体验。 结论 将SRE最佳实践应用于管道可帮助您进行智能设计选择并开发自动化工具,以便管道易于操作,更有效地扩展,并且更可靠。 Spotify的事件传递系统是构建管道的一个例子 并考虑到核心SRE原则,使用各种技术 - 内部,Google云和第三方 - 选择满足客户及时数据处理的需求。如果没有适当注意操作最佳实践,管道可能更容易出现故障并需要大量手动工作,尤其是在增长,迁移,功能启动或停机后清理期间。与任何复杂的系统设计一样,了解您的要求和您选择保留的SLO,评估可用技术,记录设计以及如何执行常见任务非常重要。