假期结束了,我们将返回Istio Service Mesh系列的第二篇文章。

今天的主题是断路器,该断路器翻译为俄语的电工技术,用通用语言表示“断路器”-“断路器”。 仅在Istio中,本机才不会断开短路或过载电路,而是断开有故障的容器。
它应该如何理想地工作
例如,当微服务由Kubernetes管理(作为OpenShift平台的一部分)时,它们会根据负载自动进行伸缩。 由于微服务在Pod中工作,因此在一个端点上可以有多个容器化微服务实例,而Kubernetes会路由请求并平衡它们之间的负载。 而且-理想情况下-所有这些都应该完美运行。
我们记得微服务是小型且短暂的。 短暂性,在这里意味着出现和消失的简单性,常常被低估了。 Pod中下一个微服务实例的诞生和死亡是人们预料之中的事情,OpenShift和Kubernetes都做得很好,并且一切工作都很好-但从理论上讲也是这样。
真正如何运作
现在想象一下,微服务的特定实例(即容器)已经变得不可用:它要么不响应(错误503),要么反应更慢,但更令人不愉快。 换句话说,它静音或不响应请求,但是不会自动将其从池中删除。 在这种情况下应该怎么办? 再试一次 从路由方案中删除它? “太慢”是什么意思-这些数字有多少,由谁定义? 也许只是给他休息一下,然后再试一次? 如果是这样,那么以后多少?
在Istio中什么是池弹出
Istio凭借其断路器断路器进行了抢救,该断路器可临时从路由池和负载平衡资源池中删除有问题的容器,并实施池弹出程序。
Istio使用异常值检测策略来检测从常规行中剔除的Pod曲线,并在给定时间内将其从资源池中删除,称为“休眠窗口”。
为了展示它在OpenShift平台上的Kubernetes中是如何工作的,我们首先从
Red Hat Developer Demos存储库中的示例中截取正常工作的微服务的屏幕截图。 在这里,我们有两个Pod,分别是v1和v2,每个容器都在其中工作。 当不使用Istio的路由规则时,Kubernetes默认会应用统一均衡的轮询路由:
为崩溃做好准备
在执行池弹出之前,必须创建Istio路由规则。 假设我们要在Pod之间分配相对于50/50的请求。 此外,我们将v2容器的数量从一个增加到两个,如下所示:
oc scale deployment recommendation-v2 --replicas=2 -n tutorial
现在,我们定义了路由规则,以使流量以50/50的比率在Pod之间分配。
这是此规则的结果:
您可能会抱怨在此屏幕上不是50/50,而是14:9,但是随着时间的流逝,情况会有所改善。
我们安排失败
现在,我们将禁用两个v2容器之一,以便拥有一个正常运行的容器v1,一个正常运行的容器v2和一个失效的容器v2:
解决崩溃
因此,我们的容器有问题,现在是时候退出池了。 使用非常简单的配置,我们会将这个失败的容器从任何路由方案中排除15秒钟,以期它会恢复到正常状态(它将重新启动,或者将恢复性能)。 这是此配置的外观及其工作结果:
如您所见,发生故障的容器v2在路由请求时不再使用,因为它已从池中删除。 但是15秒后,它将自动返回到池中。 实际上,我们只是展示了池弹出的工作原理。
开始建造建筑
池弹出功能与Istio的监视功能相结合,使您可以开始构建一个框架,以自动替换有故障的容器,以减少甚至消除停机时间和崩溃。
美国国家航空航天局(NASA)有一个引人注目的座右铭:“失败不是一个选择”,由飞行主管
吉恩·克兰茨 (
Gene Krantz)撰写。 可以将其翻译成俄文,说“失败是没有选择的”,这里的要点是,一切都可以以足够的意愿进行。 但是,在现实生活中,失败不仅会发生,而且是无处不在的,无处不在。 在微服务方面该如何应对? 我们认为,最好不要依赖意志力,而要依赖容器,
Kubernetes ,
Red Hat OpenShift和
Istio的功能 。
如上所述,Istio实现了断路器的概念,该概念已在物理世界中证明了自己。 就像自动机器断开电路的问题部分一样,当端点出问题时(例如,当服务器崩溃或开始减速时),Istio中的Circuit Breaker软件也会断开请求流与问题容器之间的连接。
此外,在第二种情况下,仅存在更多问题,因为一个容器的制动不仅会导致访问该容器的服务出现一连串的延迟,结果会降低整个系统的性能,还会导致对本已运行缓慢的服务的重复请求,这只会加剧这种情况。 。
理论上的断路器
断路器是控制到端点的请求流的代理。 当此点停止工作或根据设置开始变慢时,代理将从容器断开连接。 然后,仅由于负载平衡,然后将流量重定向到其他容器。 对于给定的睡眠窗口,该连接保持打开状态(例如两分钟),然后将其视为半打开状态(半打开状态)。 尝试发送下一个请求将确定进一步的通信状态。 如果该服务一切正常,则连接返回操作状态,然后再次关闭。 如果服务仍然存在问题,则打开连接并重新启用睡眠窗口。 简化的断路器状态图如下所示:
重要的是要注意,所有这些都发生在系统体系结构级别上。 因此,在某些时候,您将必须教您的应用程序与Circuit Breaker一起使用,例如,提供默认值作为响应,或者在可能的情况下忽略服务的存在。 为此使用了隔板模式,但这超出了本文的范围。
实践中的断路器
例如,我们将在OpenShift上启动推荐微服务的两个版本。 版本1可以正常工作,但是在v2中,我们将延迟构建以模拟服务器上的刹车。 要查看结果,请使用
围攻工具:
siege -r 2 -c 20 -v customer-tutorial.$(minishift ip).nip.io
一切似乎都可以正常工作,但是要付出什么代价呢? 乍一看,我们拥有100%的可用性,但仔细看看-最长交易时间长达12秒。 这显然是一个瓶颈,需要进行绣制。
为此,我们将使用Istio消除对慢速容器的访问。 这是使用断路器的相应配置的样子:
带有httpMaxRequestsPerConnection参数的最后一行表示在尝试创建一个连接(第二个-除了现有连接)时,应打开的连接。 由于我们的集装箱模仿制动服务,因此这种情况会定期发生,然后Istio将返回503错误,而围困将显示以下内容:
好,我们有断路器,下一步是什么?
因此,我们实现了自动关机,而无需触及服务本身的源代码。 使用上述断路器和池弹出程序,我们可以从资源池中删除制动容器,直到它们恢复正常,并以给定的频率检查其状态-在我们的示例中,这是两分钟(sleepWindow参数)。
请注意,应用程序对错误503的响应能力仍设置在其源代码级别。 有很多使用断路器的策略,具体取决于情况。
在下一篇文章中:我们将讨论跟踪和监视(它们已经内置或可以轻松添加到Istio中),以及如何有意将错误引入系统中。