【注意】最后更新于 July 26, 2021,文中内容可能已过时,请谨慎使用。
前面几节内容我们学习了Istio API资源对象中的虚拟服务VirtualService
, 目标规则DestinationRule
, Gateway
。
使用它们可以实现将集群外部流量(http或tcp)接入到服务网格内部,可以进行一些常见的流量管理功能如: 设置请求路由、故障注入、流量转移(http或tcp)等。
本节我们学习使用istio进行流量管理的另外两个常见功能:设置请求超时和熔断。
设置请求超时
对HTPP服务的请求超时,可以通过虚拟服务的路由规则中的timeout
字段来指定。默认请求下这个配置是禁用的。
下面基于bookinfo应用完成这个测试。

本测试将reviews
服务的超时设置为1秒,为了便于观察测试结果,还将使用istio的故障注入功能为对ratings
服务注入2秒的延迟故障。
首先执行下面的命令初始化bookinfo应用各服务的路由规则:
1
|
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
|
修改reviews
服务的虚拟服务,将对reviews
服务的请求全都路由到v2版本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v2
EOF
|
对ratings
服务进行故障注入,注入2秒的延迟:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
delay:
percent: 100
fixedDelay: 2s
route:
- destination:
host: ratings
subset: v1
EOF
|
此时使用我们之前配置好的Istio Gateway入口访问bookinfo应用https://bookinfo.example.com/productpage,会发现bookinfo应用运行正常(显示了评级的星型符号),但是每次刷新页面,都会有2秒的延迟。
因为reviews:
v2版本的服务是通过调用ratings
服务获取评级信息的,默认reviews服务默认是没有设置请求超时的,所以它会等待ratings服务中注入的2秒延迟,每次刷新页面也就有了2秒的延迟。
由于productpage
服务中存在硬编码重试,即遇到错误时会重试1次,下面我们将对review服务的调用设置一个0.5秒的超时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v2
timeout: 0.5s
EOF
|
此时再刷新/productpage
页,会有1秒的延迟,且页面中的书籍评级信息出现错误Error fetching product reviews!
。这是因为这个请求的调用链如下productpage(出现请求超时错误时重试1次) --> reviews(请求超时设置为0.5秒) ---> ratings(注入了2秒的延迟)
。可以看出通过设置对reviews服务的请求超时,实现了微服务治理中设置请求超时的功能,这完全是在服务网格中实现的,没有侵入微服务的业务逻辑。
在服务治理中通过设置请求超时,可以避免大量请求长时间占用资源。
熔断
熔断是创建弹性微服务的重要模式,熔断可以使应用程序具备应对来自故障、潜在峰值和其他未知网络因素的能力。
熔断机制是应对雪崩效应的一种微服务链路保护机制。服务雪崩是指当调用链中的某个环节,特别是服务提供方不可用时,将会导致上游环节不可用,并最终将这个影响扩大到整个系统中,导致整个系统的不可用。
下面将演示istio中流量管理的熔断功能。
首先部署用于测试的httpbin
应用,将其部署在k8s的default namespace内,因为default命名空间在前面部署bookinfo应用时已经开启了istio sidecar的自动注入功能,所以这里直接部署httpbin
应用即可:
1
|
kubectl apply -f samples/httpbin/httpbin.yaml
|
httpbin.yaml的内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
|
再次看一下下图中istio中虚拟服务和目标规则的关系,熔断器的配置需要配置在目标规则上。

接下来创建一个目标规则,在调用httpbin
时设置了熔断器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
outlierDetection:
consecutive5xxErrors: 1
interval: 1s
baseEjectionTime: 3m
maxEjectionPercent: 100
EOF
|
在httpbin的目标规则的trafficPolicy
中,定义了maxConnections: 1
和http1MaxPendingRequests: 1
。这表示如果并发的连接和请求数超过一个,在istio-proxy中进行进一步的请求和连接时,后续请求和连接将被阻止。
接下来在k8s的default命名空间内部署httpbin的客户端程序fortio。fortio是专门用来做负载测试的,它可以控制连接数、并发数以及发送HTTP请求的延迟。
因为default命名空间在前面部署bookinfo应用时已经开启了istio sidecar的自动注入功能,所以这里直接部署即可:
1
|
kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml
|
fortio-deploy.yaml的内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
apiVersion: v1
kind: Service
metadata:
name: fortio
labels:
app: fortio
service: fortio
spec:
ports:
- port: 8080
name: http
selector:
app: fortio
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: fortio-deploy
spec:
replicas: 1
selector:
matchLabels:
app: fortio
template:
metadata:
annotations:
# This annotation causes Envoy to serve cluster.outbound statistics via 15000/stats
# in addition to the stats normally served by Istio. The Circuit Breaking example task
# gives an example of inspecting Envoy stats.
sidecar.istio.io/statsInclusionPrefixes: cluster.outbound,cluster_manager,listener_manager,http_mixer_filter,tcp_mixer_filter,server,cluster.xds-grpc
labels:
app: fortio
spec:
containers:
- name: fortio
image: fortio/fortio:latest_release
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http-fortio
- containerPort: 8079
name: grpc-ping
|
进入fortio的pod中测试一下,下面的命令将从fortio中向httpbin发一次请求,如果返回200请求成功则说明fortio部署完成,可以进行接下来的熔断测试:
1
2
|
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD -c fortio /usr/bin/fortio -- load -curl http://httpbin:8000/get
|
下面在fortio中向httpbin发送并发数为2的连接(-c 2
),请求20次(-n 20
):
1
2
3
4
5
6
7
|
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
......
Code 200 : 13 (65.0 %)
Code 503 : 7 (35.0 %)
......
|
可以看到有35%的请求被熔断器拦截,返回了503错误。而HTTP503错误表示服务不可用,通常造成这种情况的原因是由于服务器停机维护或者已超载,返回这个状态码也是十分合适的。
接下来将并发连接数提高到3个,请求20次:
1
2
3
4
5
|
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD -c fortio -- /usr/bin/fortio load -c 3 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
Code 200 : 2 (10.0 %)
Code 503 : 18 (90.0 %)
|
可以看到只有10%的请求成功,有90%的请求被熔断器拦截。
参考