前言
本小節繼續來描述istio對於流量的各種操作
流量鏡像
對標nginx的mirror功能,複製一份流量到對應的地址去,通常用來做從線上環境引流至其他環境做測試或者分析
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: backend-vs
namespace: default
spec:
hosts:
- backend-service
- api.wilsontest.com
http:
- mirror:
host: backend-service
subset: v1
mirrorPercentage:
value: 100
route:
- destination:
host: backend-service
subset: v0
流量先到v0版本,istio-proxy複製一份流量到v1版本。如果不想1比1復刻,可以調整mirrorPercentage百分比功能
如果mirror host的目標不存在,怎麼發現該錯誤及時調整host配置呢?
超時/重試
配置超時/重試的原因主要是為了解決:
- 調用外部網絡的接口,很容易產生諸如502、504、499,甚至連接中斷等問題,有了重試,可以儘可能的嘗試再次發起,而不是直接報錯
- 公用雲網絡抖動,導致客户端收到一堆5xx,從而引起客户產生不適
- 後端服務沒有優雅更新,一旦發版,導致大量502,重試可以緩解502,避免告警風暴
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: backend-retry
spec:
hosts:
- backend-service
http:
- route:
- destination:
host: backend-service
timeout: 1s
retries:
attempts: 3 # 最大重試次數
perTryTimeout: 1s # 每次嘗試的超時
retryOn: # 觸發重試的條件
- 5xx
- gateway-error
- connect-failure
- refused-stream
有位老哥説了,如果一套qps很高的集羣,一旦發生重試,那就意味着短時間之內上游服務的qps至少翻一倍(第一波請求不成功,很快第二波請求就要來了),那這時候上游服務就有被沖垮的風險
説的沒錯,重試是為了提高請求的成功率,但是不可避免增加系統負載,並且增加請求的響應時間,如果大量重試,那就會導致重試風暴,帶來更大的問題
重試次數
為了避免重試風暴,在配置策略的時候應該考慮合理的重試次數
retries:
attempts: 3 # 最大重試次數
perTryTimeout: 1s # 每次嘗試的超時
重試3次,每次間隔1s,然後就應該報錯,介入查看了
級聯超時
超時時間逐層遞減,前端超時 > 網關超時 > 服務超時
frontend: timeout: 5s
nginx-test: timeout: 3s
backend-service: timeout: 2s
退避策略
簡而言之,就是重試失敗之後不是馬上重試,而是等一段時間再重試
- 固定退避(Fixed Backoff):每次重試等待固定時間
- attempt 1: 等待 100ms
- attempt 2: 等待 100ms
- attempt 3: 等待 100ms
- 線性退避(Linear Backoff):等待時間線性增加
- attempt 1: 等待 100ms
- attempt 2: 等待 200ms
- attempt 3: 等待 300ms
- 指數退避(Exponential Backoff):等待時間按指數增加(乘以係數),最使用也最常用
- attempt 1: 等待 100ms
- attempt 2: 等待 200ms
- attempt 3: 等待 400ms
- attempt 4: 等待 800ms
- attempt 5: 等待 1600ms
- 隨機退避(Jitter/隨機抖動):在退避時間中加入隨機性,打破同一時間重試,避免"驚羣效應"
- attempt 1: 等待 100ms ± 隨機時間
- attempt 2: 等待 200ms ± 隨機時間
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: backend-vs
namespace: default
spec:
hosts:
- backend-service
- api.wilsontest.com
http:
- retries:
attempts: 10
perTryTimeout: 1s
retryOn: 5xx,connect-failure
route:
- destination:
host: backend-service
subset: v0
測試istio-proxy的策略
istio-proxy自帶了指數退避與隨機退避,初始25ms
為了探索istio-proxy是否帶有指數退避與隨機退避的特點,特意設置attempts: 10(日常用可以設置小一點,比如筆者通常設置為3)
設置後端報錯代碼,只要報錯5xx即可,所以我直接將代碼的關鍵字改錯,應該會報語法錯誤或者方法找不到之類的
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/tornado/web.py", line 1846, in _execute
result = method(*self.path_args, **self.path_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/test.py", line 9, in get
self.writ(ret)
^^^^^^^^^
AttributeError: 'TestFlow' object has no attribute 'writ'
都準備好了,開始測試:
curl -s -H 'host: api.wilsontest.com' 10.22.12.178:30785/test- 查看日誌,有11條日誌,符合預期:第1次訪問+
attempts: 10[2026-02-05T06:51:41.322Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:41.332Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:41.369Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=2ms route=default [2026-02-05T06:51:41.441Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:41.463Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=2ms route=default [2026-02-05T06:51:41.480Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:41.660Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:41.787Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:41.804Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:41.978Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=1ms route=default [2026-02-05T06:51:42.116Z] "GET /test HTTP/1.1" 500 - upstream=10.244.0.73:10000 duration=2ms route=default - 分析下時間
序號 時間戳 與上一次間隔 1 41.322 — 2 41.332 +10ms 3 41.369 +37ms 4 41.441 +72ms 5 41.463 +22ms 6 41.480 +17ms 7 41.660 +180ms 8 41.787 +127ms 9 41.804 +17ms 10 41.978 +174ms 11 42.116 +138ms - 從日誌看來確實滿足了
指數+隨機,初始 backoff:~25ms、指數增長、加入 jitter(隨機抖動)- 10ms → 37ms → 72ms → 180ms → 127ms → 174ms → 138ms
經過這次簡單的測試:
- 配置重試應該要針對冪等的request,非冪等是絕對不能使用重試的
- retries應該要配置小一些,否則就會出現重試風暴,就像測試中10次,相當於原請求放大了10倍
熔斷
熔斷是為了保護後端服務不被流量風暴淹沒,保護系統整體穩定
-
目標:如果後端檢測5xx,超過3次,就將該pod踢下線,30s之後又加回來
apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: backend-dr namespace: default spec: host: backend-service subsets: - labels: version: v0 name: v0 trafficPolicy: outlierDetection: baseEjectionTime: 30s consecutive5xxErrors: 3 interval: 5s maxEjectionPercent: 100baseEjectionTime: 30s:服務被下線的時間,30sconsecutive5xxErrors: 3:觸發熔斷的條件,有3次5xxinterval: 5s:檢測間隔,5smaxEjectionPercent: 100,被下線的服務比例,100%
-
後端backend服務依然會報錯500,先訪問3次,
curl -s -H 'host: api.wilsontest.com' 10.22.12.178:30785/testTraceback (most recent call last): File "/usr/local/lib/python3.11/site-packages/tornado/web.py", line 1846, in _execute result = method(*self.path_args, **self.path_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/test.py", line 9, in get self.writ(ret) -
第四次再訪問
no healthy upstream -
符合預期,第四次服務直接被熔斷了,並且由於backend的pod只有1個,istio下線了,導致nginx沒有upstream
限流
首先基於http1.1,每次發起http並不是短鏈了,而是長連接。為了不讓每次都產生3次握手與4次揮手的連接消耗,istio-proxy與後端服務backend之間會維護一個長連接
-
配置在DestinationRule上
apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: backend-dr namespace: default spec: host: backend-service subsets: - labels: version: v0 name: v0 trafficPolicy: connectionPool: http: http1MaxPendingRequests: 1 maxRequestsPerConnection: 5http1MaxPendingRequests: 1與maxRequestsPerConnection: 5是為了方便測試,改得非常的小http1MaxPendingRequests: 1:等待“可用連接”的 HTTP 請求數量,如果沒有可用連接,最多允許1個,超出就報503maxRequestsPerConnection: 5:一條 TCP 連接上最多處理多少個 HTTP 請求
-
使用wrk壓測工具,用20個併發,同時發送20個連接,向目標url發送請求,持續1s
▶ wrk -t20 -c20 -d1s -H 'Host: api.wilson.com' http://10.22.12.178:30785/test Running 1s test @ http://10.22.12.178:30785/test 20 threads and 20 connections Thread Stats Avg Stdev Max +/- Stdev Latency 10.66ms 3.18ms 21.85ms 76.73% Req/Sec 93.55 16.33 171.00 80.75% 1990 requests in 1.10s, 650.09KB read Non-2xx or 3xx responses: 92 Requests/sec: 1808.21 Transfer/sec: 590.70KB- 可以看到,1秒之內有1990個請求發送至目標url
- 其中有92個請求有問題
-
檢查日誌
... [2026-02-06T07:37:08.168Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.73:10000 duration=5ms route=default [2026-02-06T07:37:08.169Z] "GET /test HTTP/1.1" 503 UO upstream=- duration=0ms route=default [2026-02-06T07:37:08.169Z] "GET /test HTTP/1.1" 0 DC upstream=10.244.0.73:10000 duration=4ms route=default ...- http_code是200是正常請求,503就是熔斷保護的結果,觸發了istio熔斷保護而返回客户端503
- http_code是0,通常意味着 連接在 HTTP 響應頭完整返回之前就已經斷開了,這非常類似於nginx的499。他們本質都描述了一個問題,客户端沒有等到結果就終止連接了,這應該和我們壓測只持續了1s有關係
聯繫我
- 聯繫我,做深入的交流

至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...