基于MSE云原生网关实现同城多活

云原生网关默认采用多可用区部署,提供了地域级的、跨可用区的全局流量管理能力。在同城多活的场景下,能够确保对跨可用区的多个业务集群的请求实现高效负载均衡分配,在单个可用区内的业务集群发生故障时,可在1秒内完成故障节点的自动摘除从而实现故障转移,有效的保障服务连续性和高可用性。

容灾概述

目前云上容灾主要分为以下三类:

  • 同城跨AZ容灾

    同城容灾包含多活容灾和主备容灾,同城中心之间物理距离较近,网络延迟低,可防范AZ级别性质的灾难损害,例如火灾、断网或断电等。

  • 跨地域多活容灾

    跨地域多活容灾对于网络延迟相对较高,但可以防范地域性质的灾难损害,例如地震、水灾等。

  • 两地三中心

    两地三中心将同城双中心和跨地域灾备结合起来,兼具两者的优点,适用于应用与数据连续性和可用性要求高的场景。

从实际情况考虑,同城容灾相比于跨地域容灾,在数据容灾方面更容易实现,所以同城容灾仍然具有非常重要的意义。

功能优势

基于云原生网关的容灾方案与基于DNS流量分发的容灾方案对比优势如下:

  • 云原生网关默认多可用区部署,提供地域级的全局流量管理能力。

  • 基于DNS流量分发的容灾方案需要手动调整分发到各个集群的流量比例,而基于云原生网关的容灾方案则会根据工作负载总数量动态的调整分发到各集群的流量比例,针对于无法保证对等部署的场景下,可有效防止部署资源较少的集群的后端服务崩溃。

  • 基于多集群网关的容灾支持七层路由转发能力,而基于DNS流量分发的容灾不支持七层路由转发。

  • 基于DNS流量分发的容灾方案在IP切换时,通常会有客户端缓存而造成服务短暂不可用,而基于云原生网关的容灾方案则可以平滑地将流量Fallback到另一个集群的服务后端。

方案架构

基于云原生网关同地域跨可用区的全局流量管理能力,当单可用区(可用区I)发生故障后,可实现100%流量自动被路由到其它可用区(可用区J)。

image

说明
  • 两个可用区各一个SLB,可有效避免SLB单点故障,当单可用区SLB发生故障后,可通过DNS切流。

  • 一个云原生网关,多可用区部署,实现跨可用区、多业务集群的全局流量管理能力,可有效保证多集群的请求负载均衡,可实现单可用区故障后秒级、自动切流。

  • 每个集群对应一个Nacos,可有效保证微服务调用在可用区内闭环,单可用区发生故障后触发网关自动切流后可保证微服务调用流量无损。

准备工作

  1. 创建两个Nacos引擎

  2. 在两个不同可用区各创建一个K8s集群。具体操作,请参见创建Kubernetes托管版集群

  3. 如果您要实现同城多活的其中一个K8s集群是在自建的IDC或其他云平台,您可以通过ACK One的注册集群快速入门将云下的K8s集群接入云端。在本文的可用区I的K8s集群,即是通过注册集群完成从自建到云上的接入。

    展开查看自建K8s集群接入云上的操作步骤

    1. 通过kubeadm自建一个K8s集群。

      image.png

    2. 查看集群网络模式。集群的网络插件使用的是Calico,网络模式是Calico IPIP模式。

      image.png

    3. 自建集群接入注册集群。具体操作,请参见将目标集群接入注册集群中

      image.png

    4. 由于自建的K8s集群使用的网络模式是Calico IPIP模式,云上的资源如想访问自建集群内的Pod需要经过Node做路由转发,因此在接入完成后,还需要在VPC的路由表内配置一下Pod的网段到Node的路由条目。

      image.png

      说明

      请根据实际情况打通网络。具体操作,请参见混合网络概述

  4. 创建云原生网关

    说明

    创建云原生网关时选择多可用区部署,请确保新创建的云原生网关和您的集群在同一VPC下。

视频教程

步骤一:在集群中部署Demo应用

  1. 登录容器服务管理控制台。分别在不同可用区下的ACK集群中使用如下YAML部署Demo应用。其中nacos_addressenv需要替换为您的实际环境参数。

    可用区I的部署YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: duohuo-provider
      labels:
        app: duohuo-provider
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: duohuo-provider
      template:
        metadata:
          labels:
            app: duohuo-provider
        spec:
          containers:
            - env:
                - name: nacos_address #注册中心的endpoint
                  value: 'mse-a8473b30-nacos-ans.mse.aliyuncs.com:8848' 
                - name: env  #所在可用区标识,izone,jzone
                  value: izone
              image: 'registry.cn-hangzhou.aliyuncs.com/jinfengdocker/mse-duohuo-provider:v1'
              imagePullPolicy: Always
              name: duohuo-provider
              ports:
                - containerPort: 8080
                  protocol: TCP
              resources:
                limits:
                  cpu: '2'
                  memory: 1Gi
                requests:
                  cpu: '0.5'
                  memory: 0.1Gi
    ---
    apiVersion: apps/v1         
    kind: Deployment
    metadata:
      name: duohuo-consumer
      labels:
        app: duohuo-consumer
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: duohuo-consumer
      template:
        metadata:
          labels:
            app: duohuo-consumer
        spec:
          containers:
            - env:
                - name: nacos_address #注册中心的endpoint
                  value: 'mse-a8473b30-nacos-ans.mse.aliyuncs.com:8848' 
                - name: env  #所在可用区标识,izone,jzone
                  value: izone
              image: 'registry.cn-hangzhou.aliyuncs.com/jinfengdocker/mse-duohuo-consumer:v1'
              imagePullPolicy: Always
              name: duohuo-consumer
              ports:
                - containerPort: 8080
                  protocol: TCP
              resources:
                limits:
                  cpu: '2'
                  memory: 1Gi
                requests:
                  cpu: '0.5'
                  memory: 0.1Gi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: duohuo-consumer-service
    spec:
      ports:
        - name: http
          port: 8080
          protocol: TCP
          targetPort: 8080
      selector:
        app: duohuo-consumer
      sessionAffinity: None
      type: ClusterIP

    可用区J的部署YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: duohuo-provider
      labels:
        app: duohuo-provider
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: duohuo-provider
      template:
        metadata:
          labels:
            app: duohuo-provider
        spec:
          containers:
            - env:
                - name: nacos_address # 注册中心的Endpoint
                  value: 'mse-7a4cd080-nacos-ans.mse.aliyuncs.com:8848' 
                - name: env  # 所在可用区标识,izone,jzone
                  value: jzone
              image: 'registry.cn-hangzhou.aliyuncs.com/jinfengdocker/mse-duohuo-provider:v1'
              imagePullPolicy: Always
              name: duohuo-provider
              ports:
                - containerPort: 8080
                  protocol: TCP
              resources:
                limits:
                  cpu: '2'
                  memory: 1Gi
                requests:
                  cpu: '0.5'
                  memory: 0.1Gi
    ---
    apiVersion: apps/v1         
    kind: Deployment
    metadata:
      name: duohuo-consumer
      labels:
        app: duohuo-consumer
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: duohuo-consumer
      template:
        metadata:
          labels:
            app: duohuo-consumer
        spec:
          containers:
            - env:
                - name: nacos_address # 注册中心的Endpoint
                  value: 'mse-7a4cd080-nacos-ans.mse.aliyuncs.com:8848' 
                - name: env  # 所在可用区标识,izone,jzone
                  value: jzone
              image: 'registry.cn-hangzhou.aliyuncs.com/jinfengdocker/mse-duohuo-consumer:v1'
              imagePullPolicy: Always
              name: duohuo-consumer
              ports:
                - containerPort: 8080
                  protocol: TCP
              resources:
                limits:
                  cpu: '2'
                  memory: 1Gi
                requests:
                  cpu: '0.5'
                  memory: 0.1Gi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: duohuo-consumer-service
    spec:
      ports:
        - name: http
          port: 8080
          protocol: TCP
          targetPort: 8080
      selector:
        app: duohuo-consumer
      sessionAffinity: None
      type: ClusterIP

  2. 部署成功后,您可以在对应的ACK集群中看到两个工作负载和一个服务。

    image

    image

步骤二:创建来源

在云原生网关中创建两个服务来源,关联您在两个可用区的容器集群。具体操作,请参见新建服务来源

image.png

步骤三:创建服务

在云原生网关中创建服务。具体操作,请参见添加服务

云原生网关支持跨集群的服务统一管理,创建的服务会自动将两个K8s集群中相同命名空间下的同名服务进行合并。

image.png

image.png

步骤四:云原生网关创建路由

在云原生网关中创建路由,设置域名和匹配规则。选择目标服务后保存并上线路由。具体操作,请参见新建路由规则

image.png

image

步骤五:切流效果验证

云原生网关可根据后端集群的工作负载数及健康状态动态的调整流量。本文分别演示两个集群工作负载数量对等部署非对等部署机房故障场景下云原生网关自动切流效果。

使用如下Shell脚本,循环对网关发起请求。

#!/bin/bash
for (( i = 1; i < 1000000000; i++ )); do
      curl http://114.55.XXX.XXX/helloDuohuo  # IP需要替换成您网关的公网IP。
      sleep 1
      echo
done

两个集群工作负载数量对等部署

两个集群中工作负载的副本保持一致。

image.png

image.png

使用Shell脚本发起请求,输出结果如下表明流量被负载均衡到可用区I和可用区J,两个可用区的集群各承担了50%的流量。

image.png

两个集群工作负载数量非对等部署

可用区I的集群副本数量缩容为1。

image.png

使用Shell脚本发起请求,输出结果如下表明可用区J的集群承担了90%的流量,可用区I的集群承担了10%的流量。

image.png

机房故障场景下自动切流

可用区I的集群副本数量缩容为0。使用Shell脚本发起请求,输出结果如下表明100%的流量自动切换到了可用区J。

image.png

PTS压测

通过PTS压测,进一步观察可用区I故障后的自动切流时效性及切流过程中的流量损失。

  1. PTS新建压测场景:

    image.png

  2. 压测的RPS配置为100后,单击保存去压测。

    image.png

  3. 压测执行到1分钟以后,手动把可用区I集群中的所有工作负载删除掉,模拟集群故障,观察流量损失。

    image.png

    image.png

  4. 可以看到MSE在I可用区的集群挂掉后,可实现秒级切流,切流过程中仅有不到1%的流量损失。

    image.png