微服务使我们可以更快地发展并缩短实现价值的时间 。 但是,我们不能天真地快速行动并破坏事物 。 我们需要一种方法来降低进行更改的风险,并在此过程中更安全地将新更改引入生产。 一种有助于降低将变更投入生产的风险的强大模式是将生产流量隐藏到测试集群或我们的软件的新版本中, 然后在将实时流量(即客户流量)定向到其之前对它进行测试,以检查是否存在问题。 这样,我们就可以将真实生活的用例发送给我们的代码,使使用情况变得晦涩难懂,从而使非生产模拟中的测试可能无法捕获。 我在上一篇文章中介绍了Istio Service Mesh如何具有很好的功能来镜像流量 。 实际上,关于Istio和Service Mesh , 实际上我有很多话要说 ,所以请随时关注@christianposta ,以了解最新信息。 现在进入主要课程:
遮挡交通的问题
当我们将实时生产流量屏蔽到测试群集或生产中的黑暗群集时,我们将面临一些挑战。 首先,我们如何在不影响生产服务的关键路径的情况下将流量发送到该群集? 我们是否需要从这些请求中过滤出个人信息? 我们如何包含测试集群以不干扰实时协作者服务? 如果我们的服务对数据进行更改,我们如何隔离这些更改而不影响生产?
这些都是真正的挑战,可以用作不尝试屏蔽流量的原因。 恕我直言,遮蔽是执行安全释放的一种较重要且功能强大的技术,因此,让我们看一下解决其中一些问题的几种模式。 模式如下所示:
- 在不影响关键路径的情况下将流量引导到测试集群
- 将流量注释为阴影流量
- 阴影后将实时服务流量与测试群集进行比较
- 为某些测试配置文件提供协作服务
- 综合交易
- 虚拟化测试集群的数据库
- 实现测试集群的数据库
让我们深入。
在不影响关键路径的情况下将流量引导到测试集群
可以说这是最重要的部分。 如果我们不能可靠地屏蔽流量并将其发送到测试集群而不影响生产流量 ,那么我们应该停止。 我们不能为自己的想法而牺牲生产的可靠性和可用性。 通常,我们将使用代理来屏蔽此流量。 Envoy代理是可用于此目的的代理。 Istio是一个服务网格,它使用Envoy作为启用此功能的默认代理。 有关更多信息,请参见Istio镜像任务 。 因此,基本上,服务网格(Istio)已位于生产流量的关键路径之间(以实现弹性,安全性,策略制定,路由控制等),并且还可能将流量隐藏在测试集群中。 实际上,这就是我们在上一个博客中进行的深入研究 。 重要的是,流量是异步镜像的,并且与生产流量不在带内。 任何响应都将被忽略。
对于熟悉所谓的“企业集成模式”(感谢Gregor Hophe! )的读者,您会注意到这种“镜像”的东西确实是一种味道或电线EIP 。
将流量注释为阴影流量
另一个重要的考虑因素是确定已镜像的流量。 我们需要能够分辨实时生产流量和用于测试目的的流量。 使用Istio / Envoy,被阴影的流量会自动附加其他上下文注释,以表示被镜像/阴影的流量。 例如,当反射镜Istio流量, 其附加 -shadow
到Host
或Authority
报头。 对于某些实现,这是当前存在的问题,因为-shadow
将添加到主机的末尾,因此foobar:8080
的Host
标头将以这样的标头结尾: foobar:8080-shadow
从技术上讲不是有效的HTTP 1 。X。 通过Envoy中的此修复程序 , -shadow
后缀将添加到主机名,因此foobar:8080
变为foobar-shadow:8080
。
阴影后将实时服务流量与测试群集进行比较
一旦我们可以可靠地屏蔽流量,就可以做一些有趣的事情。 我们可能希望将流向测试集群的流量与从实时生产集群中看到的预期行为进行比较。 例如,我们可能希望将请求结果与预期结果的任何偏差或API合约的破损进行比较,以实现向后和向前的兼容性。 我们可以插入一个负责这种流量协调的代理,并准备进行有趣的比较。 Twitter Diffy是在Twitter和其他地方的生产中被使用了一段时间的代理服务器之一。 它基本上需要镜像流量(由于Istio和Envoy,我们已经有了镜像流量),并调用实时服务和新服务并比较结果。 通过首先调用实时服务的两个实例,检测噪声,然后忽略这些部分以进行测试,它可以检测结果中的“噪声”并忽略该噪声(例如,时间戳,单调递增的计数器等)。服务。
Diffy还有一个很棒的网页/仪表板,用于查看通话结果,通话结果以及基于某些特征的过滤。 最后,Diffy有一个不错的管理控制台,用于查看有关呼叫比较的指标和统计信息。
非常感谢Prashant Khanduri , Puneet Khanduri和Alex Soto 在此提供的演示 。 留在寻找出这个演示的视频,我继续打造出来。
为某些测试配置文件提供协作服务
当我们部署服务的新版本并将流量镜像到测试群集时,我们需要注意对其余环境的影响。 我们的服务通常需要与其他服务协作(查询数据,更新数据等)。 如果与其他服务的协作只是读取或GET
请求,并且这些协作者能够承担额外的负载,则这可能不是问题。 但是,如果我们的服务更改了合作者中的数据,则需要确保将这些调用定向到测试双打,而不是实际的生产流量。 您可以为部署创建不同的安装配置,以注入这些配置。 例如,我们注入test.prod.com
而不是live.prod.com
用于下游服务。 如果在Kubernetes上部署,则可以使用不同的Config Maps进行控制。 另一个有趣的方法是使用Hoverfly或Microcks等工具部署虚拟化的测试双打。 借助这些服务虚拟化工具,您可以策划预期的请求/响应对,并引导将这些值变异为返回预期响应的这些代理的流量。
综合交易
在许多情况下,我们服务的新版本将需要更改其本地数据存储中的数据。 它可能会向协作服务发出呼叫以更改数据,但也许我们不能(或不应)使用先前的技术(服务虚拟化)对这些呼叫进行存根。 另一种方法是更明确地注释我们的调用(如在我们以前的模式中添加-shadow
),以指示这些请求应导致“综合交易”……即,这些交易不是真实交易,应采取任何撤销交易的补偿措施在请求结束时。 我们可以在请求中添加标头,甚至可以使其成为请求主体的一部分,以表明某个事务是“合成的”事实。 在执行此操作时,我们将指示参与服务按正常方式处理请求(包括所有数据操作),然后在提交之前回滚事务。 请注意,这对于事务性数据存储很好,但可能不适用于其他事务。 在这些情况下,如果您已经有了工作单元的概念,则可以在其上附加综合语义。 否则,最好不要尝试没有隔离和丢弃更改的合成交易。
这种方法对于执行包括数据存储在内的请求的完整路径很有用,以获得更好的计时保真度,数据干扰/不匹配问题,而双重测试可能无法解决。
这种方法的最大缺点是它是按惯例实现的,很难执行。 它可以与您拥有并控制的服务一起使用,但可能无法扩展到许多参与的协作者。 您可能不想尝试在所有服务上强制执行此约定,并且让一个服务无法正确实现此回滚功能,从而使所有内容混乱。 在严格控制和协调部署中使用此模式。
虚拟化测试集群的数据库
在针对镜像流量进行测试时,我们已经开始涉及与处理数据有关的问题。 通常,如果您的测试集群使用数据存储,并且测试服务以某种形式更新/插入/变异数据,则需要隔离这些更改。 我们只看了回首带有标头或嵌入标志等的任何更改,但这并非总是如此。
镜像流量时解决数据问题的另一种方法是对测试集群使用可替代数据存储。 您可以站起来一个空的数据存储,并用测试数据填充它,然后对它运行阴影流量。 但是,如果您使用的是Diffy(如上所述),则在响应比较中可能会收到很多误报,因为测试集群中的数据正在使用测试数据,而实时服务正在使用生产数据。 解决此问题的一种好方法是虚拟化数据层。 我们让测试集群使用一个数据存储,该数据存储向自己提供与生产数据存储相同的数据。
当我们这样做时,我们可以拥有生产数据的当前一致视图,并且还可以在不影响生产数据存储的情况下写入数据存储。 我们可以使用JBoss Teiid之类的工具轻松完成此操作。 Teiid具有适用于所有类型的数据存储系统的连接器,包括RDBMS,No-SQL系统,平面文件,hadoop,salesforce等,并且可以为我们的测试集群虚拟化它们。 在执行此操作时,无论何时进行写操作,此突变数据都可以进入一次性数据库中,但是您的服务却毫无头绪(也不用担心)。 我有一系列博客, 这些博客最值得注意的是关于微服务迁移的这篇博客文章 。
实现测试集群的数据库
最后,作为先前数据虚拟化技术的扩展的另一种方法是完全实现数据存储。 这样,我们测试集群的数据存储与生产集群的数据存储基本相同,并通过流处理不断进行更新。 这种工作方式是我们使用( CDC-更改数据捕获 )从生产数据库中捕获更改,然后将这些更改发送到新数据库。 一些数据存储允许将其作为内置的复制机制(例如MySQL从站或其他东西),但是很多时候这些都是只读的。 您可以使用像Debezium这样的Change Data Capture工具来构建一个简单的CDC系统,以使您的测试数据存储具有生产数据库的完全复制副本并不受惩罚地使用它。 Debezium 提供了用于不同数据存储的连接器,并从那些数据库中获取更改事件(即,读取事务日志)并将这些更改流式传输到Apache Kafka 。 从那里,您可以使用任何流处理工具将这些流具体化到测试数据库中。 FWIW, 上面提到的Teiid即将具有此功能。
此外,如果您已经拥有数据流管道,使用事件驱动的体系结构或使用某种基于事件的数据机制,则此“物化”测试数据库将成为更好的选择。
摘要
在实践中,将生产流量镜像到我们的测试群集(无论该群集存在于生产环境还是非生产环境中)是降低新部署风险的非常有效的方法。 像Twitter和Amazon这样的大型webop公司已经这样做了多年。 这种方法伴随着一些挑战,但是正如上面的模式所讨论的那样,存在着不错的解决方案。 如果您认为我错过了某些事情,或者觉得我没有涉及到一个令人讨厌的问题,请与我联系 ,我将很高兴与您讨论并将其添加到此博客的更新中。 谢谢!