在系统升级、迁移的过程中,如何验证系统逻辑、性能正确无误,是一个很大的挑战。这一系列介绍了 Netflix 通过重放流量测试解决这一挑战的实践。原文: Migrating Critical Traffic At Scale with No Downtime — Part 2
想象一下,你被心爱的 Netflix 电视剧的最新一集迷住了,享受着不间断的高清流媒体体验。在这些完美的娱乐时刻背后是一个复杂的机制,依赖许多咬合紧密的齿轮和谐工作。但当这台机器需要改造时,会发生什么呢?这就是大规模系统迁移发挥作用的地方。之前的文章介绍了重放流量测试,这是我们工具包中的关键工具,让我们以精确、可靠的方式实现迁移。
重放流量测试为我们提供了可验证的基础,但是随着迁移过程的展开,需要仔细控制迁移流程。该流程不仅需要将风险最小化,而且还需要能够促进对迁移影响的持续评估。这篇文章将深入研究 Netflix 利用的技术是如何将变化引入到生产中的。
金丝雀组(Sticky Canaries)
金丝雀部署是一种以受控和有限的方式验证对后端生产服务更改的有效机制,可以降低由于更改而出现的不可预见后果的风险。此过程包括为更新后的服务创建两个新集群,基线集群是生产环境中运行的当前版本,金丝雀集群是服务的新版本。一小部分生产流量被重定向到这两个新集群,从而允许我们监控新版本性能,并将其与当前版本进行比较。通过收集和分析一段时间内服务的关键性能指标,可以评估新更改的影响,并确定是否满足可用性、延迟和性能需求。
某些产品功能需要通过客户设备和一组后端服务之间的请求生命周期来驱动。例如,Netflix 的视频播放功能包括从一个服务请求流的 URL、调用 CDN 下载流数据、从一个单独的服务获取解密流的许可,以及向另一个服务发送指示播放成功开始的遥测信息。如果只在被更新的服务上跟踪度量,可能无法识别更广泛的端到端系统功能中的偏差。
金丝雀组(Sticky Canary)是对传统金丝雀流程的改进,从而解决这个问题。在这种变体中,金丝雀框架创建唯一的客户设备池,在实验期间将此池的流量一致路由到金丝雀和基线集群。除了测量服务级别指标,金丝雀框架还能跟踪整个金丝雀池中更广泛的系统操作和客户指标,从而检测整个请求生命周期流的回归数据。
Sticky Canary
需要注意的是,对于金丝雀组,池中的设备在整个实验过程中被持续路由到金丝雀,这可能导致在客户设备上重试时持续存在错误行为。因此,金丝雀框架被设计为监控操作和客户 KPI 指标,以检测持续产生的偏差,并在必要时终止金丝雀实验。
金丝雀和金丝雀组是系统迁移过程中有价值的工具。与重放测试相比,金丝雀将验证范围扩展到服务级别之外,能够在该功能的请求生命周期中验证更广泛的端到端系统功能,使我们确信迁移不会对客户体验造成任何影响。金丝雀还提供了在不同负载条件下测量系统性能的机会,使我们能够识别和解决任何性能瓶颈,并帮助我们进一步微调和配置系统,确保能够顺利无缝集成新的更改。
A/B 测试
A/B 测试是一种被广泛认可的通过受控实验验证假设的方法。其做法是将一部分用户分成两个或两个以上的组,每个组采用不同方法,然后通过特定度量来评估结果,以确定假设是否有效。业内经常使用该技术来评估与产品演变和用户交互相关的假设,也被Netflix广泛用于测试产品行为和客户体验的变化。
A/B 测试对于评估后端系统的重大更改也很有价值。我们可以在设备端或后端代码中确定 A/B 测试范围,并有选择的调用新的代码路径和服务。在迁移上下文中,A/B 测试让我们能够只为较小比例的用户启用新路径,从而限制暴露迁移系统,达到控制新变更引起意外风险的目的。对于涉及到设备契约变更的架构更新来说,A/B 测试也是一项关键的迁移技术。
金丝雀实验通常在几小时到几天的范围内进行。然而在某些情况下,迁移相关的实验可能需要跨越数周或数月,以获得对特定体验质量(QoE,Quality of Experience)影响的更准确理解。此外,对特定业务关键性能指标(KPI,Key Performance Indicator)的深入分析可能需要更长时间的实验。例如,设想一个旨在提高播放质量的迁移场景,期望改进能够吸引更多客户点击播放按钮。基于相当大的样本量评估相关指标,是对假设获取可靠、自信评估至关重要的步骤。A/B 框架建立信任过程的有效工具。
除了更长持续时间,A/B 测试框架还提供了其他附属功能。比如支持基于地理、设备平台和设备版本等维度的测试分配控制,同时还允许跨维度分析迁移度量,从而确保更改不会对特定客户群产生不成比例的影响。A/B 测试还提供了适应性,允许实验过程中调整分配比例。
我们不会对每个后端迁移都用 A/B 测试。相反,我们将其用于预期更改会显著影响设备 QoE 或业务 KPI 的迁移场景。例如前面提到过的,如果变更预期会改善客户 QoE 指标,我们就用 A/B 测试来验证假设。
流量分发(Dialing Traffic)
在完成验证的各个阶段(如重放测试、金丝雀组和 A/B 测试)之后,我们可以自信断言,预期更改不会显著影响 SLA(服务级别协议,service-level-agreement)、设备级别 QoE 或业务 KPI。然而,必须确保最终推出的变更不会被未注意到的意外的问题破坏客户体验。为此,我们实现了流量分发,作为降低在生产中启用更改相关的风险的最后一步。
分发器是一种软件架构,用以控制系统内的流量。通过分布函数对入站请求进行采样,并确定应该路由到新路径还是保留在现有路径上。决策过程包括评估分布函数的输出是否在预定义的目标百分比范围内,抽样基于与请求相关联的固定参数一致的完成。目标百分比通过全局范围的动态属性来控制,可以实时更新。
分发器
实际采样参数的选择取决于具体迁移要求。分发器通过选择一个变量参数(如时间戳或随机数),对所有请求进行随机抽样。或者,在系统路径相对于客户设备必须保持恒定的场景中,基于某个恒定的设备属性(如 deviceId)作为采样参数。分发器可以在多个位置实现,例如设备应用代码、相关服务器组件,甚至是边缘 API 网关,这是管理复杂系统迁移的通用工具。
流量基于离散抽样比例分发到新系统。在每一步中,相关方都会得到通知,并监控关键指标,包括服务、设备、运营和业务指标。如果在迁移过程中发现意外问题或注意到指标朝着不希望的方向发展,分发器使我们能够快速将流量回滚到旧路径并解决问题。
如果涉及到多数据中心流量,还可以在数据中心级别限定分发范围。我们可以从单个数据中心的流量分发开始,以便更容易的跨数据中心比较关键指标,从而更容易观察到指标中的任何偏差。离散抽样的持续时间也可以调整,长时间运行分发步骤增加了暴露问题的可能性,这些问题可能只影响一小部分成员或设备,由于影响面太小而很难被捕获或者执行影子流量分析。我们可以通过逐步分发和监控的组合来完成将所有生产流量迁移到新系统的最后一步。
迁移持久化存储
有状态 API 的迁移具有特殊挑战,需要不同的策略。虽然可以用本系列前一部分中讨论的重放测试技术,但其他措施也是有必要的。
这种替代迁移策略已被证明对满足某些标准的系统是有效的。具体来说,我们的数据模型是简单、自包含、不可变的,互相之间没有耦合,因此不需要严格的一致性保证,也不使用数据库事务。我们采用基于 ETL 的双写策略,大致遵循以下步骤:
- 通过 ETL 进程完成初始加载: 从源数据存储中提取数据,转换为新模型,并通过脱机作业将数据写入新数据存储,基于自定义查询来验证迁移记录的完整性。
- 通过双写进行持续迁移: 通过双活/双写策略来迁移大量数据。作为一种安全机制,我们使用分发器(前面讨论过)来控制写入新数据存储的比例。为了在两个存储中保持状态均等,我们将实体的所有状态更改请求都写到两个存储中,实现方式是通过选择与实体生命周期保持一致的采样参数来实现。随着对系统的信心不断增强,同时仔细监控系统的整体健康状况,我们会逐步加大对新系统的使用。分发器还充当开关,在必要时关闭对新数据存储的所有写操作。
- 持续验证: 当读取一条记录时,服务从两个数据存储中读取,如果在两个存储中都找到新记录,则验证新记录的功能正确性。可以根据特定用例的延迟需求选择是在请求路径上还是离线执行比较。在实时比较的情况下,当记录匹配时,可以返回新数据存储中的记录。这个过程让我们对迁移的功能正确性建立信心。
- 迁移完整性评估: 为了验证记录完整性,使用冷存储服务定期从两个数据存储获取数据转储,并比较其完整性。数据缺失的部分用 ETL 过程填充。
- 切换和清理: 一旦验证了数据的正确性和完整性,就禁用双写和双读,清理所有客户端代码,并且读/写只发生在新数据存储中。
迁移有状态系统
清理
在迁移之后,清理任何与迁移相关的代码和配置对于确保系统平稳高效运行至关重要,并且避免增加技术债务和复杂性。一旦迁移完成并经过验证,所有与迁移相关的代码,如流量分发、A/B 测试和重放流量集成,都可以从系统中安全的删除。其中包括清理配置更改、恢复到原始设置以及禁用迁移期间添加的任何临时组件。此外,记录整个迁移过程并保存遇到的任何问题及其解决方案的记录也很重要。通过执行彻底的清理和文档编制过程,可以从迁移中吸取经验教训,从而更有效的执行未来的迁移。
最后的思考
我们已经利用文中概述的一系列技术在 Netflix 平台上进行了大量大、中、小型迁移。我们的努力在很大程度上是成功的,几乎没有遇到停机或重大问题。在整个过程中,我们获得了宝贵见解并改进了技术。应该注意的是,并非所有提出的技术都是普遍适用的,因为每个迁移都有自己独特的环境。确定适当的验证、测试和风险降低策略需要仔细考虑几个因素,包括变更的性质、对客户体验的潜在影响、工程实现和产品优先级。最终,我们的目标是实现无中断或停机的无缝迁移。
你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!