使用Istio Service Mesh实现微服务的高级流量复制模式


【编者的话】本文详细介绍了流量复制模式,用来更为真实地测试新版本,提前发现问题,同时不对生产环境产生影响,从而,提高版本发布的安全性可靠性。本文首先介绍了流量复制所面临的问题,然后逐条详细介绍解决这些问题的具体方案。

微服务让我们可以更快地实现交付。但是,我们不能仅仅追求快速而导致一切都不工作了。我们需要一种方式,来降低变更所带来的风险,并且同时让生产环境上的新变化变得更为安全。有一种强大的模式,有助于降低生产环境做变更的风险,是将生产环境的流量复制到测试集群或者软件的更新版本上,在真正负载实时流量(也就是客户流量)之前验证新版本是不是没有问题。这种做法让我们可以用真正的用户场景验证代码,一般非生产环境的测试模拟可能不一定能发现这样的问题。我之前写过这篇文章,《Istio服务网格提供了镜像流量的特性》。我确实喜欢讨论Istio和服务网格的理念请关注@christianposta来参与最新的讨论。现在进入正题:

复制流量的问题

当将真实生产流量复制到测试集群,或者生产环境里的灰度集群上时,我们会面临一系列的挑战。首先,怎么在不影响生产服务关键路径的前提下将流量引入到目标集群里?是否需要过滤掉这些请求里的私人信息?怎么才能保证测试集群不会影响到实时的交互服务?如果服务对数据做变更,我们如何隔离这些变更从而不影响生产环境呢?

这些都是实际存在的挑战,也可能正是认为不要尝试复制流量的理由。IMHO复制是安全发布的最重要也最强大的技术之一,因此这里一起看看解决这些问题的一些模式。看上去类似于:
  • 得到测试集群的流量,但是不能影响关键路径
  • 将流量注释为复制的流量
  • 复制之后将实时服务流量和测试集群做对比
  • 阻止某些测试profile的交互服务
  • 人造事务
  • 虚拟化测试集群的数据库
  • 物化测试集群的数据库


让我们深入探讨。

得到测试集群的流量,但是不能影响关键路径

这可能是最为重要的部分。如果我们无法可靠地复制流量,将其导入测试集群,并且不影响生产环境的流量,那么我们就什么也做不了。我们不能为了测试而牺牲生产环境的可靠性和可用性。通常会使用代理来复制流量。Envoy Proxy可以用来实现这个功能。Istio是服务网格,使用Envoy作为默认的代理从而可以提供这一功能。Istio镜像任务里有更详细的介绍。因此服务网格(Istio)已经存在于生产环境流量的关键路径上了(实现弹性、安全、策略实施、路由控制等等),所以它可以将流量复制到测试集群上。实际上,这也正是我上一篇博客重点探讨的。重要的是,流量是异步镜像的,和生产环境流量完全隔离。所有响应都会被忽略。
01.png

对于熟悉“企业集成模式”(感谢Gregor Hophe)的读者来说,你会发现这样的“镜像”所做的事情其实就是wire tap EIP(EIP窃听模式,编者注:EIP即企业集成模式的缩写)。

将流量注释为复制的流量

另一个重要的考量是识别被镜像的流量。我们需要能够将生产流量和测试用途的流量区分开来。使用Istio/Envoy的话,被复制的流量会自动标注上额外的上下文来表示这个流量是被镜像/复制的。比如,当Istio镜像流量时,它会在Host或者Authority头字段上加上-shadow。对于一些实现来说,这可能会带来问题,因为-shadow会被添加到host的最后,这样foobar:8080Host头字段会变成:foobar:8080-shadow,从技术角度看这并不是有效的HTTP 1.x。有了Envoy的这个fix之后,-shadow会加到主机名里,foobar:8080会变成foobar-shadow:8080
02.png

复制之后将实时服务流量和测试集群做对比

一旦能够可靠地复制流量,就可以尝试做一些有意思的事情。我们可能希望将测试集群的流量和真实生产流量的实际行为做对比。比如,我们可能想比较一下请求的结果或API契约的破坏结果,以便向后和向前兼容。我们可以插入一个负责协调这种类型流量的代理,并且负责做对比。Twitter Diffy是一种这样的代理,插入到了Twitter生产环境里和其他地方来完成这样的工作。它得到镜像流量并且调用真实服务和新服务,然后比对结果。它能够检测结果里的“噪音”,并将其忽略(比如,时间戳,单调递增计数器等),这里的机制是首先调用真实服务的两个实例,检测噪音,随后在调用测试服务的时候忽略这些噪音部分。
03.png

Diffy还提供了很棒的网页/仪表盘以便查看调用的结果,之间的区别,并且基于特定特性做过滤。最后,Diffy提供了不错的管理控制台来查看这些调用比对的度量和统计数据。
04.png

这里有一个demo,感谢Prashant khanduriPuneet KhanduriAlex Soto。建议持续关注这个demo的视频,我会持续更新。

阻止特定测试profile的交互服务

当部署服务新版本,并将流量镜像到测试集群上时,我们需要时刻考虑到对其余环境可能造成的影响。我们的服务通常需要和其他服务交互(查询数据、更新数据等)。如果和其他服务的交互仅仅是读操作或者是GET请求,并且这些交互可以用额外的实例来承载的话,这可能不会造成什么问题。但是如果在交互过程中会改变数据,那么就需要确保这些调用是定位到测试环境中,而不是真实的生产流量。你可以为部署创建不同的安装配置。比如,对于下游服务,我们注入test.prod.com,而不是live.prod.com。如果部署在Kubernetes上,你可以使用不同的Config Map来做控制。另一个有意思的方案是使用Hoverfly或者Microcks部署虚拟化的测试环境。使用这些服务虚拟化的工具,你可以设定预计的请求/响应对,并且将会变更值的流量直接引入这些代理,从而得到预期的响应。
05.png

人造事务

在很多情况下,服务的新版本都需要变更自己本地数据存储里的数据。它可能会调用交互服务来变更数据,但是使用前文提到的技术(服务虚拟化)可能无法(或者不能)阻止这样的调用。另一种方案是更为精细地注释调用(就像之前的模式添加-shadow一样),标示这些请求属于“人造事务”……比如,表示这不是真正的事务,在请求的最后需要撤销这些操作。可以在请求里添加头字段或者甚至将其作为请求body的一部分,来标注某个特定事务是“综合的”。当这么做的时候,我们就需要让涉及到的服务先常规处理请求,包括所有数据操作,随后在提交之前回滚事务。注意,这在事务性数据存储上可以工作,但是其他的数据存储可能会有问题。这样的场景里,如果你已经有了工作单元的概念,就可以在其上附加综合语义。否则,最好不要尝试人造事务,因为没有办法隔离并且撤销变更。
06.png

该方案对于执行请求的全路径,包括数据存储很有用,可以得到更好的时间模拟度,帮助发现数据干扰/不匹配之类的问题,这些问题使用test double方案的话可能不容易捕捉到。

该方案的最大的缺点是它是按惯例执行的,并且很难执行。对于你自己负责并能控制的服务可能能用得起来,但是可能无法扩展到很多涉及的交互服务中。尝试让所有服务都遵循这样的管理是很难的,只要有一个服务没有正确实现这样的回滚功能,就会导致满盘皆输。在密切控制和协调的部署里使用这个模式。

虚拟化测试集群的数据库

在测试镜像流量时,我们开始接触到数据相关的问题。总的来说,如果测试集群使用数据存储,并且测试服务以某种形式更新/插入/变更数据的话,你就需要隔离这些变更。我们介绍了在头字段加标记位或者嵌入flag然后简单回滚这些变更,但是这个方法并不是总有效。

另一种处理镜像流量需要处理数据的方案是测试集群使用可替代的数据存储。可以搭建一个空的数据存储,然后填入测试数据,在其上运行复制的流量。但是,如果你使用了Diffy(上文提到过),那么在响应比对上可能会得到很多虚警,因为测试集群使用的是测试数据,而实时服务使用生产数据。处理这个问题的一种好办法是虚拟化数据层。让测试集群使用数据存储的数据和生产数据存储数据相同。
07.png

这么做的话,就可以得到生产数据的最新的稳定视图,并且还能够做数据写入,同时不真正影响生产数据存储。我们可以使用JBoss Teiid这样的工具,使用起来很容易。Teiid提供了所有类型的数据存储系统的连接器,包括RDBMS,No-SQL系统,flat文件,Hadoop,salesforce等等,并且能够为测试集群将它们虚拟化。这时,写入操作的时候,变更的数据会进入即刻抛弃的数据库,但是你的服务并不会对此有任何感知。我写过一系列有关如何做微服务迁移博客来讨论这个问题。

物化测试集群的数据库

最后,另一种方案是上述数据虚拟化技术的扩展,是彻底物化数据存储。这样,测试集群的数据存储基本和生产集群使用的完全一样,通过流处理持续更新。这里,我们使用CDC(Change Data Capture,变化数据捕捉)来捕捉生产数据库的变更,然后将这些变更发送到新的数据库里。一些数据存储提供了这样的内建复制机制(比如MySQL slave之类),但是很多时候它是只读的。可以使用变化数据捕捉工具,比如Debezium来构建简单的CDC系统,让测试数据存储时生产数据库的完整复制备份,并且可以随意使用。Debezium提供不同数据存储的连接器,并从这些数据库获得变更事件(比如,读取事务日志),将这些变更输入Apache Kafka。这里可以使用任意流处理工具,将这些流物化到测试数据库里。FWIW,Teiid将很快提供这样的功能。
08.png

另外,如果已经有了数据流管道,使用事件驱动架构,或者使用某种类型的事件源数据机制,然后“物化”测试数据库就是比较自然的方案了。

总结

实际上,将生产流量镜像到测试集群里(无论该集群是在生产环境内部还是在非生产环境里)是降低新部署风险的强大武器。Twitter和Amazon这样的大型互联网公司已经这么做很多年了。该方案的确伴随着很多挑战,但是上文讨论的方案都很好。如果你认为自己错过了什么,或者有什么我没有涉及到的问题,请联系我

原文链接:Advanced Traffic-shadowing Patterns for Microservices With Istio Service Mesh(翻译:崔婧雯)
===========================
译者介绍
崔婧雯,现就职于IBM,高级软件工程师,负责IBM WebSphere业务流程管理软件的系统测试工作。曾就职于VMware从事桌面虚拟化产品的质量保证工作。对虚拟化,中间件技术,业务流程管理有浓厚的兴趣。

0 个评论

要回复文章请先登录注册