1. 背景
本文是阿里云微服务引擎MSE在服务发现高可用的最佳实践介绍。演示的应用架构是由后端的微服务应用实例(Spring Cloud)构成。具体的后端调用链路有Spring Cloud Consumer调用Spring Cloud Provider,这些应用中的服务之间通过Nacos注册中心实现服务注册与发现。
2. 动手实践
2.1 前提条件
已创建Kubernetes集群,请参见创建Kubernetes托管版集群。
已开通MSE微服务治理专业版,请参见开通MSE微服务治理。
2.2 准备工作
开启MSE微服务治理
开通微服务治理专业版:
单击开通MSE微服务治理。
微服务治理版本选择专业版,选中服务协议,然后单击立即开通。关于微服务治理的计费详情,请参见价格说明。
安装MSE微服务治理组件:
在容器服务控制台左侧导航栏中,选择市场 > 应用目录。
在应用目录页面搜索框中输入ack-mse-pilot,单击搜索图标,然后单击组件。
在详情页面选择开通该组件的集群,然后单击创建。安装完成后,在命名空间mse-pilotmse-pilot-ack-mse-pilot应用,表示安装成功。
为应用开启微服务治理:
登录MSE治理中心控制台。
在左侧导航栏选择微服务治理中心 > K8s集群列表。
在K8s集群列表页面搜索目标集群,单击搜索图标,然后单击目标集群操作列下方的管理。
在集群详情页面命名空间列表区域,单击目标命名空间操作列下方的开启微服务治理。
在开启微服务治理对话框中单击确认。
部署 Demo 应用程序
在容器服务控制台左侧导航栏中,单击集群。
在集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情。
在集群管理页左侧导航栏中,选择工作负载 > 无状态。
在无状态页面选择命名空间,然后单击使用YAML创建资源。
对模板进行相关配置,完成配置后单击创建。本文示例中部署sc-consumer、sc-consumer-empty、sc-provider,使用的是开源的Nacos。
部署示例应用(springcloud)
YAML:
# 开启推空保护的 sc-consumer
apiVersion: apps/v1
kind: Deployment
metadata:
name: sc-consumer
spec:
replicas: 1
selector:
matchLabels:
app: sc-consumer
template:
metadata:
annotations:
msePilotCreateAppName: sc-consumer
labels:
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
- name: profiler.micro.service.registry.empty.push.reject.enable
value: "true"
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
# 无推空保护的sc-consumer-empty
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sc-consumer-empty
spec:
replicas: 1
selector:
matchLabels:
app: sc-consumer-empty
template:
metadata:
annotations:
msePilotCreateAppName: sc-consumer-empty
labels:
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
# sc-provider
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sc-provider
spec:
replicas: 1
selector:
matchLabels:
app: sc-provider
strategy:
template:
metadata:
annotations:
msePilotCreateAppName: sc-provider
labels:
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:latest
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
我们只需在Consumer增加一个环境变量profiler.micro.service.registry.empty.push.reject.enable=true
,开启注册中心的推空保护(无需升级注册中心的客户端版本,无关注册中心的实现,支持MSE 的 nacos、eureka以及自建的nacos、eureka、console)
分别给Consumer应用增加SLB用于公网访问
以下分别使用{sc-consumer-empty}代表sc-consumer-empty应用的slb的公网地址,{sc-consumer}代表sc-consumer应用的slb的公网地址
2.3 应用场景
下面通过上述准备的Demo来分别实践以下场景
编写测试脚本
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
测试,分别开两个命令行,执行如下脚本,显示如下
% sh curl.sh {sc-consumer-empty}: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!
% sh curl.sh {sc-consumer}: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!
并保持脚本一直在调用,观察mse控制台分别看到如下情况
将coredns组件缩容至数量 0,模拟 dns 网络解析异常场景
发现实例与nacos的连接断开且服务列表为空
模拟dns服务恢复,将其扩容回数量2
2.4 结果验证
在以上过程中保持持续的业务流量,我们发现 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 应用全流程没有任何报错
只有重启了Provider,sc-consumer-empty 才恢复正常
相比之下,sc-consumer 应用全流程没有任何报错
3. 尾
保障云上业务的永远在线,是 MSE 一直在追求的目标,本文通过面向失败设计的服务发现高可用能力的分享,以及MSE的服务治理能力快速构建起服务发现高可用能力的演示,模拟了线上不可预期的服务发现相关异常发生时的影响以及我们如何预防的手段,展示了一个简单的开源微服务应用应该如何构建起服务发现高可用能力。