【灰度发布(二)】服务端灰度流量API网关业务实现
一.灰度标签元数据定义
1.上行流量(Nginx携带)的灰度标记Header定义
X-Tags: gray-V1.0
2.以业务服务为例,灰度标签元数据定义如下
灰度标签Key:grayTag
特殊灰度调用标签:grayPriorityTag(特殊标志,作用后续会有说明)
spring:
cloud:
nacos:
discovery:
metadata:
# 灰度标签 标记灰度示例
grayTag: "gray-V1.0"
# 灰度调用优先级 特殊服务需要优先调用灰度服务
grayPriorityTag: "1"
3. 核心逻辑:识别到携带灰度标记(X-Tags)的灰度请求后,与下游的目标服务进行路由规则匹配
二.API Gateway网关灰度过滤器
@Slf4j
@Component
public class GatewayLoadBalancerClientFilter extends LoadBalancerClientFilter {
public GatewayLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
super(loadBalancer, properties);
}
@Override
protected ServiceInstance choose(ServerWebExchange exchange) {
URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
String routeId = exchange.getAttribute(GatewayConstant.ROUTE_ID);
if (this.loadBalancer instanceof RibbonLoadBalancerClient) {
String serviceId = ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost();
HttpHeaders headers = exchange.getRequest().getHeaders();
String tags = headers.getFirst(GatewayConstant.X_TAGS);
if(StringUtils.hasText(tags)) {
RibbonLoadBalancerClient client = (RibbonLoadBalancerClient) this.loadBalancer;
exchange.getAttributes().put(GatewayConstant.X_TAGS, tags);
log.info("执行灰度路由 uri:{} routeId:{} serviceId:{},tags:{}",uri,routeId, serviceId, tags);
return client.choose(serviceId,tags);
}
}
if(log.isDebugEnabled()) {
log.debug("执行正常路由...:{} routeId:{}", uri,routeId);
}
return super.choose(exchange);
}
}
三.网关Ribbon灰度路由规则重写
@Slf4j
public class GateWayLoadBalancerRule extends AbstractLoadBalancerRule {
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object key) {
if (log.isDebugEnabled()) {
log.debug("开始执行网关负责均衡规则:{}", key);
}
try {
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
List<Instance> instances = loadBalancer.getReachableServers().stream().map(server -> ((NacosServer) server).getInstance())
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(instances)) {
log.warn("服务实例不存在:{}", loadBalancer.getName());
return null;
}
if (ObjectUtils.isEmpty(key) || "default".equals(key.toString())) {
Instance instance = ExtendBalancer.getHostByRandomWeight2(instances);
if (log.isDebugEnabled()) {
log.debug("执行正常流量实例调度信息:{}", JSON.toJSONString(instance));
}
return new NacosServer(instance);
} else {
Instance instance = chooseGrayInstance(instances, key.toString());
return new NacosServer(instance);
}
} catch (Exception e) {
log.warn("获取目标节点异常:{}", e.getMessage(), e);
return null;
}
}
private Instance chooseGrayInstance(List<Instance> instances, String grayTag) {
List<Instance> grayInstances = instances.stream()
.filter(instance -> grayTag.equals(instance.getMetadata().get("grayTag")))
.collect(Collectors.toList());
if (!grayInstances.isEmpty()) {
Instance instance = ExtendBalancer.getHostByRandomWeight2(grayInstances);
if (log.isDebugEnabled()) {
log.debug("执行灰度负载均衡调用,目标实例信息:{}", instance.getInstanceId());
}
return instance;
} else {
Instance instance = ExtendBalancer.getHostByRandomWeight2(instances);
if (log.isDebugEnabled()) {
log.info("灰度负载均衡调用,没有灰度实例 默认调度正常示例信息:{}", instance.getInstanceId());
}
return instance;
}
}
}

浙公网安备 33010602011771号