本文是从零学习envoy笔记第四章 - 断路器
  • 从零学习envoy笔记 - Gateway总览
  • 从零学习envoy笔记 - 学习EG API和Gateway API
  • 从零学习envoy笔记 - 快速部署实验环境
  • 从零学习envoy笔记 - 官方Task Backend Routing
  • 从零学习envoy笔记 - 官方Task Backend Utilization Load Balancing
  • 从零学习envoy笔记 - 官方Task Bandwidth Limit
  • 从零学习envoy笔记 - 官方Task Client Traffic Policy

BackendTrafficPolicy

断路器是指,当后端压力过大时,Envoy 主动限制继续打到后端的请求数量,让一部分请求快速失败,用于保护后端。

Envoy Gateway 支持如下断路器阈值

  • 并发连接:限制 Envoy 可以與上游服務建立的連線數。當達到此閾值時,將不會建立新連接,部分請求將被排隊,直到現有連接可用為止。
  • 并发请求:限制 Envoy 向上游服務發送的並發請求數。當達到此閾值時,請求將被排隊。
  • Pending请求:限制 Pending 請求队列的大小。當達到此閾值時,超出佇列容量的請求將被終止。 503狀態碼。

Envoy 的计数器是跟随 Envoy Proxy 实例来维护的,默认的断路器为 1024,对于高并发系统来说很容易被触发

断路器配置

断路器配置就是根据 BackendTrafficPolicy 来配置的,然后绑定到对应的 Gatway API 上

yaml
1
2
3
4
  circuitBreaker:
    maxConnections: 0 #Envoy 到后端最多建立多少连接
    maxParallelRequests: 10 # Envoy 同时转发给后端的最大并发请求数
    maxPendingRequests: x # 并发满了以后,最多允许多少请求排队

实验

设置路由 red / gray, 50% 的流量到red,50%流量到gray

text
 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
cat <<EOF | kubectl apply -f -
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: red-gray-circuit-route
  namespace: default
spec:
  parentRefs:
    - name: eg
  hostnames:
    - circuit.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: envoy-end-red
          port: 90
          weight: 50
        - name: envoy-end-gray
          port: 90
          weight: 50
EOF

给 HTTPRoute 加断路器

text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: circuitbreaker-for-red-gray-route
  namespace: default
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: red-gray-circuit-route
  circuitBreaker:
    maxPendingRequests: 5
    maxParallelRequests: 1
EOF

测试访问

text
1
2
3
for i in $(seq 1 50); do
  curl -s -H "Host: circuit.example.com" http://127.0.0.1:8888/colorful 
done

需要注意的是,这里不能用 for , for 是串行的,没法测试出来

这里需要用 ab 这类工具测试才可以,这里使用 go 的 hey (官网推荐的工具) 来进行测试

text
1
2
apt install apache2-utils -y
go install github.com/rakyll/hey@latest

hey 测试结果更明显些,可以看出来什么请求多少个

text
 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
44
$ hey -n 100 -c 50 -host "circuit.example.com" http://127.0.0.1:8888/colorful
Summary:
  Total:        0.0931 secs
  Slowest:      0.0814 secs
  Fastest:      0.0038 secs
  Average:      0.0382 secs
  Requests/sec: 1074.1692

  Total data:   7379 bytes
  Size/request: 73 bytes

Response time histogram:
  0.004 [1]     |■
  0.012 [28]    |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.019 [10]    |■■■■■■■■■■■■■■
  0.027 [8]     |■■■■■■■■■■■
  0.035 [3]     |■■■■
  0.043 [0]     |
  0.050 [4]     |■■■■■■
  0.058 [10]    |■■■■■■■■■■■■■■
  0.066 [11]    |■■■■■■■■■■■■■■■■
  0.074 [19]    |■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.081 [6]     |■■■■■■■■■


Latency distribution:
  10%% in 0.0059 secs
  25%% in 0.0086 secs
  50%% in 0.0447 secs
  75%% in 0.0662 secs
  90%% in 0.0722 secs
  95%% in 0.0763 secs
  99%% in 0.0814 secs

Details (average, fastest, slowest):
  DNS+dialup:   0.0022 secs, 0.0000 secs, 0.0128 secs
  DNS-lookup:   0.0000 secs, 0.0000 secs, 0.0000 secs
  req write:    0.0008 secs, 0.0000 secs, 0.0107 secs
  resp wait:    0.0349 secs, 0.0036 secs, 0.0711 secs
  resp read:    0.0001 secs, 0.0000 secs, 0.0015 secs

Status code distribution:
  [200] 14 responses
  [503] 86 responses

卸载断路器的结果

text
 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
44
root@DESKTOP-P2F4970:~# hey -n 100 -c 50 -host "circuit.example.com" http://127.0.0.1:8888/colorful

Summary:
  Total:        0.0978 secs
  Slowest:      0.0929 secs
  Fastest:      0.0026 secs
  Average:      0.0419 secs
  Requests/sec: 1022.1531

  Total data:   2950 bytes
  Size/request: 29 bytes

Response time histogram:
  0.003 [1]     |■
  0.012 [30]    |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.021 [10]    |■■■■■■■■■■■■■
  0.030 [7]     |■■■■■■■■■
  0.039 [2]     |■■■
  0.048 [2]     |■■■
  0.057 [4]     |■■■■■
  0.066 [9]     |■■■■■■■■■■■■
  0.075 [11]    |■■■■■■■■■■■■■■■
  0.084 [14]    |■■■■■■■■■■■■■■■■■■■
  0.093 [10]    |■■■■■■■■■■■■■


Latency distribution:
  10%% in 0.0043 secs
  25%% in 0.0102 secs
  50%% in 0.0454 secs
  75%% in 0.0741 secs
  90%% in 0.0856 secs
  95%% in 0.0872 secs
  99%% in 0.0929 secs

Details (average, fastest, slowest):
  DNS+dialup:   0.0006 secs, 0.0000 secs, 0.0071 secs
  DNS-lookup:   0.0000 secs, 0.0000 secs, 0.0000 secs
  req write:    0.0004 secs, 0.0000 secs, 0.0075 secs
  resp wait:    0.0404 secs, 0.0026 secs, 0.0898 secs
  resp read:    0.0001 secs, 0.0000 secs, 0.0004 secs

Status code distribution:
  [200] 100 responses

上述例子差不多为 200 25%, 503 75%,这里模拟的是 “100 个请求、50 并发”,“每一个后端同时接受 “1 个 active + 5 个 pending ≈ 6 个可接受请求” (可能有多种条件,如85,15; 80,20)

text
1
2
3
  circuitBreaker:
    maxPendingRequests: 5
    maxParallelRequests: 1

Reference

[1] Circuit Breakers