Flomesh 服务网格:熔断降级

在这里插入图片描述

在这篇文章我们将介绍如何在 Flomesh 服务网格中使用熔断功能。


背景

在微服务架构设计中,熔断是服务可用性保障除了限流外的另一种手段。熔断是一种自我保护机制,对链路中的问题进行隔离防止服务雪崩。熔断的开启通常有一定的触发条件,通常情况下都是关闭的,只有达到条件时才会打开。这点类似电路中的保险丝,当电压过高时就会熔断,防止电路中的电器损毁。

降级与熔断的结果是一样的,都会使应用不对外提供服务或者进行简单的处理。不同的地方则是降级是人为发起、主动的行为,因为某种原因主动开启。比如电商活动促销时,会将某些非核心服务降级,释放资源给核心的服务。

Flomesh 服务网格方案

在服务网格中,我们将接收、处理请求和返回响应的服务称之为上游(Upstream)。

Flomesh 服务网格 中提供了 UpstreamTrafficSetting API 对发往上游的流量进行控制,在介绍 服务网格的限流功能 时就增用过这个 API,这次我们来介绍它的另一部分功能:熔断。Flomesh 服务网格的熔断可以由错误请求或慢调用请求触发:

  • spec.host 字段用于配置上游服务的主机名,这里配置上游主机 fortio.server.svc.cluster.local,熔断的设置真对发往该主机的请求生效。
  • connectionSettings.http.circuitBreaking:是 7 层的熔断策略
    • statTimeWindow:熔断统计的时间窗口,1m
    • minRequestAmount:触发熔断的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断。结合统计的时间窗口指熔断配置在 1 分钟内请求数超过 200 才会生效,才有可能触发熔断。低于 200,即使异常比率超出阈值也不会触发熔断。
    • errorAmountThreshold:触发熔断的错误请求数阈值为 100
    • errorRatioThreshold:触发熔断的错误请求比例阈值为 50%
    • slowTimeThreshold:慢调用耗时阈值 100ms
    • slowAmountThreshold:慢调用请求数阈值 100
    • slowRatioThreshold:慢调用请求比例阈值 10%
    • degradedTimeWindow:熔断的持续时间为 1m
    • degradedStatusCode:熔断开启时的响应状态码为 503
    • degradedResponseContent:熔断开启式响应内容为 Service Unavailable!
apiVersion: policy.openservicemesh.io/v1alpha1
kind: UpstreamTrafficSetting
metadata:
  name: http-circuit-breaking
spec:
  host: fortio.server.svc.cluster.local
  connectionSettings:
    http:
      circuitBreaking: 
        statTimeWindow: 1m
        minRequestAmount: 200 
        errorAmountThreshold: 100
        errorRatioThreshold: 0.50
        slowTimeThreshold: 100ms
        slowAmountThreshold: 100
        slowRatioThreshold: 0.10
        degradedTimeWindow: 1m
        degradedStatusCode: 503
        degradedResponseContent: 'Service Unavailable!'

演示

下载 CLI

system=$(uname -s | tr [:upper:] [:lower:])
arch=$(dpkg --print-architecture)
release=v1.3.0
curl -L https://github.com/flomesh-io/osm-edge/releases/download/${release}/osm-edge-${release}-${system}-${arch}.tar.gz | tar -vxzf -
./${system}-${arch}/osm version
cp ./${system}-${arch}/osm /usr/local/bin/

安装 osm-edge

export osm_namespace=osm-system 
export osm_mesh_name=osm 

osm install \
    --mesh-name "$osm_mesh_name" \
    --osm-namespace "$osm_namespace"

部署示例应用

使用 fortio 作为客户端和服务端,部署服务端。

kubectl create namespace server
osm namespace add server
kubectl apply -n server -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: fortio
  labels:
    app: fortio
    service: fortio
spec:
  ports:
  - port: 8080
    name: http-8080
  - port: 8078
    name: tcp-8078
  - port: 8079
    name: grpc-8079
  selector:
    app: fortio
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fortio
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fortio
  template:
    metadata:
      labels:
        app: fortio
    spec:
      containers:
      - name: fortio
        image: fortio/fortio:latest_release
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 8078
          name: tcp
        - containerPort: 8079
          name: grpc
EOF

部署客户端。

kubectl create namespace client
osm namespace add client

kubectl apply -n client -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: fortio-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fortio-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fortio-client
  template:
    metadata:
      labels:
        app: fortio-client
    spec:
      serviceAccountName: fortio-client
      containers:
      - name: fortio-client
        image: fortio/fortio:latest_release
        imagePullPolicy: Always
EOF

测试

我们使用 10 个连接、200 并发来发送 1000 个请求,设置服务端 20% 的情况下返回状态码 511

fortio_client=`kubectl get pod -n client -l app=fortio-client -o jsonpath='{.items[0].metadata.name}'`
kubectl exec "$fortio_client" -n client -c fortio-client -- fortio load -quiet -c 10 -n 1000 -qps 200 -p 99.99 http://fortio.server.svc.cluster.local:8080/echo?status=511:20

结果类似下面这种,511 的响应在 20% 上下浮动。

Sockets used: 205 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false, Catchup allowed: true
IP addresses distribution:
10.43.43.151:8080: 205
Code 200 : 804 (80.4 %)
Code 511 : 196 (19.6 %)
All done 1000 calls (plus 0 warmup) 2.845 ms avg, 199.8 qps

接下来我们测试不同熔断策略下系统的表现。

策略:错误请求数触发熔断

设置错误请求数触发阈值 errorAmountThreshold=100,错误请求数达到 100 的时候触发熔断,返回 503 Service Unavailable!,熔断时长 10s

kubectl apply -f - <<EOF
apiVersion: policy.openservicemesh.io/v1alpha1
kind: UpstreamTrafficSetting
metadata:
  name: http-circuit-breaking
  namespace: server
spec:
  host: fortio.server.svc.cluster.local
  connectionSettings:
    http:
      circuitBreaking:
        statTimeWindow: 1m
        minRequestAmount: 200
        errorAmountThreshold: 100
        degradedTimeWindow: 10s
        degradedStatusCode: 503
        degradedResponseContent: 'Service Unavailable!'
EOF

设置服务端 20% 的响应返回错误码 511。当错误请求数达到 100 时,成功的请求应该 400 左右。

kubectl exec "$fortio_client" -n client -c fortio-client -- fortio load -quiet -c 10 -n 1000 -qps 200 -p 99.99 http://fortio.server.svc.cluster.local:8080/echo\?status\=511:20

从结果来看符合预期,熔断后的请求返回了 503 错误码。

Sockets used: 570 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false, Catchup allowed: true
IP addresses distribution:
10.43.43.151:8080: 570
Code 200 : 430 (43.0 %)
Code 503 : 470 (47.0 %)
Code 511 : 100 (10.0 %)
All done 1000 calls (plus 0 warmup) 3.376 ms avg, 199.8 qps

检查 sidecar 日志,在第 530 个请求的时候错误数达到了 100,触发了熔断。

2023-02-08 01:08:01.456 [INF] [circuit_breaker] total/slowAmount/errorAmount (open) server/fortio|8080 530 0 100

策略:错误率触发熔断

这里我们将错误数触发改为错误率触发:errorRatioThreshold=0.10,当错误率达到 10% 触发熔断,熔断 10s 并返回 503 Service Unavailable!。注意,这里的最小请求数仍为 200

kubectl apply -f - <<EOF
apiVersion: policy.openservicemesh.io/v1alpha1
kind: UpstreamTrafficSetting
metadata:
  name: http-circuit-breaking
  namespace: server
spec:
  host: fortio.server.svc.cluster.local
  connectionSettings:
    http:
      circuitBreaking:
        statTimeWindow: 1m
        minRequestAmount: 200
        errorRatioThreshold: 0.10
        degradedTimeWindow: 10s
        degradedStatusCode: 503
        degradedResponseContent: 'Service Unavailable!'
EOF

设置服务端 20% 的响应返回错误码 511

kubectl exec "$fortio_client" -n client -c fortio-client -- fortio load -quiet -c 10 -n 1000 -qps 200 -p 99.99 http://fortio.server.svc.cluster.local:8080/echo\?status\=511:20

从输出的结果可以看出 200 个请求之后触发了熔断,熔断的请求数为 800。

Sockets used: 836 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false, Catchup allowed: true
IP addresses distribution:
10.43.43.151:8080: 836
Code 200 : 164 (16.4 %)
Code 503 : 800 (80.0 %)
Code 511 : 36 (3.6 %)
All done 1000 calls (plus 0 warmup) 3.605 ms avg, 199.8 qps

查看 sidecar 的日志,在满足触发熔断的最小请求数 200 后,检查错误率也达到了阈值,触发了熔断。

2023-02-08 01:19:25.874 [INF] [circuit_breaker] total/slowAmount/errorAmount (close) server/fortio|8080 200 0 36

策略:慢调用请求数触发熔断

测试慢调用,为 20% 的请求加上 200ms 的延迟。

kubectl exec "$fortio_client" -n client -c fortio-client -- fortio load -quiet -c 10 -n 1000 -qps 200 -p 50,78,79,80,81,82,90,95 http://fortio.server.svc.cluster.local:8080/echo\?delay\=200ms:20

得类似下面的效果,接近 80% 的请求耗时小于 200ms。

# target 50% 0.000999031
# target 78% 0.0095
# target 79% 0.200175
# target 80% 0.200467
# target 81% 0.200759
# target 82% 0.20105
# target 90% 0.203385
# target 95% 0.204844

285103 max 0.000285103 sum 0.000285103
Sockets used: 10 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false, Catchup allowed: true
IP addresses distribution:
10.43.43.151:8080: 10
Code 200 : 1000 (100.0 %)
All done 1000 calls (plus 0 warmup) 44.405 ms avg, 149.6 qps

设置策略:

  • 设置慢调用请求耗时阈值 200ms
  • 设置慢调用请求数为 100
kubectl apply -f - <<EOF
apiVersion: policy.openservicemesh.io/v1alpha1
kind: UpstreamTrafficSetting
metadata:
  name: http-circuit-breaking
  namespace: server
spec:
  host: fortio.server.svc.cluster.local
  connectionSettings:
    http:
      circuitBreaking:
        statTimeWindow: 1m
        minRequestAmount: 200
        slowTimeThreshold: 200ms
        slowAmountThreshold: 100
        degradedTimeWindow: 10s
        degradedStatusCode: 503
        degradedResponseContent: 'Service Unavailable!'
EOF

为 20% 的请求注入 200ms 的延迟。

kubectl exec "$fortio_client" -n client -c fortio-client -- fortio load -quiet -c 10 -n 1000 -qps 200 -p 50,78,79,80,81,82,90,95 http://fortio.server.svc.cluster.local:8080/echo\?delay\=200ms:20

成功请求数为 504,其中的 20% 耗时 200ms,慢调用的请求数量达到触发熔断的阈值。

# target 50% 0.00246111
# target 78% 0.00393846
# target 79% 0.00398974
# target 80% 0.00409756
# target 81% 0.00421951
# target 82% 0.00434146
# target 90% 0.202764
# target 95% 0.220036

Sockets used: 496 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false, Catchup allowed: true
IP addresses distribution:
10.43.43.151:8080: 496
Code 200 : 504 (50.4 %)
Code 503 : 496 (49.6 %)
All done 1000 calls (plus 0 warmup) 24.086 ms avg, 199.8 qps

查看 sidecar 的日志,在第 504 个请求时慢调用的数量达到了 100,触发熔断。

2023-02-08 07:27:01.106 [INF] [circuit_breaker] total/slowAmount/errorAmount (open)  server/fortio|8080 504 100 0

策略:慢调用比率触发熔断

将慢调用比率设置为 0.10,即统计窗口内期望 10% 的请求耗时超过 200ms 时触发熔断。

kubectl apply -f - <<EOF
apiVersion: policy.openservicemesh.io/v1alpha1
kind: UpstreamTrafficSetting
metadata:
  name: http-circuit-breaking
  namespace: server
spec:
  host: fortio.server.svc.cluster.local
  connectionSettings:
    http:
      circuitBreaking:
        statTimeWindow: 1m
        minRequestAmount: 200
        slowTimeThreshold: 200ms
        slowRatioThreshold: 0.1
        degradedTimeWindow: 10s
        degradedStatusCode: 503
        degradedResponseContent: 'Service Unavailable!'
EOF

为 20% 的请求注入 200ms 的延迟。

kubectl exec "$fortio_client" -n client -c fortio-client -- fortio load -quiet -c 10 -n 1000 -qps 200 -p 50,78,79,80,81,82,90,95 http://fortio.server.svc.cluster.local:8080/echo\?delay\=200ms:20

查看输出的结果,成功的请求数 202,满足配置生效的最小请求数,其中 20% 为慢调用,达到触发熔断的阈值。

# target 50% 0.00305539
# target 78% 0.00387172
# target 79% 0.00390087
# target 80% 0.00393003
# target 81% 0.00395918
# target 82% 0.00398834
# target 90% 0.00458915
# target 95% 0.00497674

Sockets used: 798 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false, Catchup allowed: true
IP addresses distribution:
10.43.43.151:8080: 798
Code 200 : 202 (20.2 %)
Code 503 : 798 (79.8 %)
All done 1000 calls (plus 0 warmup) 10.133 ms avg, 199.8 qps

查看 sidecar 的日志,第 202 个请求的时候,慢调用的请求数为 28,触发了熔断。

2023-02-08 07:38:25.284 [INF] [circuit_breaker] total/slowAmount/errorAmount (open)  server/fortio|8080 202 28 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PipyFlomesh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值