背景信息
社區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產生影響。
驗證準備
部署網關
網關安裝可以參考 應用服務網格-入口網關。bookinfo的安裝可以參考部署bookinfo應用到CSM實例。
網關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.daliqc.cn/library/httpbin:latest
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
開始驗證
創建CTGCircuitBreaker,例如
apiVersion: istio.daliqc.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
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 | 匹配的端口號,網關一般對外端口與內部轉發端口不一致,用戶請求中可能不攜帶端口號,實踐中一般路由配置基于uri或者header的規則,此時沒必要配置該字段。 |
| 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" "//$GATEWAY_URL/httpbin/status/503"
curl -H "host: bookinfo.com" "//$GATEWAY_URL/httpbin/status/200"
curl -H "host: bookinfo.com" "//$GATEWAY_URL/httpbin/status/503"
curl -H "host: bookinfo.com" "//$GATEWAY_URL/httpbin/status/200" | grep 'hello, break!'
echo "sleep for 10 second to try if recover"
sleep 10
curl -H "host: bookinfo.com" "//$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" "//$GATEWAY_URL/httpbin/delay/1"
done
curl -H "host: bookinfo.com" "//$GATEWAY_URL/httpbin/delay/1" | grep 'hello, break!'
curl -H "host: bookinfo.com" "//$GATEWAY_URL/productpage" -sv
echo "sleep for 10 second to try if recover"
sleep 10
curl -H "host: bookinfo.com" "//$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" "//$GATEWAY_URL/httpbin/delay/1"
done
curl -H "host: bookinfo.com" -H "key1: value1" -H "key2: value2" "//$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" "//$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" "//$GATEWAY_URL/httpbin/delay/1" -sv
驗證前需要設置好header_match條件。調整腳本中的-H參數改寫key和value值,同時調整header_match字段,驗證httpbin是否熔斷,也驗證一下productpage是否沒有熔斷。sleep 10s后驗證是否恢復。