回到Istio的微服务。 第二部分



注意事项 佩雷夫 :本系列的第一部分专门介绍Istio并在实际中进行演示。 现在,我们将讨论该服务网格的配置和使用的更复杂方面,尤其是关于微调的路由和网络流量管理。

我们还提醒您,本文使用istio-mastery存储库中的配置(Kubernetes和Istio的清单)。

交通管理


使用Istio,新功能会出现在群集中,以提供:

  • 动态查询路由 :金丝雀推出,A / B测试;
  • 负载平衡 :简单且一致,基于哈希;
  • 秋季恢复 :超时,重试,断路器;
  • 故障输入 :延迟,请求中断等

在本文的后续部分,这些功能将作为所选应用程序的示例显示,并且将在此过程中引入新的概念。 第一个这样的概念将是DestinationRules (即有关流量/请求接收者的规则-大约是Transl。) ,通过它我们可以启动A / B测试。

A / B测试:实际中的DestinationRules


如果应用程序有两个版本(通常在视觉上有所不同),并且我们不确定100%确定哪个版本可以改善用户交互,则使用A / B测试。 因此,我们同时启动两个版本并收集指标。

要部署演示A / B测试所需的前端的第二个版本,请运行以下命令:

 $ kubectl apply -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml deployment.extensions/sa-frontend-green created 

“绿色版本”的部署清单在两个地方有所不同:

  1. 该图片基于另一个标记istio-green
  2. 豆荚有一个version: green标签。

由于两个部署都具有app: sa-frontend标签,因此由sa-external-services虚拟服务路由到sa-frontend服务的请求将被重定向到其所有实例,并且将使用round-robin算法分配负载,这将导致以下情况:


找不到请求的文件

找不到这些文件是因为它们在应用程序的不同版本中被不同地调用。 让我们确保这一点:

 $ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main /static/css/main.c7071b22.css /static/js/main.059f8e9c.js $ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main /static/css/main.f87cd8c9.css /static/js/main.f7659dbb.js 

这意味着,请求平衡文件的一种版本的index.html可以由负载平衡器发送到具有不同版本的Pod,在这些Pod中,由于明显的原因,这些文件不存在。 因此,为了使该应用程序正常工作,我们需要施加一个限制:“ 提供index.html的相同版本的应用程序也必须满足后续请求 。”

我们将通过基于一致性的基于哈希的负载平衡(Consistent Hash Loadbalancing)来实现该目标。 在这种情况下, 来自一个客户端的请求将发送到同一后端实例 ,该后端实例使用预定义的属性-例如HTTP标头。 使用DestinationRules实现。

DestinationRules


VirtualService向所需的服务发送请求之后,使用DestinationRules,我们可以确定将应用于发往该服务实例的流量的策略:


Istio资源流量管理

注意 :此处以简化的方式介绍了Istio资源对网络流量的影响。 确切地说,Envoy在CRD中配置的Ingress网关中决定将请求发送到哪个实例。

使用目标规则,我们可以配置负载平衡,以便使用一致的哈希值,并确保来自同一服务实例的响应被提供给同一用户。 通过以下配置,此目标地址destinationrule-sa-frontend.yaml )可以实现此目的:

 apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: sa-frontend spec: host: sa-frontend trafficPolicy: loadBalancer: consistentHash: httpHeaderName: version # 1 

1-将基于HTTP version标头的内容生成哈希。

使用以下命令应用配置:

 $ kubectl apply -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml destinationrule.networking.istio.io/sa-frontend created 

现在运行下面的命令,并确保在指定version头时获得所需的文件:

 $ curl --silent -H "version: yogo" http://$EXTERNAL_IP/ | tr '"' '\n' | grep main 

注意 :要在标题中添加不同的值并直接在浏览器中测试结果,您可以将此扩展名用于Chrome (对于Firefox ,请使用此扩展名 -大约翻译)

通常,DestinationRules在负载均衡领域中有更多选项-请查看官方文档以了解详细信息。

在进一步探索VirtualService之前,我们将通过执行以下命令来删除应用程序的“绿色版本”和流量方向上的相应规则:

 $ kubectl delete -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml deployment.extensions “sa-frontend-green” deleted $ kubectl delete -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml destinationrule.networking.istio.io “sa-frontend” deleted 

镜像:实践中的虚拟服务


在我们想要测试生产变更而不影响最终用户的情况下,会使用阴影(“屏蔽”)或镜像(“镜像”) :为此,我们在第二次实例中重复(“镜像”)请求,并在必要时进行了更改,看看后果。 简而言之,这是您的(一位)同事选择最关键的问题并以巨大污垢的形式提出拉动请求时,实际上没有人可以对他进行审查。

要测试实际情况,请通过运行以下命令来创建第二个带有错误( buggy )的SA-Logic实例:

 $ kubectl apply -f resource-manifests/kube/shadowing/sa-logic-service-buggy.yaml deployment.extensions/sa-logic-buggy created 

现在,我们执行命令以确保所有具有app=sa-logic实例app=sa-logic具有带有相应版本的标签:

 $ kubectl get pods -l app=sa-logic --show-labels NAME READY LABELS sa-logic-568498cb4d-2sjwj 2/2 app=sa-logic,version=v1 sa-logic-568498cb4d-p4f8c 2/2 app=sa-logic,version=v1 sa-logic-buggy-76dff55847-2fl66 2/2 app=sa-logic,version=v2 sa-logic-buggy-76dff55847-kx8zz 2/2 app=sa-logic,version=v2 

sa-logic针对带有app=sa-logic标签的pod,因此所有请求将在所有实例之间分配:



...但是我们希望将请求定向到版本v1的实例并镜像到版本v2的实例:



我们将通过将VirtualService与DestinationRule结合使用来实现此目标,在DestinationRule中,规则将确定VirtualService的子集和到特定子集的路由。

在目标规则中定义子集


子集由以下配置( sa-logic-subsets-destinationrule.yaml )定义:

 apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: sa-logic spec: host: sa-logic # 1 subsets: - name: v1 # 2 labels: version: v1 # 3 - name: v2 labels: version: v2 

  1. host确定此规则仅适用于路由进入sa-logic
  2. 路由到子集的实例时使用子集的名称。
  3. 标签定义实例必须匹配的键/值对,才能成为子集的一部分。

使用以下命令应用配置:

 $ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-destinationrule.yaml destinationrule.networking.istio.io/sa-logic created 

现在已经定义了子集,您可以继续并配置VirtualService以将规则应用于对sa-logic的请求,以便它们:

  1. 路由到v1的子集,
  2. 镜像到v2的子集。

以下清单可帮助您实现计划( sa-logic-subsets-shadowing-vs。yaml ):

 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 mirror: host: sa-logic subset: v2 

这里不需要解释,因此只需看一下操作即可:

 $ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-shadowing-vs.yaml virtualservice.networking.istio.io/sa-logic created 

通过调用以下命令来添加负载:

 $ while true; do curl -v http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}'; \ sleep .8; done 

让我们看一下Grafana中的结果,在这里我们可以看到有buggy版本在大约60%的请求中崩溃,但是这些崩溃都不会影响最终用户,因为他们拥有有效的服务。


不同版本的sa-logic服务的响应成功

在这里,我们首先看到了如何将VirtualService应用于服务的Envoy:当sa-web-appsa-logic发出请求时,它将通过sidecar Envoy,后者通过VirtualService被配置为将请求路由到子集v1和镜像对sa-logic v2的子集的请求。

我知道:您已经有时间认为虚拟服务很简单。 在下一部分中,我们通过它们也确实很棒的事实来扩展这种观点。

金丝雀卷


Canary Deployment是为少数用户推出应用程序新版本的过程。 它用于确保发行版中没有问题,仅在此之后,已经对其足够的(发行版)质量充满信心,才能传播到更大的受众群体。

为了演示金丝雀的推出,我们将继续使用sa-logicbuggy集。

让我们不要浪费时间,立即将20%的用户发送给有错误的版本(它将代表我们的Canary推出),其余80%的用户返回正常服务。 为此,请应用以下VirtualService( sa-logic-subsets-canary-vs.yaml ):

 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 weight: 80 # 1 - destination: host: sa-logic subset: v2 weight: 20 # 1 

1是权重,它确定将发送给接收者或接收者子集的请求的百分比。

sa-logic以下命令为sa-logic更新以前的VirtualService配置:

 $ kubectl apply -f resource-manifests/istio/canary/sa-logic-subsets-canary-vs.yaml virtualservice.networking.istio.io/sa-logic configured 

...并立即看到部分请求崩溃:

 $ while true; do \ curl -i http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}' \ --silent -w "Time: %{time_total}s \t Status: %{http_code}\n" \ -o /dev/null; sleep .1; done Time: 0.153075s Status: 200 Time: 0.137581s Status: 200 Time: 0.139345s Status: 200 Time: 30.291806s Status: 500 

VirtualServices激活了金丝雀的推出:在这种情况下,我们将问题的潜在影响范围缩小到了20%的用户群。 太好了! 现在,在每种情况下,当我们不确定我们的代码时(换句话说,总是...),我们可以使用镜像和canary卷展栏。

超时和重试


但并非总是在代码中包含错误。 在“ 分布式计算中的8个错误 ”列表中,首先出现了“网络可靠”的错误观点。 实际上,网络是可靠的,因此,我们需要超时和重试

为了进行演示,我们将继续使用相同版本的sa-logicbuggy ),并将模拟随机故障导致的网络不可靠性。

让我们的错误服务有1/3的机会响应时间太长,有1/3的机会完成内部服务器错误,有1/3的机会返回成功的页面。

为了减轻此类问题的后果并改善用户的生活,我们可以:

  1. 如果服务响应时间超过8秒,请添加超时,
  2. 如果请求失败,请重试。

为了实现,我们将使用以下资源定义( sa-logic-retries-timeouts-vs.yaml ):

 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 weight: 50 - destination: host: sa-logic subset: v2 weight: 50 timeout: 8s # 1 retries: attempts: 3 # 2 perTryTimeout: 3s # 3 

  1. 请求的超时设置为8秒;
  2. 重复请求尝试3次;
  3. 如果响应时间超过3秒,则每次尝试都将被视为失败。

因此,我们已经实现了优化,因为用户不必等待超过8秒的时间,并且在发生故障时我们将进行三种新的尝试来获得答案,从而增加了成功响应的机会。

使用以下命令应用更新的配置:

 $ kubectl apply -f resource-manifests/istio/retries/sa-logic-retries-timeouts-vs.yaml virtualservice.networking.istio.io/sa-logic configured 

并检查Grafana的图形,成功答案的数量已经结束:


添加超时和重试后,成功响应统计信息的改进

在继续下一节(或者,因为本文中不会进行更多实验-大约翻译)之前 ,请通过运行以下命令删除sa-logic-buggy和VirtualService:

 $ kubectl delete deployment sa-logic-buggy deployment.extensions “sa-logic-buggy” deleted $ kubectl delete virtualservice sa-logic virtualservice.networking.istio.io “sa-logic” deleted 

断路器和隔板模式


我们正在谈论微服务体系结构中的两个重要模式,这些模式可让您实现自我修复服务。

电路断路器 (“电路断路器”)用于停止请求到不健康服务实例的请求,并在客户端请求重定向到该服务的健康实例(恢复成功响应的百分比)时恢复该请求。 (注意:例如,可以在这里找到关于模式的更详细的描述。)

隔板 (“分区”)将服务故障与整个系统的故障隔离开来。 例如,服务B中断,另一个服务(服务B的客户端)向服务B发出请求,结果它将耗尽其线程池,并且将无法服务其他请求(即使它们与服务B不相关)。 (注意:例如,可以在这里找到关于模式的更详细的描述。)

我将省略有关这些模式的实现的详细信息,因为它们在官方文档中很容易找到,并且我确实想显示身份验证和授权,这将在本文的下一部分中进行讨论。

译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN440378/


All Articles