熔断

在微服务中,系统的各个服务之间在网络上存在大量的调用,在调用过程中,如果某个服务繁忙或者无法响应请求,可能会引发集群的大规模级联故障,从而造成整个系统不可用,引发服务雪崩效应。当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用,达到服务降级的效果,通过牺牲局部保全整体的措施就叫做熔断(Circuit Breaking)

本文基于示例应用 Bookinfo,演示如何对其中的一个服务设置熔断规则,并通过一个负载测试客户端 (fortio) 来触发熔断机制,在 KubeSphere 中演示熔断现象。

预估时间

约 15 分钟。

前提条件

已完成了 Bookinfo 微服务的灰度发布 示例中 查看流量监测 之前的所有步骤。

操作示例

第一步:设置熔断规则

使用项目普通用户 project-regular 登录 KubeSphere,进入示例应用 Bookinfo 的详情页。由于在 查看流量拓扑图 步骤中,通过 watch 命令引入真实的访问流量后,此时在流量治理中可以看到流量治理拓扑图。

熔断 - 图1

1、点击 ratings,在右侧展开 「流量治理」,打开 「连接池管理| 和 「熔断器」,参考如下设置。

  • 连接池管理:将 最大连接数最大等待请求数(等待列队的长度) 都设置为 1,表示如果超过了一个连接同时发起请求,Istio 就会熔断,阻止后续的请求或连接;
  • 熔断器:参考如下设置,表示每 1 秒钟扫描一次上游主机,连续失败 5 次返回 5xx 错误码的 100% 数量的主机 (Pod) 会被移出连接池 180 秒,熔断器参数释义详见 流量治理 - 熔断器

    • 连续错误响应(5xx)个数:5;
    • 检查周期(单位: s):1;
    • 容器组隔离比例(单位: %):100;
    • 短隔离时间(s):180。

连接池参数说明:

  • 最大连接数:表示在任何给定时间内, Envoy 与上游集群(比如这里是 ratings 服务)建立的最大连接数,适用于 HTTP/1.1;
  • 每连接最大请求数:表示在任何给定时间内,上游集群中所有主机(比如这里是 ratings 服务)可以处理的最大请求数。对后端连接中最大的请求数量若设为 1 则会禁止 keep alive 特性;
  • 最大请求重试次数:在指定时间内对目标主机最大重试次数;
  • 连接超时时间:TCP 连接超时时间,最小值必须大于 1ms。最大连接数和连接超时时间是对 TCP 和 HTTP 都有效的通用连接设置;
  • 最大等待请求数 (等待列队的长度):表示待处理请求队列的长度,默认为 1024。如果该断路器溢出,集群的 upstream_rq_pending_overflow 计数器就会递增。

熔断 - 图2

2、完成设置后,下拉至底部点击 「确定」,保存规则。

第二步:设置客户端

由于我们已经在 reviews-v2 中 reviews 容器中注入了负载测试客户端 (fortio),它可以控制连接数量、并发数以及发送 HTTP 请求的延迟,能够触发在上一步中设置的熔断策略。因此可以通过 reviews 容器来向后端服务发送请求,观察是否会触发熔断策略。

1、使用集群管理员账号 admin 登入 KubeSphere,在右下角找到小锤子图标,然后打开 kubectl (或直接 SSH 登录集群任意节点)。

2、执行以下命令登录客户端 Pod (reviews-v2) 并使用 Fortio 工具来调用 ratings 服务,-curl 参数表明只调用一次,返回 200 OK 表示调用成功。

  1. $ FORTIO_POD=$(kubectl get pod -n demo-namespace | grep reviews-v2 | awk '{pri
  2. nt $1}')
  3. $ kubectl exec -n demo-namespace -it $FORTIO_POD -c reviews /usr/bin/fortio -- load -curl http://ratings:9080/ratings/0
  4. HTTP/1.1 200 OK
  5. ···

第三步:触发熔断机制

1、在 ratings 中设置了连接池管理的熔断规则,最大连接数最大等待请求数(等待列队的长度) 都设置为 1,接下来设置两个并发连接(-c 2),发送 20 请求(-n 20):

  1. $ kubectl exec -n demo-namespace -it $FORTIO_POD -c reviews /usr/bin/fortio -- load -c 2 -qps 0 -n 20 -loglevel Warning http://ratings:9080/ratings/0
  2. ···
  3. Code 200 : 18 (90.0 %)
  4. Code 503 : 2 (10.0 %)
  5. ···

2、以上可以看到,几乎所有请求都通过了,Istio-proxy 允许存在一些误差。接下来把并发连接数量提高到 3:

  1. $ kubectl exec -n demo-namespace -it $FORTIO_POD -c reviews /usr/bin/fortio --
  2. load -c 3 -qps 0 -n 30 -loglevel Warning http://ratings:9080/ratings/0
  3. ···
  4. Code 200 : 22 (73.3 %)
  5. Code 503 : 8 (26.7 %)
  6. ···

3、查看结果发现熔断行为按照之前的设置规则生效了,此时仅 73.3 % 的请求允许通过,剩余请求被断路器拦截了。由于此时 503 的返回次数为 8,超过了预先设置的连续错误响应(5xx)个数 5,此时 ratings 的 Pod 将被 100% 地隔离 180 s,ratings 与 reviews-v2 之间也出现了灰色箭头,表示服务间的调用已断开,ratings 被完全隔离。

熔断 - 图3

4、可以给 reviews-v2 的部署 (Deployment) 添加如下一条 annotation,即可查询 ratings 的 istio-proxy 的状态。在 「工作负载」→ 「部署」列表中找到 reviews-v2,点击右侧 ··· 选择 「编辑配置文件」,添加一条 sidecar.istio.io/statsInclusionPrefixes 的 annotation。

  1. ···
  2. annotations:
  3. sidecar.istio.io/inject: 'true'
  4. sidecar.istio.io/statsInclusionPrefixes: 'cluster.outbound,cluster_manager,listener_manager,http_mixer_filter,tcp_mixer_filter,server,cluster.xds-grpc'
  5. ···

完成后点击 「更新」。

5、查询 istio-proxy 的状态,获取更多相关信息。如下所示 upstream_rq_pending_overflow 的值是 10,说明有 10 次调用被熔断。

  1. $ kubectl exec -n demo-namespace -it $FORTIO_POD -c istio-proxy -- sh -c 'curl localhost:15000/stats' | grep ratings | grep pending
  2. ···
  3. cluster.outbound|9080|v1|ratings.demo-namespace.svc.cluster.local.upstream_rq_pending_overflow: 10
  4. cluster.outbound|9080|v1|ratings.demo-namespace.svc.cluster.local.upstream_rq_pending_total: 41
  5. ···