文档

使用ASMCircuitBreaker为服务间调用流量配置熔断规则

本文介绍如何使用ASMCircuitBreaker CRD为东西向调用流量配置熔断规则。

背景信息

流量熔断是一种过载保护机制,主要用于防止系统因为短时间内过大的流量而崩溃。在云原生服务之间存在东西向调用流量的情况下,如果某个服务发生故障(例如:响应过慢或者失败率升高),可能会导致该服务所在调用链路上的一系列服务也发生连锁崩溃。

通过为服务间的东西向调用流量配置熔断规则,可以实现当流量失败率或响应超时次数达到阈值时,主动“切断”来自上游服务的请求。在保护上游服务的同时,也有效防止故障在整个调用链路中扩散,造成整个系统雪崩。

服务网格ASM支持为特定服务之间和特定路由上的东西向调用流量配置熔断规则,通过配置使网格代理主动拒绝出现故障上游服务的请求,实现无侵入式的流量熔断能力。

前提条件

步骤一:部署示例应用

本文以在ACK集群中部署的sleep服务调用httpbin服务为例,演示sleep与httpbin服务之间进行东西向调用时的熔断规则配置。演示场景包括基于错误率的熔断配置与基于慢请求数量的熔断配置。

  1. 为default命名空间开启自动注入。具体操作,请参见启用自动注入。关于自动注入的更多信息,请参见配置Sidecar注入策略

  2. 部署sleep服务。

    1. 使用如下内容创建sleep.yaml文件。

      展开查看YAML详细信息

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: sleep
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: sleep
        labels:
          app: sleep
          service: sleep
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep
        template:
          metadata:
            labels:
              app: sleep
          spec:
            terminationGracePeriodSeconds: 0
            serviceAccountName: sleep
            containers:
            - name: sleep
              image: registry.cn-hangzhou.aliyuncs.com/acs/curl:8.1.2
              command: ["/bin/sleep", "infinity"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
              - mountPath: /etc/sleep/tls
                name: secret-volume
            volumes:
            - name: secret-volume
              secret:
                secretName: sleep-secret
                optional: true
      ---
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,在default命名空间部署sleep服务。

      kubectl apply -f sleep.yaml
  3. 部署httpbin服务。

    1. 使用如下内容创建httpbin.yaml文件。

      展开查看YAML详细信息

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: httpbin
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: httpbin
        labels:
          app: httpbin
          service: httpbin
      spec:
        ports:
        - name: http
          port: 8000
          targetPort: 80
        selector:
          app: httpbin
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: httpbin
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: httpbin
            version: v1
        template:
          metadata:
            labels:
              app: httpbin
              version: v1
            annotations:
              sidecar.istio.io/inject: "true"
          spec:
            serviceAccountName: httpbin
            containers:
            - image: docker.io/kennethreitz/httpbin
              imagePullPolicy: IfNotPresent
              name: httpbin
              ports:
              - containerPort: 80
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,在default命名空间部署httpbin服务。

      kubectl apply -f httpbin.yaml

步骤二:为服务调用的东西向调用流量配置请求路径路由

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 选择下方两种方式的任意一种配置虚拟服务。

    控制台手动创建

    1. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择流量管理中心 > 虚拟服务,然后单击创建

    2. 填写命名空间服务名称,打开作用范围>作用于所有Sidecar

    3. 所属服务框中单击添加所属服务,添加httpbin服务。

    4. 配置HTTP路由>添加路由,信息填写请参见下图红框标注。

    image

    image

    image

    使用YAML创建

    1. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择流量管理中心 > 虚拟服务,然后单击使用YAML创建

    2. YAML输入框中输入如下内容,点击创建

      展开查看YAML详细内容

      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: httpbin
        namespace: default
      spec:
        hosts:
          - httpbin.default.svc.cluster.local
        http:
          - match:
              - uri:
                  exact: /status/500
            name: error-route
            route:
              - destination: 
                  host: httpbin.default.svc.cluster.local
          - match:
              - uri:
                  prefix: /delay
            name: delay-route
            route:
              - destination:
                  host: httpbin.default.svc.cluster.local
          - name: default-route
            route:
              - destination:
                  host: httpbin.default.svc.cluster.local
      

    下表为请求与路径的对应关系以及具体说明。

    请求路径

    匹配类型

    路由项

    说明

    /status/500

    精确匹配

    error-route

    固定响应500状态码。

    /delay

    前缀匹配

    delay-route

    指定的时间后响应200状态码;/delay请求的具体使用方法参见delay

    /*

    任意路径

    default-route

    默认路由项。

步骤三:配置熔断

本节将分别介绍错误率熔断和慢请求熔断的具体配置步骤以及测试结果。

基于错误率熔断

基于错误率的熔断是指在给定的时间窗口内检测服务器响应的错误率,并在错误率超过一定阈值时触发熔断。

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择流量管理中心 > 熔断降级

  3. 创建页面,在YAML输入框处输入以下内容,然后单击创建

    展开查看YAML详细信息

    apiVersion: istio.alibabacloud.com/v1beta1
    kind: ASMCircuitBreaker
    metadata:
      name: httpbin-error-circuitbreak
      namespace: default
    spec:
      configs:
        - breaker_config:
            break_duration: 60s
            custom_response:
              body: error break!
              header_to_add:
                x-envoy-overload: 'true'
              status_code: 499
            error_percent:
              value: 60
            min_request_amount: 5
            window_size: 10s
          match:
            vhost:
              name: httpbin.default.svc.cluster.local
              port: 8000
              route:
                name_match: error-route
      workloadSelector:
        labels:
          app: sleep
    

    熔断配置中使用的参数说明如下:

    参数

    说明

    workloadSelector.labels

    熔断配置的下游服务工作负载,在本例中是sleep服务,因此用app: sleep标签选中该工作负载。

    break_duration

    熔断发生后到恢复对服务访问之间的时长。本例中配置为60s。

    window_size

    进行熔断检测的时间窗口。本例中配置为10s,代表在10秒内若路由中的请求错误率超过指定阈值,则开始熔断,拒绝请求。

    error_percent

    在时间窗口内,判断是否达到熔断所需的请求错误率。本例中配置为60,代表在时间窗口的10s内若路由中的请求错误率超过60%,则发生熔断,拒绝请求。

    min_request_amount

    时间窗口内触发熔断所需的最小请求数。配置该参数的目的是防止因请求量过小而误判触发熔断。

    本例中配置为5,代表在时间窗口的10s内若路由已经发送了5次以上请求,且错误率超过60%时,才发生熔断。

    custom_response

    熔断发生时,网格代理拒绝请求时返回的自定义响应内容。

    • body配置为error break!,代表响应体为error break!

    • header_to_add配置为x-envoy-overload: 'true',代表熔断的响应头中将添加x-envoy-overload: 'true'

    • status_code配置为499,代表熔断后请求的响应码为499

    match.vhost

    熔断的路由条目配置,该路由条目必须与虚拟服务中声明的具体路由条目匹配。

    • name:需要配置为调用链路中的上游服务服务域名。在本例中,配置为sleep服务的上游服务httpbin服务的域名httpbin.default.svc.cluster.local

    • port:需要配置为上游服务的Service端口。在本例中,配置为httpbin服务的Service端口8000

    • route.name_match:需要配置为虚拟服务中实际的路由项名称,熔断配置将在该段路由中生效。在本例中,配置为步骤二中编写的路由项error-route,此路由项对应的请求将固定响应500状态码,确保能够触发熔断。

  4. 使用kubectl连接ACK集群,执行以下命令。

    for i in {1..100};  do kubectl exec -it deploy/sleep -- curl httpbin:8000/status/500 -I | grep 'HTTP';  echo ''; sleep 0.1; done;

    预期输出:

    展开查看详细信息

    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    ...

    可以看到,当发送第6条请求时,熔断被触发,可以观察到后续请求都返回自定义的499响应码,熔断将持续60s。

  5. 在熔断期间,可以尝试对httpbin服务的其他路径进行访问。

    for i in {1..100};  do kubectl exec -it deploy/sleep -- curl httpbin:8000/status/503 -I | grep 'HTTP';  echo ''; sleep 0.1; done;

    预期输出:

    展开查看详细信息

    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    HTTP/1.1 503 Service Unavailable
    
    ...

    可以看到发往服务其他路径的请求并不受error-route路由项上的熔断配置影响,仍然可以正常返回httpbin服务的响应内容。

基于慢请求熔断

基于慢请求数的熔断是指检测在给定的时间窗口内响应时间超过给定阈值的请求数量(这种请求被称作慢请求),并在慢请求数量超过一定阈值时触发熔断。

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择流量管理中心 > 熔断降级

  3. 创建页面,在YAML输入框中输入以下内容,然后单击创建

    展开查看YAML详细信息

    apiVersion: istio.alibabacloud.com/v1beta1
    kind: ASMCircuitBreaker
    metadata:
      name: httpbin-error-circuitbreak
      namespace: default
    spec:
      configs:
        - breaker_config:
            break_duration: 60s
            custom_response:
              body: error break!
              header_to_add:
                x-envoy-overload: 'true'
              status_code: 499
            error_percent:
              value: 60
            min_request_amount: 5
            window_size: 10s
          match:
            vhost:
              name: httpbin.default.svc.cluster.local
              port: 8000
              route:
                name_match: error-route
      workloadSelector:
        labels:
          app: sleep

    熔断配置中使用的参数说明如下:

    参数

    说明

    workloadSelector.labels

    熔断配置的下游服务工作负载,在本例中是sleep服务,因此用app: sleep标签选中该工作负载。

    break_duration

    熔断发生后到恢复对服务访问之间的时长。本例中配置为60s。

    window_size

    进行熔断检测的时间窗口。本例中配置为10s,代表在10秒内若路由中慢请求数量超过指定阈值,则发生熔断,拒绝请求。

    slow_request_rt

    慢请求的判断基准响应时间。本例中配置为0.5s,代表响应时间超过0.5s的请求将被视作慢请求。

    max_slow_requests

    时间窗口内触发熔断所需的慢请求数量。本例中配置为5,代表时间窗口的10s内若出现了超过5次慢请求,则发生熔断,拒绝请求。

    min_request_amount

    时间窗口内触发熔断所需的最小请求数量。配置该参数的目的是防止因请求量过小而被误判触发熔断。

    本例中配置为5,代表在时间窗口的10s内若路由上已经发送了5次以上请求、且慢请求数超过5时,才会发生熔断。

    custom_response

    熔断发生时,网格代理拒绝请求时返回的自定义响应内容。

    • body配置为delay break!,代表响应体为delay break!

    • header_to_add配置为x-envoy-overload: 'true',代表熔断的响应头中将添加x-envoy-overload: 'true'

    • status_code配置为498,代表熔断后请求的响应码为498

    match.vhost

    熔断的路由条目配置,该路由条目必须与虚拟服务中声明的具体路由条目匹配。

    • name:需要配置为调用链路中上游服务的服务域名。在本例中,配置为sleep服务的上游服务httpbin服务的域名httpbin.default.svc.cluster.local

    • port:需要配置为上游服务的Service端口。在本例中,配置为httpbin服务的Service端口8000

    • route.name_match:需要配置为虚拟服务中实际配置的路由项名称,熔断配置将在该段路由中生效。在本例中,配置为步骤二中编写的路由项delay-route,此路由项对应的请求能够以人工方式指定超过0.5秒响应,确保能够触发熔断。

  4. 使用kubectl连接ACK集群,执行以下命令。

    for i in {1..100};  do kubectl exec -it deploy/sleep -- curl httpbin:8000/delay/1 -I | grep 'HTTP';  echo ''; sleep 0.1; done; 

    预期输出:

    展开查看详细信息

    HTTP/1.1 200 OK
    
    HTTP/1.1 200 OK
    
    HTTP/1.1 200 OK
    
    HTTP/1.1 200 OK
    
    HTTP/1.1 200 OK
    
    HTTP/1.1 498 Unknown
    
    HTTP/1.1 498 Unknown
    
    HTTP/1.1 498 Unknown
    
    HTTP/1.1 498 Unknown
    
    HTTP/1.1 498 Unknown
    
    HTTP/1.1 498 Unknown
    
    HTTP/1.1 498 Unknown
    
    HTTP/1.1 498 Unknown
    
    ...

    可以看到,当发送第6次请求时,熔断被触发。可以观察到后续的请求都返回了自定义498响应码,熔断将持续60s。

  5. 在熔断触发期间,可以执行以下命令对步骤三中配置的基于错误率的熔断进行测试。

    for i in {1..100};  do kubectl exec -it deploy/sleep -- curl httpbin:8000/status/500 -I | grep 'HTTP';  echo ''; sleep 0.1; done;

    预期输出:

    展开查看详细信息

    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 500 Internal Server Error
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    HTTP/1.1 499 Unknown
    
    ...

    上述输出说明在不同路由项上配置的熔断规则彼此之间互不影响,您可以灵活地针对服务之间不同特征的东西向调用流量配置各自的熔断规则,灵活地实现流量熔断策略。

  • 本页导读 (1)