作为Service Mesh架构,Istio为出问题的微服务提供了感知和恢复能力以提高系统的可用性,主要体现在超时(Timeout)、重试(Try)、断路器(Circuit Breaker)等功能。
准备环境
在开始操作前,我们先把以前针对Recommendation定义的DestinationRule和VirtualService删除掉,然后把运行recommendation-v2微服务的Pod设为1个。
<code>$ oc delete -f istiofiles/destination-rule-recommendation_lb_policy_app.yml -n tutorial$ oc get istio-io -n tutorialNAME GATEWAYS HOSTS AGEvirtualservice.networking.istio.io/customer-vs [customer-gw] [*] 5hNAME AGEgateway.networking.istio.io/customer-gw 5h$ oc scale deployment recommendation-v2 --replicas=1 -n tutorial$ oc get pod -n tutorialcustomer-77dc47d7f8-szhd5 2/2 Running 4 6hpreference-v1-55476494cf-xm4dq 2/2 Running 0 3hrecommendation-v1-67976848-4l4s7 2/2 Running 0 3hrecommendation-v2-599867df6c-5ccdx 2/2 Running 0 19m/<code>
重试(Fail Try)
当通过Service访问一个微服务的Pod出现错误(例如503)后,Istio可以自动(缺省配置,可以修改)尝试访问其它运行微服务的Pod。
1. 在一个窗口中运行以下命令,可以看到此时recommendation v1和recommendation v2是交替被调用的。
<code>$ export INGRESS_GATEWAY=$(oc get route istio-ingressgateway -n istio-system -o 'jsonpath={.spec.host}')$ ./scripts/run.sh $INGRESS_GATEWAY/customercustomer => preference => recommendation v2 from '3cbba7a9cde5': 50customer => preference => recommendation v1 from '67976848-4l4s7': 1451customer => preference => recommendation v2 from '3cbba7a9cde5': 51customer => preference => recommendation v1 from '67976848-4l4s7': 1452/<code>
此时在Kiali中可以看到recommendation v1和recommendation v2各有50%的调用机会。
2. 在另一个窗口执行以下命令进入运行recommendation v2微服务的容器,以便能模拟recommendation v2微服务运行不正常。
<code>$ oc exec -it $(oc get pods|grep recommendation-v2|awk '{ print $1 }'|head -1) -c recommendation /bin/bash/<code>
3. 在运行recommendation v2微服务的容器内部执行以下命令,调用微服务接口模拟运行异常(返回503),然后退出容器。
<code>bash-4.4$ curl localhost:8080/misbehaveFollowing requests to / will return a 503bash-4.4$ exitexit/<code>
4. 在第一个窗口确认只调用recommendation-v1微服务了。
<code>$ export INGRESS_GATEWAY=$(oc get route istio-ingressgateway -n istio-system -o 'jsonpath={.spec.host}')$ ./scripts/run.sh $INGRESS_GATEWAY/customercustomer => preference => recommendation v1 from '67976848-4l4s7': 1444customer => preference => recommendation v1 from '67976848-4l4s7': 1445customer => preference => recommendation v1 from '67976848-4l4s7': 1446/<code>
此时在Kiali中可以看到recommendation v1有100%的调用机会。选中recommandation的方框,然后将鼠标放在右侧红色App:recommendation上,此时可以看到提示:虽然2个recommandation的Pod状态都正常,但是有一部分Inbound请求出错。
选中recommandation v2的小方框,然后将鼠标放在右侧红色App:recommendation上,此时可以看到提示:100%的Inbound请求出错。
选中preference的方框,然后将鼠标放在右侧红色App:preference上,此时可以看到提示:有一部分Outbound请求出错。
5. 再恢复recommendation v2微服务正常运行,此时第一个窗口又可以访问到recommendation v2微服务了。
<code>$ oc exec -it $(oc get pods|grep recommendation-v2|awk '{ print $1 }'|head -1) -c recommendation /bin/bashbash-4.4$ curl localhost:8080/behaveFollowing requests to / will return a 503bash-4.4$ exitexit/<code>
6. 文件istiofiles/virtual-service-recommendation-try.yml修改了对recommendation的Servic访问的缺省重试配置。
<code>apiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata: name: recommendationspec: hosts: - recommendation http: - route: - destination: host: recommendation retries: attempts: 3 perTryTimeout: 2s/<code>
执行命令修改重试的配置。
<code>$ oc apply -f istiofiles/virtual-service-recommendation-try.yml/<code>
超时(Timeout)
为访问微服务设置超时时间,当超过Timeout时间后自动结束访问。
1. 首先我们根据本文开始说明,重新准备环境,确保recommendation v1和recommendation v2都可以正常访问。
2. 执行以下命令,删掉正常的recommendation v2的Deployment,然后部署一个超时版的recommendation v2。
<code>
3. 执行脚本连续访问customer,可以发现recommendation v2返回结果比较慢。
<code>$ export INGRESS_GATEWAY=$(oc get route istio-ingressgateway -n istio-system -o 'jsonpath={.spec.host}')$ ./scripts/run.sh $INGRESS_GATEWAY/customercustomer => preference => recommendation v1 from '67976848-4l4s7': 3078customer => preference => recommendation v2 from '379afb614fb1': 1customer => preference => recommendation v1 from '67976848-4l4s7': 3079customer => preference => recommendation v2 from '379afb614fb1': 2CTL+C/<code>
4. 为recommendation服务创建一个VirtualService。文件istiofiles/virtual-service-recommendation-timeout.yml内容如下,其中为访问recommendation定义了timeout为1s。
<code>apiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata: name: recommendationspec: hosts: - recommendation http: - route: - destination: host: recommendation timeout: 1.000s/<code>
执行命令,创建VirtualService
<code>$ oc apply -f istiofiles/virtual-service-recommendation-timeout.yml -n tutorial/<code>
5. 执行脚本持续访问customer,可以看到由于recommendation v2超时,所以返回的只有recommendation v1。
<code>$ export INGRESS_GATEWAY=$(oc get route istio-ingressgateway -n istio-system -o 'jsonpath={.spec.host}')$ ./scripts/run.sh $INGRESS_GATEWAY/customercustomer => preference => recommendation v1 from '67976848-4l4s7': 3084customer => preference => recommendation v1 from '67976848-4l4s7': 3085customer => preference => recommendation v1 from '67976848-4l4s7': 3086/<code>
6. 在Kiali控制台中,选中recommendation的红色方框,鼠标点到右上方App:recommendation后,可以看到50%的Inbound出现错误。由于此步骤没有配置“retry”
7. 最后恢复环境,删除超时的recommendation v2部署和recommendation的VirtualService,并重新部署正常的recommendation v2。
<code>
断路器(Circuit Breaker)
当一个被调用服务出现错误后,下一次Istio还会将请求发给出错的服务。回顾本文的“重试(Fail Try)”中的第二章截图,访问recommendation v2的失败率是33%。这是由于Istio会轮训将请求发给recommendation v2和recommendation v2,当发现recommendation v2出现错误后再尝试发给recommendation v1。我们可以在DestinationRule上设置断路器(Circuit Breaker),以便在访问某个服务失败后暂时断开对这个服务实例的访问。Istio会在指定的时间后尝试将请求再次发给recommendation v2,如果此时失效的recommendation v2已经恢复正常,Istio会停止作用于recommendation v2的断路器。
1. 根据本文“准备环境”的说明,删除所有recommendation微服务相关的VirtualService、DestinationRule。此时请求可以被轮训发到recommendation v1和recommendation v2上。
2. 进入运行recommendation v2的容器里,执行命令把状态设为disbehave状态,然后退出。
<code>$ oc exec -it -n tutorial $(oc get pods -n tutorial|grep recommendation-v2|awk '{ print $1 }'|head -1) -c recommendation /bin/bashbash-4.4$ curl localhost:8080/misbehaveFollowing requests to / will return a 503bash-4.4$ exitexit/<code>
3. 执行命令,连续访问customer。此时从调用客户端看到的是recommendation v1响应处理的请求。
<code>$ export INGRESS_GATEWAY=$(oc get route istio-ingressgateway -n istio-system -o 'jsonpath={.spec.host}')$ ./scripts/run.sh $INGRESS_GATEWAY/customercustomer => preference => recommendation v1 from '67976848-4l4s7': 3492customer => preference => recommendation v1 from '67976848-4l4s7': 3493customer => preference => recommendation v1 from '67976848-4l4s7': 3494customer => preference => recommendation v1 from '67976848-4l4s7': 3495.../<code>
4. 在另一个窗口执行以下命令,查看运行recommendation v2的容器日志。我们可以发现recommendation v2微服务还继续不断有日志输出,说明有请求还是不断发给它。因为此时我们还没有为recommendation v2设置断路器。
<code>$ oc logs -f $(oc get pods |grep recommendation-v2|awk '{ print $1 }'|head -1) -c recommendationrecommendation request from 3cbba7a9cde5: 11recommendation request from 3cbba7a9cde5: 12recommendation request from 3cbba7a9cde5: 13/<code>
5. 在第三个窗口执行命令,为recommendation服务创建带有断路器的DestinationRule。文件istiofiles/destination-rule-recommendation_cb_policy_version_v2.yml定义了DestinationRule:
<code>apiVersion: networking.istio.io/v1alpha3kind: DestinationRulemetadata: name: recommendationspec: host: recommendation subsets: - labels: version: v1 name: version-v1 - labels: version: v2 name: version-v2 trafficPolicy: connectionPool: http: http1MaxPendingRequests: 1 maxRequestsPerConnection: 1 tcp: maxConnections: 1 outlierDetection: baseEjectionTime: 3m consecutiveErrors: 1 interval: 1s maxEjectionPercent: 100/<code>
执行命令为recommendation服务创建DestinationRule。
<code>$ oc apply -f istiofiles/destination-rule-recommendation_cb_policy_version_v2.yml -n tutorial/<code>
6. 此时可从从窗口1看到还不断发送对customer的请求,但是窗口2已经不再有日志输出,说明请求没有被发到recommendation
v2微服务上,这是由于断路器暂时不再将请求发给出问题的recommendation v2微服务。
7. 再次进入运行recommendation v2的容器里,执行命令把状态设为behave状态,然后退出。这样recommendation v2微服务又恢复了正常访问。
<code>$ oc exec -it -n tutorial $(oc get pods -n tutorial|grep recommendation-v2|awk '{ print $1 }'|head -1) -c recommendation /bin/bashbash-4.4$ curl localhost:8080/behaveFollowing requests to / will return a 503bash-4.4$ exitexit/<code>
8. 继续观察窗口1和窗口2的输出,需要等3分钟左右。从以下窗口1的日志可以看到请求再次被转发到recommendation v2,而窗口2也会有新的日志输出,说明recommendation v2已经恢复接收到转发的请求。
<code>customer => preference => recommendation v1 from '67976848-4l4s7': 4522customer => preference => recommendation v2 from '3cbba7a9cde5': 20customer => preference => recommendation v1 from '67976848-4l4s7': 4523customer => preference => recommendation v2 from '3cbba7a9cde5': 21customer => preference => recommendation v1 from '67976848-4l4s7': 4524customer => preference => recommendation v2 from '3cbba7a9cde5': 22customer => preference => recommendation v1 from '67976848-4l4s7': 4525customer => preference => recommendation v2 from '3cbba7a9cde5': 23/<code>
閱讀更多 OpenShift之家 的文章