背景信息
社区Istio提供DestinationRule进行熔断配置,以官方的一个demo为例
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-cb-policy
spec:
host: reviews.prod.svc.cluster.local
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http2MaxRequests: 1000
maxRequestsPerConnection: 10
outlierDetection:
consecutive5xxErrors: 7
interval: 5m
baseEjectionTime: 15m
可以看出DestinationRule提供的熔断功能,通过Envoy连接池实现对上游集群的限流熔断,并周期性检查一些异常指标,例如5xx错误,达到一定累积量则将该主机从连接池中隔离出去,从而实现熔断效果。显然,社区的熔断功能仅支持服务级别熔断,无法细化到路由级,熔断的情况下影响面比较大。
因此,CSM提供一种新的CRD CTGCircuitBreaker,可以限定仅作用于特定的路由,提供更细粒度的熔断控制。
本文以Bookinfo和Httpbin为例,模拟熔断效果。其中httpbin的熔断不会对bookinfo产生影响。
验证准备
部署网关
网关安装可以参考 入口网关-应用服务网格-用户指南-网关 - 天翼云 (ctyun.cn)。bookinfo的安装可以参考部署bookinfo应用到CSM实例-应用服务网格-快速入门 - 天翼云 (ctyun.cn)。
网关deployment部署后,按以下规则配置VirtualService。这条规则表示网关后端分别路由到productpage和httpbin,分别按不同的url路由,两者互相独立,为了后续可以验证路由级的熔断,httpbin不会影响productpage的业务。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: bookinfo
namespace: default
spec:
gateways:
- bookinfo-gateway
hosts:
- bookinfo.com
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
name: bookinfo-vs
route:
- destination:
host: productpage.default.svc.cluster.local
port:
number: 9080
- match:
- uri:
prefix: /httpbin
name: httpbin-route-name1
rewrite:
uri: /
route:
- destination:
host: httpbin.foo.svc.cluster.local
port:
number: 8000
部署httpbin
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
namespace: foo
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
namespace: foo
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: foo
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: registry-vpc-crs-huadong1.cnsp-internal.ctyun.cn/library/httpbin:latest
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
开始验证
创建CTGCircuitBreaker,例如
apiVersion: istio.ctyun.cn/v1beta1
kind: CTGCircuitBreaker
metadata:
name: router-breaker
namespace: istio-system
spec:
configs:
- breaker_config:
break_duration: 10s
custom_response:
body: "hello, break!\r\n"
header_to_add:
x-envoy-circuitbreak: "true"
status_code: 499
error_percent:
value: 60
max_slow_requests: 10
min_request_amount: 3
slow_request_rt: 0.1s
window_size: 11s
match:
vhost:
name: bookinfo.com
port: 80
route:
header_match:
- exact_match: value1
name: key1
- exact_match: value2
name: key2
name_match: httpbin-route-name1
workloadSelector:
labels:
istio: ingressgateway
这条熔断规则作用于http-bin-route-name1,对应VirtualService中的路由名。spec具体字段说明如下:
字段名 | 类型 | 字段说明 |
---|---|---|
configs | []*CircuitBreakerConfig | 熔断配置,详细字段下文说明。 |
workloadSelector | *WorkloadSelector | 通用的workloadSelector,以labels过滤所作用的workload。 |
CircuitBreakerConfig
字段名 | 类型 | 字段说明 |
---|---|---|
name | string | 熔断规则名 |
match | BreakerMatcher | 熔断规则的匹配条件,详细字段下文说明 |
breaker_config | BreakerConfig | 熔断条件以及表现等,详细字段下文说明 |
BreakerMatcher
字段 | 类型 | 说明 |
---|---|---|
vhost | *VhostMatcher | VirtualHost匹配条件 |
VhostMatcher
字段 | 类型 | 说明 |
---|---|---|
name | string | 匹配的VirtualHost名称 |
port | int | 端口号 |
route | *RouteMatcher | 匹配的路由规则 |
RouteMatcher
字段 | 类型 | 说明 |
---|---|---|
name_match | string | 对应VirtualService里面的某条规则 |
header_match | []*HeaderMatcher | 匹配服务请求的Header |
HeaderMatcher
字段 | 类型 | 说明 |
---|---|---|
name | string | Header名称 |
regex_match | string | 正则匹配 |
exact_match | string | 精确匹配 |
prefix_match | string | 前缀匹配,以什么开头进行匹配 |
suffix_match | string | 后缀匹配,以什么结尾进行匹配 |
present_match | bool | 配置为true,表示存在Header即可,无需关注Header Value的取值。 配置为false,表示不存在Header。 |
invert_match | bool | 默认为false。 配置为true,表示上述匹配结果取反。 配置为false,表示遵循上述匹配结果。 |
BreakerConfig
字段 | 类型 | 说明 |
---|---|---|
window_size | string | 统计时间窗口,默认10s,最大不能超过12s |
break_duration | string | 熔断时长,默认30s,最大不超过180s |
slow_request_rt | string | 定义慢请求的响应延迟时间,超过该响应时长的请求则被认定为慢请求 |
max_slow_requests | int | 最大慢请求次数,必须为整数,例如:1000。超过该次数的新请求会被熔断 |
error_percent | *Percent | 失败率阈值,时间窗口内错误请求(5XX)比例超过该值,则触发熔断 |
min_request_amount | int | 最少请求次数,防止请求量太少时,error_percent统计失真。 |
custom_response | *CustomResponse | 自定义返回内容,当请求被熔断时代替后端返回。 |
注意表示时间范围的字符串,可以使用以下时间单位的组合:
nsec 纳秒
usec/μs 微秒
ms 毫秒
s 或 sec 秒
m 或 min 分钟
h 或 hour 小时。
Percent
字段 | 类型 | 说明 |
---|---|---|
value | double | 百分比值,只能在[0.0,100.0]中取值。 |
CustomResponse
字段 | 类型 | 说明 |
---|---|---|
status_code | int | HTTP响应状态码 |
header_to_add | map[string]string | 自定义响应添加的Headers |
body | string | 自定义响应Body内容 |
执行脚本验证效果
验证失败率脚本
#!/bin/sh
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/status/503"
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/status/200"
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/status/503"
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/status/200" | grep 'hello, break!'
echo "sleep for 10 second to try if recover"
sleep 10
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/delay/1" -sv
验证前需要删除header_match条件,该脚本只模拟后端返回错误,不设置请求header。这个脚本发起了两次模拟httpbin返回503,一次200。失败率已达66%,下一次请求会被熔断(可以通过设置error_percent控制失败率,通过min_request_amount控制最少生效次数)。随后sleep 10s在请求验证是否不再熔断。
hello,break的熔断文本可以自行通过custom_response设置成您想要的返回内容。
sleep 10s,这个恢复间隔也可以通过break_duration设置。
验证慢调用脚本
#!/bin/sh
for i in {1..10}; do
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/delay/1"
done
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/delay/1" | grep 'hello, break!'
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/productpage" -sv
echo "sleep for 10 second to try if recover"
sleep 10
curl -H "host: bookinfo.com" "http://$GATEWAY_URL/httpbin/delay/1" -sv
验证前需要删除header_match条件,该脚本只模拟后端返回超时,不设置请求header。这个脚本通过发起10次delay 1s的调用,使得熔断器打开,此处的delay时间和次数,可以通过slow_request_rt max_slow_requests来控制,脚本内容中的1也可以换成0.5之类的非整数delay间隔。
后续验证是否在请求会返回hello,break,以及sleep 10s后是否恢复正常。
验证header过滤条件脚本
#!/bin/sh
for i in {1..10}; do
curl -H "host: bookinfo.com" -H "key1: value1" -H "key2: value2" "http://$GATEWAY_URL/httpbin/delay/1"
done
curl -H "host: bookinfo.com" -H "key1: value1" -H "key2: value2" "http://$GATEWAY_URL/httpbin/delay/1" | grep 'hello, break!'
echo "try productpage to see if blocked"
curl -H "host: bookinfo.com" -H "key1: value1" -H "key2: value2" "http://$GATEWAY_URL/productpage" -sv
echo "sleep for 10 second to try if recover"
sleep 10
curl -H "host: bookinfo.com" -H "key1: value1" -H "key2: value2" "http://$GATEWAY_URL/httpbin/delay/1" -sv
验证前需要设置好header_match条件。调整脚本中的-H参数改写key和value值,同时调整header_match字段,验证httpbin是否熔断,也验证一下productpage是否没有熔断。sleep 10s后验证是否恢复。