istio 1.10学习笔记09: Istio流量管理之设置请求超时和熔断
2021-07-26
前面几节内容我们学习了Istio API资源对象中的虚拟服务VirtualService
, 目标规则DestinationRule
, Gateway
。
使用它们可以实现将集群外部流量(http或tcp)接入到服务网格内部,可以进行一些常见的流量管理功能如: 设置请求路由、故障注入、流量转移(http或tcp)等。
本节我们学习使用istio进行流量管理的另外两个常见功能:设置请求超时和熔断。
设置请求超时 #
对HTPP服务的请求超时,可以通过虚拟服务的路由规则中的timeout
字段来指定。默认请求下这个配置是禁用的。
下面基于bookinfo应用完成这个测试。
本测试将reviews
服务的超时设置为1秒,为了便于观察测试结果,还将使用istio的故障注入功能为对ratings
服务注入2秒的延迟故障。
首先执行下面的命令初始化bookinfo应用各服务的路由规则:
1kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
修改reviews
服务的虚拟服务,将对reviews
服务的请求全都路由到v2版本:
1kubectl apply -f - <<EOF
2apiVersion: networking.istio.io/v1alpha3
3kind: VirtualService
4metadata:
5 name: reviews
6spec:
7 hosts:
8 - reviews
9 http:
10 - route:
11 - destination:
12 host: reviews
13 subset: v2
14EOF
对ratings
服务进行故障注入,注入2秒的延迟:
1kubectl apply -f - <<EOF
2apiVersion: networking.istio.io/v1alpha3
3kind: VirtualService
4metadata:
5 name: ratings
6spec:
7 hosts:
8 - ratings
9 http:
10 - fault:
11 delay:
12 percent: 100
13 fixedDelay: 2s
14 route:
15 - destination:
16 host: ratings
17 subset: v1
18EOF
此时使用我们之前配置好的Istio Gateway入口访问bookinfo应用https://bookinfo.example.com/productpage,会发现bookinfo应用运行正常(显示了评级的星型符号),但是每次刷新页面,都会有2秒的延迟。
因为reviews:
v2版本的服务是通过调用ratings
服务获取评级信息的,默认reviews服务默认是没有设置请求超时的,所以它会等待ratings服务中注入的2秒延迟,每次刷新页面也就有了2秒的延迟。
由于productpage
服务中存在硬编码重试,即遇到错误时会重试1次,下面我们将对review服务的调用设置一个0.5秒的超时:
1kubectl apply -f - <<EOF
2apiVersion: networking.istio.io/v1alpha3
3kind: VirtualService
4metadata:
5 name: reviews
6spec:
7 hosts:
8 - reviews
9 http:
10 - route:
11 - destination:
12 host: reviews
13 subset: v2
14 timeout: 0.5s
15EOF
此时再刷新/productpage
页,会有1秒的延迟,且页面中的书籍评级信息出现错误Error fetching product reviews!
。这是因为这个请求的调用链如下productpage(出现请求超时错误时重试1次) --> reviews(请求超时设置为0.5秒) ---> ratings(注入了2秒的延迟)
。可以看出通过设置对reviews服务的请求超时,实现了微服务治理中设置请求超时的功能,这完全是在服务网格中实现的,没有侵入微服务的业务逻辑。
在服务治理中通过设置请求超时,可以避免大量请求长时间占用资源。
熔断 #
熔断是创建弹性微服务的重要模式,熔断可以使应用程序具备应对来自故障、潜在峰值和其他未知网络因素的能力。 熔断机制是应对雪崩效应的一种微服务链路保护机制。服务雪崩是指当调用链中的某个环节,特别是服务提供方不可用时,将会导致上游环节不可用,并最终将这个影响扩大到整个系统中,导致整个系统的不可用。
下面将演示istio中流量管理的熔断功能。
首先部署用于测试的httpbin
应用,将其部署在k8s的default namespace内,因为default命名空间在前面部署bookinfo应用时已经开启了istio sidecar的自动注入功能,所以这里直接部署httpbin
应用即可:
1kubectl apply -f samples/httpbin/httpbin.yaml
httpbin.yaml的内容如下:
1apiVersion: v1
2kind: ServiceAccount
3metadata:
4 name: httpbin
5---
6apiVersion: v1
7kind: Service
8metadata:
9 name: httpbin
10 labels:
11 app: httpbin
12 service: httpbin
13spec:
14 ports:
15 - name: http
16 port: 8000
17 targetPort: 80
18 selector:
19 app: httpbin
20---
21apiVersion: apps/v1
22kind: Deployment
23metadata:
24 name: httpbin
25spec:
26 replicas: 1
27 selector:
28 matchLabels:
29 app: httpbin
30 version: v1
31 template:
32 metadata:
33 labels:
34 app: httpbin
35 version: v1
36 spec:
37 serviceAccountName: httpbin
38 containers:
39 - image: docker.io/kennethreitz/httpbin
40 imagePullPolicy: IfNotPresent
41 name: httpbin
42 ports:
43 - containerPort: 80
再次看一下下图中istio中虚拟服务和目标规则的关系,熔断器的配置需要配置在目标规则上。
接下来创建一个目标规则,在调用httpbin
时设置了熔断器:
1kubectl apply -f - <<EOF
2apiVersion: networking.istio.io/v1alpha3
3kind: DestinationRule
4metadata:
5 name: httpbin
6spec:
7 host: httpbin
8 trafficPolicy:
9 connectionPool:
10 tcp:
11 maxConnections: 1
12 http:
13 http1MaxPendingRequests: 1
14 maxRequestsPerConnection: 1
15 outlierDetection:
16 consecutive5xxErrors: 1
17 interval: 1s
18 baseEjectionTime: 3m
19 maxEjectionPercent: 100
20EOF
在httpbin的目标规则的trafficPolicy
中,定义了maxConnections: 1
和http1MaxPendingRequests: 1
。这表示如果并发的连接和请求数超过一个,在istio-proxy中进行进一步的请求和连接时,后续请求和连接将被阻止。
接下来在k8s的default命名空间内部署httpbin的客户端程序fortio。fortio是专门用来做负载测试的,它可以控制连接数、并发数以及发送HTTP请求的延迟。 因为default命名空间在前面部署bookinfo应用时已经开启了istio sidecar的自动注入功能,所以这里直接部署即可:
1kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml
fortio-deploy.yaml的内容如下:
1apiVersion: v1
2kind: Service
3metadata:
4 name: fortio
5 labels:
6 app: fortio
7 service: fortio
8spec:
9 ports:
10 - port: 8080
11 name: http
12 selector:
13 app: fortio
14---
15apiVersion: apps/v1
16kind: Deployment
17metadata:
18 name: fortio-deploy
19spec:
20 replicas: 1
21 selector:
22 matchLabels:
23 app: fortio
24 template:
25 metadata:
26 annotations:
27 # This annotation causes Envoy to serve cluster.outbound statistics via 15000/stats
28 # in addition to the stats normally served by Istio. The Circuit Breaking example task
29 # gives an example of inspecting Envoy stats.
30 sidecar.istio.io/statsInclusionPrefixes: cluster.outbound,cluster_manager,listener_manager,http_mixer_filter,tcp_mixer_filter,server,cluster.xds-grpc
31 labels:
32 app: fortio
33 spec:
34 containers:
35 - name: fortio
36 image: fortio/fortio:latest_release
37 imagePullPolicy: Always
38 ports:
39 - containerPort: 8080
40 name: http-fortio
41 - containerPort: 8079
42 name: grpc-ping
进入fortio的pod中测试一下,下面的命令将从fortio中向httpbin发一次请求,如果返回200请求成功则说明fortio部署完成,可以进行接下来的熔断测试:
1FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
2kubectl exec -it $FORTIO_POD -c fortio /usr/bin/fortio -- load -curl http://httpbin:8000/get
下面在fortio中向httpbin发送并发数为2的连接(-c 2
),请求20次(-n 20
):
1FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
2kubectl exec -it $FORTIO_POD -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
3
4......
5Code 200 : 13 (65.0 %)
6Code 503 : 7 (35.0 %)
7......
可以看到有35%的请求被熔断器拦截,返回了503错误。而HTTP503错误表示服务不可用,通常造成这种情况的原因是由于服务器停机维护或者已超载,返回这个状态码也是十分合适的。
接下来将并发连接数提高到3个,请求20次:
1FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
2kubectl exec -it $FORTIO_POD -c fortio -- /usr/bin/fortio load -c 3 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
3
4Code 200 : 2 (10.0 %)
5Code 503 : 18 (90.0 %)
可以看到只有10%的请求成功,有90%的请求被熔断器拦截。