istio熔斷


熔斷主要是無感的處理服務異常並保證不會發生級聯甚至雪崩的服務異常。在微服務方面體現是對異常的服務情況進行快速失敗,它對已經調用失敗的服務不再會繼續調用,如果仍需要調用此異常服務,它將立刻返回失敗。與此同時,它一直監控服務的健康狀況,一旦服務恢復正常,則立刻恢復對此服務的正常訪問。這樣的快速失敗策略可以降低服務負載壓力,很好地保護服務免受高負載的影響。

一個熔斷器可以有三種狀態:關閉、打開和半開,默認情況下處於關閉狀態。在關閉狀態下,無論請求成功或失敗,到達預先設定的故障數量閾值前,都不會觸發熔斷。而當達到閾值時,熔斷器就會打開。當調用處於打開狀態的服務時,熔斷器將斷開請求,這意味着它會直接返回一個錯誤,而不去執行調用。通過在客戶端斷開下游請求的方式,可以在生產環境中防止級聯故障的發生。在經過事先配置的超時時長后,熔斷器進入半開狀態,這種狀態下故障服務有時間從其中斷的行為中恢復。如果請求在這種狀態下繼續失敗,則熔斷器將再次打開並繼續阻斷請求。否則熔斷器將關閉,服務將被允許再次處理請求。

熔斷器對比 Hystrix vs Istio

Hystrix是Netflix OSS的一部分,是微服務領域的領先的熔斷工具。Hystrix可以被視為白盒監控工具,而Istio可以被視為黑盒監控工具,主要是因為Istio從外部監控系統並且不知道系統內部如何工作。另一方面,每個服務中有Hystrix來獲取所需的數據。
Istio是無縫銜接服務,istio可以在不更改應用程序代碼的情況下配置和使用。Hystrix的使用需要更改每個服務來引入Hystrix libraries。
Istio提高了網格中服務的可靠性和可用性。但是,應用程序需要處理錯誤並有一定的fall back行為。例如當負載平衡池中的所有服務實例都出現異常時,Envoy將返回HTTP 503。當上游服務返回 HTTP 503 錯誤,則應用程序需要采取回退邏輯。與此同時,Hystrix也提供了可靠的fall back實現。它允許擁有所有不同類型的fall backs:單一的默認值、緩存或者去調用其他服務。

envoy對應用程序來說幾乎完全無感和透明。Hystrix則必須在每個服務調用中嵌入Hystrix庫。
Istio的熔斷應用幾乎無語言限制,但Hystrix主要針對的是Java應用程序。

Istio是使用了黑盒方式來作為一種代理管理工具。它實現起來很簡單,不依賴於底層技術棧,而且可以在部署后也可以進行配置和修改。Hystrix需要在代碼級別處理斷路器,可以設置級聯和一些附加功能,它需要在開發階段時做出降級決策,后期優化配置成本高。

Istio限流

Istio無需對代碼進行任何更改就可以為應用增加熔斷和限流功能。Istio中熔斷和限流在DestinationRule的CRD資源的TrafficPolicy中設置,一般設置連接池(ConnectionPool)限流方式和異常檢測(outlierDetection)熔斷方式。兩者ConnectionPool和outlierDetection各自配置部分參數,其中參數有可能存在對方的功能,並沒有很嚴格的區分出來,如主要進行限流設置的ConnectionPool中的maxPendingRequests參數,最大等待請求數,如果超過則也會暫時的熔斷。

連接池(ConnectionPool)設置
ConnectionPool可以對上游服務的並發連接數和請求數進行限制,適用於TCP和HTTP。ConnectionPool又稱之是限流。

官方定義的屬性

 設置在DestinationRule中的配置如下圖:

連接池相關參數解析

TCP設置

Tcp連接池設置http和tcp上游連接的設置。相關參數設置如下:

maxConnections:到目標主機的HTTP1/TCP最大連接數量,只作用於http1.1,不作用於http2,因為后者只建立一次連接。

connectTimeout:tcp連接超時時間,默認單位秒。也可以寫其他單位,如ms。

tcpKeepalive:如果在套接字上設置SO_KEEPALIVE可以確保TCP 存活

TCP的TcpKeepalive設置:

Probes:在確定連接已死之前,在沒有響應的情況下發送的keepalive探測的最大數量。默認值是使用系統級別的配置(除非寫詞參數覆蓋,Linux默認值為9)。

Time:發送keep-alive探測前連接存在的空閑時間。默認值是使用系統的配置(除非寫此參數,Linux默認值為7200s(即2小時)。

interval:探測活動之間的時間間隔。默認值是使用系統的配置(除非被覆蓋,Linux默認值為75秒)。

HTTP設置

http連接池設置用於http1.1/HTTP2/GRPC連接。

http1MaxPendingRequests:http請求pending狀態的最大請求數,從應用容器發來的HTTP請求的最大等待轉發數,默認是1024。

http2MaxRequests:后端請求的最大數量,默認是1024。

maxRequestsPerConnection:在一定時間內限制對后端服務發起的最大請求數,如果超過了這個限制,就會開啟限流。如果將這一參數設置為 1 則會禁止 keepalive 特性;

idleTimeout:上游連接池連接的空閑超時。空閑超時被定義為沒有活動請求的時間段。如果未設置,則沒有空閑超時。當達到空閑超時時,連接將被關閉。注意,基於請求的超時意味着HTTP/2ping將無法保持有效連接。適用於HTTP1.1和HTTP2連接;

maxRetries:在給定時間內,集群中所有主機都可以執行的最大重試次數。默認為3。

與Envoy參數對比

熔斷和限流是分布式系統的重要組成部分,優點是快速失敗並迅速向下游反饋。Istio是通過Envoy Proxy 來實現熔斷和限流機制的,Envoy 強制在網絡層面配置熔斷和限流策略,這樣就不必為每個應用程序單獨配置或重新編程。Envoy支持各種類型的全分布式(不協調)限流。

IstioConnectionPool與 Envoy 的限流參數對照表:

Envoy paramether
Envoy  upon object
Istio parameter
Istio  upon ojbect
max_connections
cluster.circuit_breakers
maxConnections
TCPSettings
max_pending_requests
cluster.circuit_breakers
http1MaxPendingRequests
HTTPSettings
max_requests
cluster.circuit_breakers
http2MaxRequests
HTTPSettings
max_retries
cluster.circuit_breakers
maxRetries
HTTPSettings
connect_timeout_ms
cluster
connectTimeout
TCPSettings
max_requests_per_connection
cluster
maxRequestsPerConnection
HTTPSettings

maxConnections: 表示在任何給定時間內,Envoy 與上游集群建立的最大連接數,限制對后端服務發起的 HTTP/1.1 連接數。該配置僅適用於 HTTP/1.1 協議,因為HTTP/2 協議可以在同一個 TCP 連接中發送多個請求,而 HTTP/1.1 協議在同一個連接中只能處理一個請求。如果超過了這個限制(即斷路器溢出),集群的upstream_cx_overflow計數器就會增加。

maxPendingRequests: 表示待處理請求隊列的長度,如果超過了這個限制,就會開啟限流。因為HTTP/2 是通過單個連接並發處理多個請求的,因此該策略僅在創建初始 HTTP/2 連接時有用,之后的請求將會在同一個 TCP 連接上多路復用。對於HTTP/1.1 協議,只要沒有足夠的上游連接可用於立即分派請求,就會將請求添加到待處理請求隊列中,因此該斷路器將在該進程的生命周期內保持有效。如果該斷路器溢出,集群的upstream_rq_pending_overflow計數器就會增加。

maxRequestsPerConnection: 表示在任何給定時間內,上游集群中主機可以處理的最大請求數,限制對后端服務發起的HTTP/2 請求數。實際上,這適用於僅 HTTP/2 集群,因為 HTTP/1.1 集群由最大連接數斷路器控制。如果該斷路器溢出,集群的upstream_rq_pending_overflow 計數器就會遞增。

maxRetries:在任何給定時間內,集群中所有主機都可以執行的最大重試次數。一般情況下,建議對偶爾的故障積極地進行斷路重試,因為總體重試容量不會爆炸並導致大規模級聯故障。如果這個斷路器溢出,則集群的upstream_rq_retry_overflow計數器將增加。

envoy新加參數(后期istio可能會增加)

maximumconcurrent connection pools:可以並發實例化的連接池的最大數量。一些特性,比如Original SrcListener Filter,可以創建無限數量的連接池。當集群耗盡其並發連接池時將會回收空閑連接。如果不能回收,斷路器就會溢出。這與連接池中的集群最大連接不同,連接池中的連接通常不會超時。Connections自動清理;連接池不需要。注意,為了使連接池發揮作用,它至少需要一個上游連接,因此這個值應該小於集群最大連接。

在上游集群和優先級上針對不同的組件,都可以分別進行單獨的配置參數進行請求限制。通過統計可以觀察到這些斷路器的狀態,包括斷路器打開前剩余數量的斷路器。注意,在HTTP請求下將會重新設置路由過濾器的x-envoy-overloaded報頭。

Istio中的熔斷

Istio的 熔斷 可以在 流量策略 中配置。Istio的 自定義資源Destination Rule里,TrafficPolicy字段下有兩個和熔斷相關的配置:ConnectionPoolSettings 和 OutlierDetection。
ConnectionPoolSettings可以為服務配置連接的數量。OutlierDetection用來控制從負載均衡池中剔除不健康的實例。
例如,ConnectionPoolSettings控制請求的最大數量,掛起請求,重試或者超時;OutlierDetection 設置服務被從連接池剔除時發生錯誤的請求數,可以設置最小逐出時間和最大逐出百分比。有關完整的字段列表,請參考文檔

啟動 Httpbin 樣例程序。

如果您啟用了 Sidecar 自動注入,通過以下命令部署 httpbin 服務:

kubectl apply -f samples/httpbin/httpbin.yaml

配置熔斷器

創建一個目標規則,在調用 httpbin 服務時應用熔斷設置:

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:
      consecutiveErrors: 1
      interval: 1s
      baseEjectionTime: 3m
      maxEjectionPercent: 100
EOF

驗證目標規則是否已正確創建:

kubectl get destinationrule httpbin -o yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: httpbin
  ...
spec:
  host: httpbin
  trafficPolicy:
    connectionPool:
      http:
        http1MaxPendingRequests: 1
        maxRequestsPerConnection: 1
      tcp:
        maxConnections: 1
    outlierDetection:
      baseEjectionTime: 180.000s
      consecutiveErrors: 1
      interval: 1.000s
      maxEjectionPercent: 100

使用ConnectionPoolSettings字段中的這些設置,在給定的時間內只能和notifications 服務建立一個連接:每個連接最多只能有一個掛起的請求。如果達到閾值,熔斷器將開始阻斷請求。
OutlierDetection部分的設置用來檢查每秒調用服務是否有錯誤發生。如果有,則將服務從負載均衡池中逐出至少三分鍾(100%最大彈出百分比表示,如果需要,所有的服務實例都可以同時被逐出)。

在手動創建Destination Rule資源時有一件事需要特別注意,那就是是否為該服務啟用了mTLS。如果是的話,還需要在Destination Rule中設置如下字段,否則當調用movies服務時,調用方可能會收到503錯誤:

    trafficPolicy:
       tls:
      mode: ISTIO_MUTUAL

還可以為特定namespace 或特定服務啟用全局的mTLS。你應該了解這些設置以便確定是否把trafficPolicy.tls.mode設置為 ISTIO_MUTUAL。更重要的是,當你試圖配置一個完全不同的功能(例如熔斷)時,很容易忘記設置此字段。

    提示:在創建Destination Rule前總是考慮mTLS!

為了觸發熔斷,讓我們同時從兩個連接來調用 notifications服務。maxConnections字段被設置為1。這時應該會看到503與200的響應同時到達。
當一個服務從客戶端接收到的負載大於它所能處理的負載(如熔斷器中配置的那樣),它會在調用之前返回503錯誤。這是防止錯誤級聯的一種方法。

增加一個客戶端

創建客戶端程序以發送流量到 httpbin 服務。這是一個名為 Fortio 的負載測試客戶端,它可以控制連接數、並發數及發送 HTTP 請求的延遲。通過 Fortio 能夠有效的觸發前面 在 DestinationRule 中設置的熔斷策略。

向客戶端注入 Istio Sidecar 代理,以便 Istio 對其網絡交互進行管理:

kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml

登入客戶端 Pod 並使用 Fortio 工具調用 httpbin 服務。-curl 參數表明發送一次調用:

$ export FORTIO_POD=$(kubectl get pods -l app=fortio -o 'jsonpath={.items[0].metadata.name}')
$ kubectl exec "$FORTIO_POD" -c fortio -- /usr/bin/fortio curl -quiet http://httpbin:8000/get
HTTP/1.1 200 OK
server: envoy
date: Tue, 25 Feb 2020 20:25:52 GMT
content-type: application/json
content-length: 586
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 36

{
  "args": {},
  "headers": {
    "Content-Length": "0",
    "Host": "httpbin:8000",
    "User-Agent": "fortio.org/fortio-1.3.1",
    "X-B3-Parentspanid": "8fc453fb1dec2c22",
    "X-B3-Sampled": "1",
    "X-B3-Spanid": "071d7f06bc94943c",
    "X-B3-Traceid": "86a929a0e76cda378fc453fb1dec2c22",
    "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=68bbaedefe01ef4cb99e17358ff63e92d04a4ce831a35ab9a31d3c8e06adb038;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
  },
  "origin": "127.0.0.1",
  "url": "http://httpbin:8000/get"
}

可以看到調用后端服務的請求已經成功!接下來,可以測試熔斷。

觸發熔斷器

DestinationRule 配置中,您定義了 maxConnections: 1http1MaxPendingRequests: 1。 這些規則意味着,如果並發的連接和請求數超過一個,在 istio-proxy 進行進一步的請求和連接時,后續請求或 連接將被阻止。

發送並發數為 2 的連接(-c 2),請求 20 次(-n 20):

kubectl exec -it $FORTIO_POD  -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
Fortio 0.6.2 running at 0 queries per second, 2->2 procs, for 5s: http://httpbin:8000/get
Starting at max qps with 2 thread(s) [gomax 2] for exactly 20 calls (10 per thread + 0)
23:51:10 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
Ended after 106.474079ms : 20 calls. qps=187.84
Aggregated Function Time : count 20 avg 0.010215375 +/- 0.003604 min 0.005172024 max 0.019434859 sum 0.204307492
# range, mid point, percentile, count
>= 0.00517202 <= 0.006 , 0.00558601 , 5.00, 1
> 0.006 <= 0.007 , 0.0065 , 20.00, 3
> 0.007 <= 0.008 , 0.0075 , 30.00, 2
> 0.008 <= 0.009 , 0.0085 , 40.00, 2
> 0.009 <= 0.01 , 0.0095 , 60.00, 4
> 0.01 <= 0.011 , 0.0105 , 70.00, 2
> 0.011 <= 0.012 , 0.0115 , 75.00, 1
> 0.012 <= 0.014 , 0.013 , 90.00, 3
> 0.016 <= 0.018 , 0.017 , 95.00, 1
> 0.018 <= 0.0194349 , 0.0187174 , 100.00, 1
# target 50% 0.0095
# target 75% 0.012
# target 99% 0.0191479
# target 99.9% 0.0194062
Code 200 : 19 (95.0 %)
Code 503 : 1 (5.0 %)
Response Header Sizes : count 20 avg 218.85 +/- 50.21 min 0 max 231 sum 4377
Response Body/Total Sizes : count 20 avg 652.45 +/- 99.9 min 217 max 676 sum 13049
All done 20 calls (plus 0 warmup) 10.215 ms avg, 187.8 qps

有趣的是,幾乎所有的請求都完成了!istio-proxy 確實允許存在一些誤差。

Code 200 : 19 (95.0 %)
Code 503 : 1 (5.0 %)

將並發連接數提高到 3 個:

kubectl exec -it $FORTIO_POD  -c fortio -- /usr/bin/fortio load -c 3 -qps 0 -n 30 -loglevel Warning http://httpbin:8000/get
Fortio 0.6.2 running at 0 queries per second, 2->2 procs, for 5s: http://httpbin:8000/get
Starting at max qps with 3 thread(s) [gomax 2] for exactly 30 calls (10 per thread + 0)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
23:51:51 W http.go:617> Parsed non ok code 503 (HTTP/1.1 503)
Ended after 71.05365ms : 30 calls. qps=422.22
Aggregated Function Time : count 30 avg 0.0053360199 +/- 0.004219 min 0.000487853 max 0.018906468 sum 0.160080597
# range, mid point, percentile, count
>= 0.000487853 <= 0.001 , 0.000743926 , 10.00, 3
> 0.001 <= 0.002 , 0.0015 , 30.00, 6
> 0.002 <= 0.003 , 0.0025 , 33.33, 1
> 0.003 <= 0.004 , 0.0035 , 40.00, 2
> 0.004 <= 0.005 , 0.0045 , 46.67, 2
> 0.005 <= 0.006 , 0.0055 , 60.00, 4
> 0.006 <= 0.007 , 0.0065 , 73.33, 4
> 0.007 <= 0.008 , 0.0075 , 80.00, 2
> 0.008 <= 0.009 , 0.0085 , 86.67, 2
> 0.009 <= 0.01 , 0.0095 , 93.33, 2
> 0.014 <= 0.016 , 0.015 , 96.67, 1
> 0.018 <= 0.0189065 , 0.0184532 , 100.00, 1
# target 50% 0.00525
# target 75% 0.00725
# target 99% 0.0186345
# target 99.9% 0.0188793
Code 200 : 19 (63.3 %)
Code 503 : 11 (36.7 %)
Response Header Sizes : count 30 avg 145.73333 +/- 110.9 min 0 max 231 sum 4372
Response Body/Total Sizes : count 30 avg 507.13333 +/- 220.8 min 217 max 676 sum 15214
All done 30 calls (plus 0 warmup) 5.336 ms avg, 422.2 qps

現在,您將開始看到預期的熔斷行為,只有 63.3% 的請求成功,其余的均被熔斷器攔截:

Code 200 : 19 (63.3 %)
Code 503 : 11 (36.7 %)

查詢 istio-proxy 狀態以了解更多熔斷詳情:

kubectl exec $FORTIO_POD -c istio-proxy -- pilot-agent request GET stats | grep httpbin | grep pending
cluster.outbound|80||httpbin.springistio.svc.cluster.local.upstream_rq_pending_active: 0
cluster.outbound|80||httpbin.springistio.svc.cluster.local.upstream_rq_pending_failure_eject: 0
cluster.outbound|80||httpbin.springistio.svc.cluster.local.upstream_rq_pending_overflow: 12
cluster.outbound|80||httpbin.springistio.svc.cluster.local.upstream_rq_pending_total: 39

可以看到 upstream_rq_pending_overflow12,這意味着,目前為止已有 12 個調用被標記為熔斷

參考:

https://blog.csdn.net/weixin_38754564/article/details/102386272

https://preliminary.istio.io/latest/zh/docs/tasks/traffic-management/circuit-breaking/

https://www.kubernetes.org.cn/5556.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM