在系统升级、迁移的过程中,如何验证系统逻辑、性能正确无误,是一个很大的挑战。这一系列介绍了 Netflix 通过重放流量测试解决这一挑战的实践。原文: Migrating Critical Traffic At Scale with No Downtime — Part 1
每天都有数以亿计用户收看 Netflix,享受不间断的沉浸式流媒体体验。而在幕后有无数系统和服务参与到产品体验的编排中,这些后端系统不断发展优化,以满足并超越客户和产品的期望。
在进行系统迁移时,主要挑战之一是建立信心,在不影响客户体验的情况下将流量无缝切换到升级后的体系架构。本系列将讨论实现这一目标的工具、技术和策略。
流媒体产品后端采用了高度分布式的微服务架构,因此迁移也发生在服务调用图的不同点上。可以发生在为客户设备提供服务的边缘 API 系统上,也可以发生在边缘和中间层服务之间,或者发生在中间层到数据存储之间。另一个相关因素是,迁移可能发生在无状态和幂等的 API 上,也可能发生在有状态 API 上。
我们将用于辅助迁移的工具和技术分为两个阶段。第一阶段包括在迁移之前验证功能正确性、可伸缩性和性能问题,并确保新系统的弹性。第二阶段是在降低风险的前提下将流量迁移到新系统,同时持续监控并确认系统满足多个级别的关键指标,包括客户设备级别的体验质量(QoE,Quality-of-Experience)度量、服务级别协议(SLA,Service-Level-Agreement)和业务级别的关键性能指标(KPI,Key-Performance-Indicator)。
本文将提供对重放流量测试的详细分析,这是在多步骤迁移计划的初步验证阶段应用的一种通用技术。后续文章将重点关注第二阶段,并深入研究某些以受控方式迁移流量的战术步骤。
重放流量测试(Replay Traffic Testing)
重放流量是指被克隆并分发到服务调用图中不同路径的生产流量,允许我们以模拟实际生产条件的方式运行新的、更新的系统。在此测试策略中,我们针对系统现有版本和新版本执行生产流量的副本(重播),以进行相关验证。这种方法有几个好处。
- 重放流量测试支持大规模沙盒测试,而不会显著影响生产流量或客户体验。
- 利用克隆的真实流量,可以在生产环境中测试来自各种设备及应用版本的输入多样性,这对于具有许多高基数输入的复杂 API 尤其重要。重放流量提供了测试系统处理不经常使用的输入组合和边缘情况的能力所需的覆盖范围。
- 这种技术有助于在多个方面进行验证,允许断言功能的正确性,并提供了加载测试系统的机制,可以调优系统和可伸缩性参数以获得最佳功能。
- 通过模拟真实生产环境,可以在考虑预期和意外流量模式变化的同时,在较长时间段内刻画系统性能,很好的了解不同生产条件下的可用性和延迟范围。
- 提供能够确保相关操作见解、度量、日志记录和告警在迁移之前到位的平台。
重放解决方案
重放流量测试解决方案包括两个基本组件。
- 流量复制和关联: 初始步骤需要实现一种机制,将生产流量克隆和分发到新建立的路径上,同时还需要记录和关联来自原始和替代路由的响应。
- 对比分析和报告: 在流量复制和关联之后,需要一个框架来比较和分析从两条路径记录的响应,并获得全面的报告进行分析。
我们通过各种迁移尝试了不同的流量复制和步骤记录方法,并在此过程中进行了改进,包括在设备上、服务器上和通过专用服务生成重放流量并进行编排的选项,接下来将研究这些替代方案。
设备驱动
在此选项中,设备在生产路径和重放路径上发出请求,然后丢弃重放路径上的响应。请求并行执行,以尽量减少生产路径上的任何潜在延迟。后端重放路径的选择可以由设备在发出请求时携带的 URL 驱动,也可以通过在服务调用图适当层级的路由逻辑中利用特定请求参数来驱动。该设备还包括一个在两条路径上具有相同值的唯一标识符,用于关联生产和重放响应。响应可以在服务调用图的最优位置进行记录,也可以记录在设备本身,取决于特定迁移需求。
设备驱动的明显缺点是浪费设备资源,影响设备 QoE,特别是在低资源设备上。将分发逻辑和复杂性添加到设备代码中可能会造成对设备应用程序发布周期的依赖,设备应用发布周期通常比服务发布周期慢,从而导致迁移瓶颈。此外,允许设备执行未经测试的服务端代码路径可能会无意中暴露潜在攻击面。
服务端驱动
为了解决设备驱动的问题,另一个选项是完全在后端处理重放。重放流量在迁移服务上游的适当服务中进行克隆和分发,上游服务同时调用现有的以及新的替换服务,以最小化生产路径上的任何延迟。上游服务记录两条路径上的响应,以及用于关联响应的公共标识符。记录操作也是异步完成,以尽量减少对生产路径上延迟的任何影响。
服务端驱动的好处是,重放逻辑的所有复杂性被封装在后端,不会浪费设备资源。此外,由于逻辑驻留在服务端,可以更快迭代任何所需更改。然而,仍然需要在处理业务逻辑的生产代码旁边插入与重放相关的逻辑,这可能导致不必要的耦合和复杂性。重放逻辑中的 bug 也有可能影响产品代码和指标,同样增加了风险。
专用服务
最新方法是将所有重放流量组件完全隔离到一个单独的专用服务中。在这种方法中,我们将需要异步更新或替换为脱机事件流的服务请求和响应记录下来(这种请求和响应的日志记录通常已经因为运维分析的需求而记录了下来)。随后,我们使用分布式流处理器Mantis来捕获这些请求和响应,并针对新的服务或集群重放请求,对请求进行任何必要的调整。在重放请求之后,此专用服务还记录来自生产和重放路径的响应,以便进行脱机分析。
这种方法将重放逻辑集中在独立的专用代码库中。除了不消耗设备资源和不影响设备 QoE 之外,这种方法还减少了生产业务逻辑和后端重放流量逻辑之间的耦合,将重放框架上的任何更新从设备和服务发布周期中解耦了出来。
重放流量分析
一旦运行了重放流量并记录了具有统计意义的响应量,就可以进行重放流量测试的比较分析和报告。考虑到使用重放流量生成的数据的规模,我们使用Apache Iceberg等技术将数据记录在具有成本效益的冷存储设备上。然后可以创建脱机分布式批处理作业来关联和比较生产和重放路径上的响应,并生成详细的分析报告。
规一化(Normalization)
根据正在迁移的系统的性质,响应可能需要在比较之前进行一些预处理。例如,如果响应中的某些字段是时间戳,则这些字段将有所不同。类似的,如果响应中有未排序的列表,最好在比较之前进行排序。在某些迁移场景中,可能会有意更改更新后的服务或组件生成的响应。例如,在原始路径中是列表的字段在新路径中表示为键值对。在这种情况下,我们可以对重放路径上的响应应用特定转换,以模拟预期更改。基于系统和相关响应,在比较响应之前,可能会对响应应用其他特定的规一化操作。
比较
归一化后,对两边响应进行比较,检查是否匹配。批处理作业会创建一些能够获取某些关键比较指标的高级摘要,包括双方响应总数、由相关标识符连接的响应计数、匹配或者不匹配。摘要还记录了每条路径上成功、失败响应的数量。摘要提供了分析的高级视图,以及整个生产和重放路径的总体匹配率。此外,对于不匹配的情况,我们将双方的规一化和非规一化响应以及其他相关参数(如 diff)记录到另一个大数据表中,这些额外的日志记录可以用来调试和识别导致不匹配问题的根本原因。一旦发现并解决了这些问题,就可以迭代使用重放测试过程,将不匹配的百分比降低到某个可接受的数字。
追溯(Lineage)
比较响应时,一个常见的噪声源来自于利用非确定性或非幂等的依赖数据生成生产和重放响应。例如,某个负责为播放会话提供媒体流响应的有效负载的服务需要查询元数据服务,获取给定标题的所有可用流。有各种因素可能造成流的添加或删除,例如识别到特定流有问题、合并对新语言的支持、引入了新的编码。因此,用于确定生产和重放路径上有效载荷的流的集合可能会不一样,从而导致不同的响应。
生成响应所涉及所有依赖项数据版本或校验和的综合摘要,称为追溯,以解决这一问题。通过比较分析响应的自动化作业中的生产响应和重放响应的追溯,可以识别和丢弃差异。这种方法降低了噪声的影响,并确保生产和重放响应之间准确可靠的比较。
比较实时流量
记录响应并离线执行比较的另一种替代方案是执行实时比较。在这种方法中,对上游服务的重放流量进行分叉,如"服务端驱动"部分所述。派生和克隆重放流量的服务直接比较生产和重放路径上的响应,并记录相关指标。如果响应负载不是很复杂,比较就不会显著增加延迟。如果正在迁移的服务不在关键路径上,那么这个选项是可行的。在新旧响应不匹配的情况下,日志记录是可选择的。
压力测试
除了功能测试,重放流量放我们可以对更新的系统组件进行压力测试。可以通过控制被重放的流量以及新服务的水平和垂直扩容因子来调节重放路径上的负载。这种方法让我们可以评估新服务在不同流量情况下的表现,可以看到可用性、延迟和其他系统性能指标(如 CPU 消耗、内存消耗、垃圾收集率等)如何随着负载因子的变化而变化。用这种技术对系统进行负载测试,能够基于实际的生产流量模式识别性能热点,有助于暴露内存泄漏、死锁、缓存问题和其他系统问题,能够支持线程池、连接池、连接超时和其他配置参数的调优。此外,还有助于确定合理的扩容策略,并对相关成本和更广泛的成本/风险权衡进行估计。
有状态系统
到此为止,我们已经广泛利用重放测试来建立对无状态和幂等系统的迁移信心。重放测试还可以验证有状态系统的迁移,只是必须采取额外的措施。在启用流量重放之前,生产路径和重放路径必须具有不同且隔离的数据存储,这些数据存储处于相同的状态。此外,必须重放驱动状态机的所有不同请求类型。在记录步骤中,除了响应,还需要捕获与该特定响应相关联的状态。相应的,在分析阶段,需要比较状态机中和响应相关的状态。考虑到对有状态系统使用重放测试的总体复杂性,我们在这种情况下采用了其他技术,将在后续文章中介绍。
总结
我们在 Netflix 的许多迁移项目中采用了重放流量测试。最近的例子是利用重放测试来验证驱动产品重放组件的边缘 API 的广泛重构。另一个实例包括将中间层服务从 REST 迁移到 gRPC。在这两种情况下,重放测试促进了全面的功能测试、负载测试和使用实际生产流量进行大规模系统调优。这种方法使我们能够识别难以捉摸的问题,并在这些实质性的重新设计中迅速建立信心。
在完成重放测试之后,就准备在生产环境中引入这些更改。在接下来的文章中,我们将介绍一些技术,以逐步控制风险的方式将系统的重大变化推出到生产中,同时通过不同级别的指标建立信心。
你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!