如果想直接查看修改部分请跳转 动手-点击跳转
本文基于 ReactiveLoadBalancerClientFilter使用RoundRobinLoadBalancer
灰度发布
灰度发布,又称为金丝雀发布,是一种新旧版本平滑发布的方式。在上面可以对同一个API进行两个版本 的内容,由一部分用户先行体验,如无问题,逐步扩大发布范围
本文将讲述如何基于基于nacos的matedata与Ribbon如何去做灰度发布
重点知识
Spring Cloud Gateway两种负载均衡器
官网说明两种负载均衡器
Gateway有两种客户端负载均衡器,LoadBalancerClientFilter和ReactiveLoadBalancerClientFilter。
LoadBalancerClientFilter使用一个Ribbon的阻塞式LoadBalancerClient,Gateway建议使用ReactiveLoadBalancerClientFilter。
可以通过设置spring.cloud.loadbalancer.ribbon.enabled=false,切换到ReactiveLoadBalancerClientFilter。无论使用Ribbon还是LoadBalancer,在Route中配置的lb是一样的
本节采用 ReactiveLoadBalancerClientFilter 进行设置
采用ReactiveLoadBalancerClientFilter使用RoundRobinLoadBalancer
灰度发布服务器选择 简单示意图
Client —-> gateway —-> GlobalFilter 拦截 选择一个灰度发布服务器 如果没有灰度服务则选取正常服务器 —->转发到服务
nacos的matedata
我们在向 Nacos Server 进行服务注册的时候往往会附加一些 metadata ,可以参考官方文档中 Dubbo 融合 Nacos 成为注册中心 章节。
充分利用好服务实例的 metadata ,可以衍生出许多有意思的实践。
完全可以把相关内容放进 metadata 中,好比说版本号,特性名等等
然后再根据负载均衡路由到不同的服务
1 2
|
spring.cloud.nacos.discovery.metadata.version=1.15 spring.cloud.nacos.discovery.metadata.advance=true
|
准备工作
nacos 部署
gateway 部署 -可以参考
部署两台服务A
开始
跟踪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR); if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) { ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url); if (log.isTraceEnabled()) { log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url); }
return this.choose(exchange).doOnNext((response) -> { if (!response.hasServer()) { throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost()); } else { ServiceInstance retrievedInstance = (ServiceInstance)response.getServer(); URI uri = exchange.getRequest().getURI(); String overrideScheme = retrievedInstance.isSecure() ? "https" : "http"; if (schemePrefix != null) { overrideScheme = url.getScheme(); }
DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance, overrideScheme); URI requestUrl = this.reconstructURI(serviceInstance, uri); if (log.isTraceEnabled()) { log.trace("LoadBalancerClientFilter url chosen: " + requestUrl); }
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl); } }).then(chain.filter(exchange)); } else { return chain.filter(exchange); } }
protected URI reconstructURI(ServiceInstance serviceInstance, URI original) { return LoadBalancerUriTools.reconstructURI(serviceInstance, original); }
private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) { URI uri = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); ReactorLoadBalancer<ServiceInstance> loadBalancer = (ReactorLoadBalancer)this.clientFactory.getInstance(uri.getHost(), ReactorSer |