Spring Cloud Gateway和Zuul是两种常用的微服务架构中的API网关,它们均能实现路由转发和过滤器处理等功能。通过配置路由规则,可以将请求路由到灰度环境中,对灰度版本进行验证和测试。借助MSE提供的全链路灰度能力,您无需修改业务代码,即可实现端到端的全链路流量控制。本文介绍如何通过配置Spring Cloud Gateway或者Zuul网关实现全链路灰度。
前提条件
背景信息
本文通过模拟真实的调用链路为您演示MSE全链路灰度功能。您无需修改任何业务代码,只需要给入口应用设置流量规则,该流量的标签会通过链路透传到下一个灰度版本中。在每个应用的调用过程中,符合金丝雀条件的流量会优先调用对应的版本,如果没有对应版本则会自动切换回基线版本(即稳定版本)。
部署spring-cloud-gateway、spring-cloud-a、spring-cloud-b、spring-cloud-c这四个业务应用,以及注册中心Nacos Server。调用链路为:spring-cloud-gateway->A->B->C。
应用之间的调用既包含了Spring Cloud服务调用,也包含了Dubbo服务调用。
全链路灰度提供了给流量染色,并让灰度流量优先调用灰度节点的能力,帮助您进行可控的灰度验证,保障稳定性。
全链路灰度验证通常采用以下策略:
直接调用现有线上流量的一小部分进行测试,通常按照百分比控制。
按照特定规则筛选线上流量进行验证,如使用指定的Header或Cookie等。
本文将分别介绍上述两种策略配置方式,以便适应微服务架构中不同的灰度发布需求。
步骤一:将应用接入MSE微服务治理
将ACK微服务应用接入MSE治理中心,您可以选择您需要的方式实现应用接入。更多信息,请参见ACK微服务应用接入MSE治理中心。
为ACK命名空间中的应用开启MSE微服务治理
登录MSE治理中心控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择治理中心 > 应用治理。
在应用列表页面,单击ACK应用接入。
在ACK应用接入对话框中,进行配置,配置完成后,单击确定。
配置项
说明
集群类型
选择ACK集群、ACK Serverless集群和ACS集群
说明如果您尚未授权容器服务调用微服务引擎,则需要单击请授权进行授权。
集群名称/ID
选择接入MSE微服务治理的集群名称/ID,可通过关键词搜索。
ack-onepilot
显示ack-onepilot接入状态。
如果您未安装ack-onepilot,单击ack-onepilot右侧的点击安装,安装完成后状态会显示为已安装。
如果您使用子账号接入,提示没有权限使用时,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理,然后找到ack-onepilot,点击安装。
说明该步骤接入的组件为ack-onepilot,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理查看详情。
ack-onepilot安装后会自动注入探针,可能会导致应用启动耗时增加(10s内)。
接入类型
选择命名空间接入。
容器集群命名空间
选择容器集群命名空间。
治理命名空间
选择治理命名空间。在对应命名空间下重新部署现有应用或新创建的应用,均会接入到MSE微服务治理中。
为单个应用开启MSE微服务治理
登录MSE治理中心控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择治理中心 > 应用治理。
在应用列表页面,单击ACK应用接入。
在ACK应用接入对话框中,进行配置,配置完成后,单击确定。
配置项
说明
集群类型
选择ACK集群、ACK Serverless集群和ACS集群。
说明如果您尚未授权容器服务调用微服务引擎,则需要单击请授权进行授权。
集群名称/ID
选择接入MSE微服务治理的集群名称/ID,可通过关键词搜索。
ack-onepilot
显示ack-onepilot接入状态。
如果您未安装ack-onepilot,单击ack-onepilot右侧的点击安装,安装完成后状态会显示为已安装。
如果您使用子账号接入,提示没有权限使用时,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理,然后找到ack-onepilot,点击安装。
说明该步骤接入的组件为ack-onepilot,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理查看详情。
ack-onepilot安装后会自动注入探针,可能会导致应用启动耗时增加(10s内)。
接入类型
选择单个应用接入。
接入步骤
按照接入步骤进行操作。
Step 1:进入集群工作负载-无状态应用页面,切换到应用的命名空间下。
Step 2:找到所接入的应用,点击「查看Yaml」。
Step 3:按以下格式编辑Labels,完成后点击「更新」。
spec: template: metadata: labels: # 填写“on”表示开启接入,需加上双引号 msePilotAutoEnable: "on" # 填写接入到的治理命名空间,值不存在可自动新建 mseNamespace: 202401 # 填写接入MSE的实际应用名称,需加上双引号 msePilotCreateAppName: "your-deployment-name"
步骤二:部署应用(模拟线上场景)
登录容器服务管理控制台,在左侧导航栏选择集群。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
在无状态页面选择命名空间,然后单击使用YAML创建资源。
本文示例中部署一个注册中心Nacos Server,然后部署spring-cloud-gateway、spring-cloud-a、spring-cloud-b、spring-cloud-c这四个业务应用。您也可以直接在Demo中获取对应的源码。
注册中心Nacos Server YAML
spring-cloud-c应用YAML
spring-cloud-b应用YAML
spring-cloud-a应用YAML
spring-cloud-gateway应用YAML
执行以下命令查看部署结果:
kubectl get svc,deploy
预期输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 172.16.x.x <none> 443/TCP 23h service/nacos-server ClusterIP 172.16.x.x <none> 8848/TCP,9848/TCP 94s service/spring-cloud-gateway-slb LoadBalancer 172.16.x.x 8.130.x.x 80:32641/TCP 57s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nacos-server 1/1 1 1 94s deployment.apps/spring-cloud-a 1/1 1 1 66s deployment.apps/spring-cloud-b 1/1 1 1 74s deployment.apps/spring-cloud-c 1/1 1 1 83s deployment.apps/spring-cloud-gateway 1/1 1 1 57s
步骤三:部署spring-cloud-c、spring-cloud-a应用的灰度版本
登录容器服务管理控制台。使用如下YAML部署spring-cloud-c应用的灰度版本:
使用如下YAML部署spring-cloud-a应用的灰度版本:
步骤四:创建灰度环境泳道组
登录MSE治理中心控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择 。
单击创建泳道组及泳道。如果您选择的微服务空间内已经创建过泳道组,则单击+创建泳道组。
在创建泳道组面板,单击+ 创建泳道组,在创建泳道组页面,设置如下相关配置,然后单击确定。
配置项
说明
泳道组名称
自定义泳道组的名称。
入口类型
选择Java服务网关。
入口应用
选择spring-cloud-gateway。
泳道组涉及应用
选择spring-cloud-a、spring-cloud-b和spring-cloud-c。
泳道组创建完成后,在全链路灰度页面的泳道组区域,可以查看您创建的泳道组。如需变更泳道组信息,单击图标,可在页面自行修改相关信息。
步骤五:创建灰度环境泳道
使用全链路灰度功能时,需要您给灰度应用添加一个特殊的
tag
标记,以便将这些节点和其他节点区分开来。容器环境下需要您在spec.template.metadata.labels
下增加alicloud.service.tag: ${tag}
信息。ECS 环境下需要添加Java启动参数-Dalicloud.service.tag=${tag}
。以Java网关作为全链路灰度入口时,MSE支持两种泳道模式。
按请求内容灰度:当请求内容可以用于灰度识别时,建议采用此种灰度模式。如果不可以,也强烈建议您通过系统改造增加此类灰度标识,以便获得更好的灰度效果。比如,可以保持灰度请求前后的一致性。
按比例路由灰度:当请求内容无法用于灰度识别且遗留系统也无法进行改造时,可以采用此种退化的灰度模式。该模式有一定弊端,可能导致同一来源的请求进入不同泳道,而造成灰度请求前后行为的不一致。
泳道路由模式在一个泳道组中需要保持一致。您只有在创建泳道组中第一条泳道时可以调整网关路由规则Path和泳道路由模式。
在全链路灰度页面底部,单击点击创建第一个分流泳道。如果您选择的微服务空间内已经创建过泳道,则单击创建泳道。
在创建泳道面板,设置流控泳道相关配置,然后单击确定。
配置项 | 说明 |
配置节点标签 | 需要您手工给您的灰度应用节点打上标签,用来和正常节点做区分。 |
填写泳道信息 | 泳道标签:该泳道内的匹配的流量去往的目标标签。 确认匹配关系:检查您配置了该标签的应用节点数是否符合预期。 |
配置路由和灰度规则 | 设置流量进入该泳道的规则。
说明 您还可以为每条网关path分别设置不同的流量比例,开启该功能时,您需要注意该每条path当前在所有泳道组中配置的流量比例总和不应超过100%。 |
创建按请求内容路由的泳道
配置项 | 说明 |
配置节点标签 | 需要您给灰度应用节点打上标签,用来和正常节点做区分。 |
填写泳道信息 | 泳道标签:该泳道内所匹配的流量去往的目标标签。本示例将泳道目标标签设置为gray。 确认匹配关系:检查您配置了该标签的应用节点数是否符合预期。 |
配置路由和灰度规则 | 设置相应的路由规则条件。
|
创建按比例路由的泳道
请确保MSE Java Agent的版本为3.2.3及以上,否则会影响百分比灰度能力。
配置项 | 说明 |
配置节点标签 | 需要您给灰度应用节点打上标签,用来和正常节点做区分。 |
填写泳道信息 | 泳道标签:该泳道内所匹配的流量去往的目标标签。本示例将泳道目标标签设置为gray。 确认匹配关系:检查您配置了该标签的应用节点数是否符合预期。 |
配置路由和灰度规则 | 设置相应的路由规则条件。
|
完成泳道创建后,在全链路灰度的流量分配区域,可以查看泳道详情,还可以进行如下操作。
在操作列,选择开启,创建的泳道将会生效,即流量会按照泳道方式进行流转,满足规则的流量会优先流向标记有当前泳道对应标签的应用版本,如果没有对应标签的应用版本,则流向未打标的应用版本。
在操作列,选择关闭,关闭创建的泳道,即该应用往后的流量会流向未打标的应用版本。
单击图标,可以查看该泳道的流量比例。
单击图标,可以设置该泳道上应用的状态。
步骤六:测试基线及灰度版本流量
测试按请求内容路由的泳道
使用curl命令测试基线流量:
curl 8.130.x.x/A/a A[192.168.x.x][config=base] -> B[192.168.x.x] -> C[192.168.x.x]
说明命令中的
8.130.x.x
是Spring Cloug Gateway暴露出的公网IP地址。使用curl命令测试灰度流量:
curl 8.130.x.x/A/a?name=xiaoming Agray[192.168.x.x][config=base] -> B[192.168.x.x] -> Cgray[192.168.x.x]
说明当参数带上
name=xiaoming
时,会命中灰度标签,并向后透传。比如灰度请求到A应用和C应用时,会请求到Agray和Cgray节点。
请求到B应用时,由于不存在Bgray节点,仍然会请求B的基线节点。
测试按比例路由的泳道
通过如下Python3脚本测试按比例路由的分流情况(需要安装requests包)。注意将x.x.x.x
替换为spring-cloud-gateway网关的入口SLB地址。
# pip3 install requests
# python3 traffic.py
import requests
TOTAL_REQUEST = 100
ENTRY_URL = 'http://x.x.x.x/A/a'
def parse_tag(text:str):
'''
A[10.0.23.64][config=base] -> B[10.0.23.65] -> C[10.0.23.61]
Agray[10.0.23.64][config=base] -> B[10.0.23.65] -> Cgray[10.0.23.61]
Ablue[10.0.23.64][config=base] -> B[10.0.23.65] -> Cblue[10.0.23.61]
'''
print(text)
app_parts = text.split(' -> ')
# tag_app: C[10.0.23.61] / Cgray[10.0.23.61]
tag_app = app_parts[-1]
splits = tag_app.split('[')
# tag_part: C / Cgray
tag_part = splits[0]
tag = tag_part[1:]
return tag if len(tag) > 0 else 'base'
def get_tag(url:str):
resp = requests.get(url)
resp.encoding = resp.apparent_encoding
return parse_tag(resp.text)
def cal_tag_count(url:str, total_request:int):
count_map = {}
for i in range(total_request):
tag = get_tag(url)
if tag not in count_map:
count_map[tag] = 1
else:
count_map[tag] += 1
print()
print('Total Request:', total_request)
print('Traffic Distribution:', count_map)
if __name__ == '__main__':
cal_tag_count(ENTRY_URL, TOTAL_REQUEST)
从结果可以看到,约有30%的流量去往了灰度环境。
步骤七:可观测
若应用出现异常,您可以通过MSE提供的可观测能力查看异常数据,帮助您快速定位问题。
微服务治理可观测
在MSE微服务治理的全链路灰度页面,单击目标应用,在应用 QPS 监控区域,可查看对应泳道基线版本和灰度版本的流量情况。
总QPS:该应用总的QPS。
异常QPS:该应用出错的请求数。
GrayQPS:该应用的灰度版本的QPS。