文档

配置推空保护

更新时间:

当注册中心向客户端推送服务列表时,如果由于某些原因(如内部故障、网络问题等)导致服务列表为空,注册中心将会启动推空保护机制,以确保不会向客户端推送空的服务列表,从而保障系统的容错性和稳定性。

背景信息

客户端在请求注册中心订阅服务端地址列表时,有可能出现服务端注册异常的场景,注册中心返回了空列表,此时客户端忽略该空返回的变更,从缓存中获取上一次正常的服务端地址进行服务访问。

在注册中心进行变更(变配、升降级)、遇到突发情况(例如,可用区断网断电)或其他不可预知情况下,都有可能出现订阅异常,导致服务消费者获取到空的服务提供者的实例列表,继而影响服务消费者的可用性。开启推空保护的功能,可以有效保护业务调用,增加业务可靠性。

本文演示的应用架构是由后端的微服务应用实例(Spring Cloud)构成。具体的后端调用链路有Spring Cloud Consumer调用Spring Cloud Provider,这些应用中的服务之间通过Nacos注册中心实现服务注册与发现。

image
说明

该功能Agent正在灰度中,如果需要使用欢迎加入微服务引擎钉钉交流群:34754806,联系技术支持单独升级后再进行试用。

使用限制

限制项

限制值

说明

Spring Cloud版本

Spring Cloud Edgware及以上版本。

-

Dubbo版本

2.5.3~2.7.8

Dubbo 3.0+版本支持当前处于灰度中。

注册中心类型

  • Nacos

  • Eureka

  • ZooKeeper

-

前提条件

部署Demo应用程序

  1. 容器服务控制台左侧导航栏,单击集群。在集群列表页面,单击目标集群名称。

  2. 在集群管理页左侧导航栏,选择工作负载 > 无状态

  3. 无状态页面的顶部,选择命名空间,然后单击使用YAML创建资源。对模板进行相关配置,完成配置后单击创建。本文示例中部署sc-consumer、sc-consumer-empty和sc-provider,使用的是开源的Nacos。

    展开查看YAML文件

    # 开启推空保护的 sc-consumer
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sc-consumer
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sc-consumer
      template:
        metadata:
          labels:
            msePilotCreateAppName: sc-consumer
            app: sc-consumer
        spec:
          containers:
          - env:
            - name: JAVA_HOME
              value: /usr/lib/jvm/java-1.8-openjdk/jre
            - name: spring.cloud.nacos.discovery.server-addr
              value: nacos-server:8848
            image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/demo:sc-consumer-0.1
            imagePullPolicy: Always
            name: sc-consumer
            ports:
            - containerPort: 18091
            livenessProbe:
              tcpSocket:
                port: 18091
              initialDelaySeconds: 10
              periodSeconds: 30
    ---
    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.small
        service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet
      name: sc-consumer-slb
    spec:
      ports:
        - port: 80
          protocol: TCP
          targetPort: 18091
      selector:
        app: sc-consumer
      type: LoadBalancer
    status:
      loadBalancer: {}
    # 无推空保护的sc-consumer-empty
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sc-consumer-empty
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sc-consumer-empty
      template:
        metadata:
          labels:
            msePilotCreateAppName: sc-consumer-empty
            app: sc-consumer-empty
        spec:
          containers:
          - env:
            - name: JAVA_HOME
              value: /usr/lib/jvm/java-1.8-openjdk/jre
            - name: spring.cloud.nacos.discovery.server-addr
              value: nacos-server:8848
            image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/demo:sc-consumer-0.1
            imagePullPolicy: Always
            name: sc-consumer-empty
            ports:
            - containerPort: 18091
            livenessProbe:
              tcpSocket:
                port: 18091
              initialDelaySeconds: 10
              periodSeconds: 30
    ---
    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.small
        service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet
      name: sc-consumer-empty-slb
    spec:
      ports:
        - port: 80
          protocol: TCP
          targetPort: 18091
      selector:
        app: sc-consumer-empty
      type: LoadBalancer
    status:
      loadBalancer: {}
    # sc-provider
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sc-provider
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sc-provider
      strategy:
      template:
        metadata:
          labels:
            msePilotCreateAppName: sc-provider
            app: sc-provider
        spec:
          containers:
          - env:
            - name: JAVA_HOME
              value: /usr/lib/jvm/java-1.8-openjdk/jre
            - name: spring.cloud.nacos.discovery.server-addr
              value: nacos-server:8848
            image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/demo:sc-provider-0.3
            imagePullPolicy: Always
            name: sc-provider
            ports:
            - containerPort: 18084
            livenessProbe:
              tcpSocket:
                port: 18084
              initialDelaySeconds: 10
              periodSeconds: 30
    # Nacos Server
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nacos-server
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nacos-server
      template:
        metadata:
          labels:
            app: nacos-server
        spec:
          containers:
          - env:
            - name: MODE
              value: standalone
            image: nacos/nacos-server:v2.2.0
            imagePullPolicy: Always
            name: nacos-server
          dnsPolicy: ClusterFirst
          restartPolicy: Always
    
    # Nacos Server Service 配置
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nacos-server
    spec:
      ports:
      - port: 8848
        protocol: TCP
        targetPort: 8848
      selector:
        app: nacos-server
      type: ClusterIP
                            

开启推空保护功能

  1. 登录MSE治理中心控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择治理中心 > 应用治理,然后单击目标应用的资源量卡片。

  3. 在目标应用详情页面的左侧导航栏,单击流量治理,然后选择推空保护页签。

  4. 打开推空保护开关按钮。

查看推空保护事件

  1. 登录MSE治理中心控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择治理中心 > 应用治理,然后单击目标应用的资源量卡片。

  3. 在目标应用详情页面的左侧导航栏,单击流量治理,然后选择推空保护页签。

  4. 在页面的右上角,查看保护事件

功能验证

  1. 编写测试脚本vi curl.sh

    while :
    do
            result=`curl $1 -s`
            if [[ "$result" == *"500"* ]]; then
                    echo `date +%F-%T` $result
            else
                    echo `date +%F-%T` $result
            fi
    
            sleep 0.1
    done
  2. 执行脚本,进行测试。

    1. 执行脚本% sh curl.sh {sc-consumer-empty-slb}:18091/user/rest,显示如下:

      2022-01-19-11:58:12 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:12 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:12 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:13 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:13 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:13 Hello from [18084]10.116.0.142!
    2. 保持脚本一直在调用,观察MSE控制台看到如下情况:

      应用详情

    3. 执行脚本% sh curl.sh {sc-consumer-slb}:18091/user/rest,显示如下:

      2022-01-19-11:58:13 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:13 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:13 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:14 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:14 Hello from [18084]10.116.0.142!
      2022-01-19-11:58:14 Hello from [18084]10.116.0.142!
    4. 保持脚本一直在调用,观察MSE控制台看到如下情况:

      应用详情

  3. 将coredns组件缩容至数量0,模拟DNS网络解析异常场景。

    无状态发现实例与Nacos的连接断开且服务列表为空。

  4. 模拟DNS服务恢复,将其扩容回数量2。

结果验证

在以上持续的业务流量过程中,可以发现sc-consumer-empty服务出现大量且持续的报错。只有重启了Provider,sc-consumer-empty才恢复正常。

2022-01-19-12:02:37 {"timestamp":"2022-01-19T04:02:37.597+0000","status":500,"error":"Internal Server Error","message":"com.netflix.client.ClientException: Load balancer does not have available server for client: mse-service-provider","path":"/user/feign"}
2022-01-19-12:02:37 {"timestamp":"2022-01-19T04:02:37.799+0000","status":500,"error":"Internal Server Error","message":"com.netflix.client.ClientException: Load balancer does not have available server for client: mse-service-provider","path":"/user/feign"}
2022-01-19-12:02:37 {"timestamp":"2022-01-19T04:02:37.993+0000","status":500,"error":"Internal Server Error","message":"com.netflix.client.ClientException: Load balancer does not have available server for client: mse-service-provider","path":"/user/feign"}

相比sc-consumer-empty,sc-consumer应用全流程没有任何报错。

相关文档

如果您使用的是MSE Nacos,还可以开启Nacos推空保护做多一层的兜底保护。具体操作,请参见推空保护

  • 本页导读 (1)
文档反馈