Java体系-微服务治理-无损下线

在生产环境中,应用的部署、回滚、缩容等操作是不可避免的。如果您的应用没有具备无损下线的能力,您的任何应用在发布的过程中会造成短暂的服务不可用,短时间内业务监控会出现大量 IO 异常报错。如何在服务更新部署、缩容过程中保证业务无感知,是开发者必须要解决的问题,下面我们介绍基于MSE的无损下线。

背景信息


关于MSE的详细介绍,请参见什么是微服务引擎MSE

前提条件


操作步骤


步骤一:安装Demo应用

1. 安装helm-acr插件。

  • 如果您位于海外或访问Github比较流畅,执行以下命令安装Helm插件。
helm plugin install https://github.com/AliyunContainerService/helm-acr
  • 如果您位于国内且为Linux操作系统,执行以下命令安装Helm插件。
git clone https://github.com/AliyunContainerService/helm-acr.git
sed -i 's/github.com/helm-acr-releases.oss-cn-hangzhou.aliyuncs.com/g' helm-acr/scripts/install_plugin.sh
helm plugin install helm-acr
  • 如果您位于国内且为Mac操作系统,执行以下命令安装Helm插件。
git clone https://github.com/AliyunContainerService/helm-acr.git
sed -i '' 's/github.com/helm-acr-releases.oss-cn-hangzhou.aliyuncs.com/g' helm-acr/scripts/install_plugin.sh
helm plugin install helm-acr

2. 安装demo应用。

# 添加 helm repo
export HELM_REPO_USERNAME='edas_common_test@aliyun-inner.com';
export HELM_REPO_PASSWORD='Hello1234';
helm repo add mse acr://microservice-repo-chart.cn-hangzhou.cr.aliyuncs.com/ms/canary --username ${HELM_REPO_USERNAME} --password ${HELM_REPO_PASSWORD}
# 部署 MSE-Samples
helm install mse-samples-v2 mse/mse-samples --namespace default

安装成功后,示例如下

$ kubectl get svc,deploy,ing
NAME                       TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
service/kubernetes         ClusterIP      172.21.0.1    <none>         443/TCP        13h
service/nacos-server       ClusterIP      172.21.1.80   <none>         8848/TCP       13h
service/zuul-gateway-svc   LoadBalancer   172.21.2.69   192.168.0.48   80:32266/TCP   13h

NAME                                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/nacos-server                   1/1     1            1           13h
deployment.extensions/sc-a-gray                      1/1     1            1           13h
deployment.extensions/sc-a-normal                    4/4     4            4           13h
deployment.extensions/sc-a-normal-without-shutdown   4/4     4            4           13h
deployment.extensions/sc-b-gray                         1/1     1            1           13h
deployment.extensions/sc-b-normal                    1/1     1            1           13h
deployment.extensions/sc-c                           1/1     1            1           13h
deployment.extensions/zuul-gateway                   1/1     1            1           13h

NAME                              HOSTS   ADDRESS           PORTS   AGE
ingress.extensions/zuul-ingress   *       101.133.150.118   80      13h  
# 获取ingress的ip
export INGRESS_IP=`kubectl get ing zuul-ingress -n default --output jsonpath="{.status.loadBalancer.ingress[*].ip}"|xargs -I {} echo {}`

Demo应用的架构如下图所示。流量从 Netflix Zuul 对应的 Ingress 进来,会调用 SC-A 应用对应的服务,SC-A 应用内部调用 SC-B 应用的服务,SC-B 应用内部调用 SC-C 应用的服务。其中sc-a-gray、sc-b-gray用于金丝雀发布演示,SC-A 的正常版本通过两个 Deployment 部署,其中带 -without-shutdown 的 Deployment 关闭无损下线功能,不带 -without-shutdown 的 Deployment 会被 MSE 默认开启无损下线功能。关闭无损下线的 Deployment 在下线/缩容等场景下会出现流量损失、业务报错的问题。

步骤二:验证无损下线的效果

  1. 执行一下命令,查询Netflix Zuul的Ingress IP地址。
$ kubectl get ing zuul-ingress -n default --output jsonpath="{.status.loadBalancer.ingress[*].ip}"|xargs -I {} echo {}
101.133.150.118
  1. 访问该ip我们可以看到如下所示一个简单的页面

  2. 当我们打开开关页面就会不断去访问后端服务,并且将结果打印至页面,对应的字符串是 A[] ->B[] ->C[] ,其中[]中的内容是对应服务提供者的ip,我们可以看到A[]中的ip在不断变化,其中会记录调用的总数与调用失败的次数

  1. 当我们缩容 sc-a-normal-without-shutdown 应用从4个pod缩容至1个 可以看到其由于关闭了MSE无损下线的能力,缩容的过程中会产生错误。

  1. 我们重新打开一下开关让其从0开始重新计数,我们去缩容 sc-a-normal 应用从4个pod缩容至1个,可以看到在这个过程中没有任何错误,即业务没任何感知。

而两个应用的差别就是在Yaml文件中是否有如下的配置。

annotations:
  msePilotAutoEnable: "on"
  msePilotCreateAppName: "<your-deployment-name>"   

操作总结


方案优势:

  1. 应用接入过程不需要修改Java代码。只需要在Pod的annotation里添加对应注解即可。
  2. 微服务的调用方和服务方都需要接入微服务治理(MSE)系统才能完成无损下线

由于篇幅所限,本文例子中使用的注册中心为nacos,微服务协议是springcloud,同样的方案适用于如下的微服务中心和服务协议:

  • 微服务中心
  1. zookeeper
  2. nacos
  3. eureka
  • 微服务协议
  1. dubbo
  2. springcloud