springcloud|springcloud gateway如何实现路由和负载均衡

简介: gateway主要是做路由 负载,过滤 主要是替代zuul 1.x 性能比zuul好 zuul是基于
Servlet ,gateway是基于spring-webflux 用的netty+reactor
yml文件 实现路由 负载 的配置 亲自测试

spring:application:name: xgyx_gatewaycloud:discovery:locator:enabled: truegateway:routes:- id: a#随便定义不重复就好uri: lb://xgyx-welfareservice-x#服务名称predicates:- Path=/m/**#前端访问需加入例如 http:ip:port/mfilters:- StripPrefix=1 #访问后端服务过滤掉m 必填否则找不到后端服务也可以在服务加上统一路径- name: Hystrix#熔断args:name: defaultfallbackUri: forward:/defaultfallback#熔断后访问路径- id: buri: lb://xgyx-welfareservicepredicates:- Path=/welfare/**filters:- StripPrefix=1- name: Hystrixargs:name: defaultfallbackUri: forward:/fallback#熔断时间hystrix:command:default:execution:isolation:strategy:SEMAPHOREthread:timeoutInMilliseconds: 300000#熔断时间

上面是用了两天时间根据官网上的demo和说明自己测的可以使用 上面 stripPrefix 用的是 PrefixPath 过滤器 其他过滤器使用可以看官网
springcloud gateway 自定义负载均衡 相关类及接口
LoadbalancerClientFilter:使用ribbon负载均衡,默认使用该类(已不推荐使用)
/** @deprecated */@Deprecatedpublic class LoadBalancerClientFilter implements GlobalFilter, Ordered {public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100; private static final Log log = LogFactory.getLog(LoadBalancerClientFilter.class); protected final LoadBalancerClient loadBalancer; private LoadBalancerProperties properties; public LoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {this.loadBalancer = loadBalancer; this.properties = properties; } public int getOrder() {return 10100; } public Mono 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("LoadBalancerClientFilter url before: " + url); } ServiceInstance instance = this.choose(exchange); if (instance == null) {throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost()); } else {URI uri = exchange.getRequest().getURI(); String overrideScheme = instance.isSecure() ? "https" : "http"; if (schemePrefix != null) {overrideScheme = url.getScheme(); } URI requestUrl = this.loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri); if (log.isTraceEnabled()) {log.trace("LoadBalancerClientFilter url chosen: " + requestUrl); } exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl); return chain.filter(exchange); }} else {return chain.filter(exchange); }} protected ServiceInstance choose(ServerWebExchange exchange) {return this.loadBalancer.choose(((URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR)).getHost()); }}

说明:默认使用该类,可通过下述方法使用ReactiveLoadbalancerClientFilter
【springcloud|springcloud gateway如何实现路由和负载均衡】?"You already have RibbonLoadBalancerClient on your classpath. It will be used by default.
As Spring Cloud Ribbon is in maintenance mode. We recommend switching to " + BlockingLoadBalancerClient.class.getSimpleName() + " instead.
In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false`
or remove spring-cloud-starter-netflix-ribbon from your project."

ReactiveLoadBalancerClientFilter:负载均衡拦截器
public class ReactiveLoadBalancerClientFilter implements GlobalFilter, Ordered {private static final Log log = LogFactory.getLog(ReactiveLoadBalancerClientFilter.class); private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150; private final LoadBalancerClientFactory clientFactory; private LoadBalancerProperties properties; public ReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) {this.clientFactory = clientFactory; this.properties = properties; } public int getOrder() {return 10150; } public Mono 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))) {//url不为null且协议为lb,或者url以lb开头 ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url); if (log.isTraceEnabled()) {log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url); } return this.choose(exchange).doOnNext((response) -> {//获取ServiceInstance实例,进行一些处理 if (!response.hasServer()) {//如果没有serviceInstance,直接抛出异常 throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost()); } else {//如果有serviceInstance,进行相关处理URI uri = exchange.getRequest().getURI(); String overrideScheme = null; if (schemePrefix != null) {overrideScheme = url.getScheme(); } DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance((ServiceInstance)response.getServer(), overrideScheme); URI requestUrl = LoadBalancerUriTools.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); //如果获取不到serviceInstance,直接进行后续过滤}} private Mono choose(ServerWebExchange exchange) {URI uri = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); ReactorLoadBalancer loadBalancer = (ReactorLoadBalancer)this.clientFactory.getInstance(uri.getHost(), ReactorLoadBalancer.class, new Class[]{ServiceInstance.class}); if (loadBalancer == null) {throw new NotFoundException("No loadbalancer available for " + uri.getHost()); } else {return loadBalancer.choose(this.createRequest()); }}//选择服务实例 private Request createRequest() {return ReactiveLoadBalancer.REQUEST; }}

ReactorLoadBalancer:负载均衡接口
public interface ReactorLoadBalancer extends ReactiveLoadBalancer {Mono> choose(Request request); default Mono> choose() {return this.choose(REQUEST); }} *********************** public interface ReactorServiceInstanceLoadBalancer extends ReactorLoadBalancer {}

RoundRobinLoadbalancer:负载均衡使用轮询
public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {private static final Log log = LogFactory.getLog(RoundRobinLoadBalancer.class); private final AtomicInteger position; private ObjectProvider serviceInstanceListSupplierProvider; private final String serviceId; ************构造方法 public RoundRobinLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider, String serviceId) {public RoundRobinLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider, String serviceId, int seedPosition) { ************普通方法 public Mono choose(Request request) {if (this.serviceInstanceListSupplierProvider != null) {ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new); return ((Flux)supplier.get()).next().map(this::getInstanceResponse); } else {ServiceInstanceSupplier supplier = (ServiceInstanceSupplier)this.serviceInstanceSupplier.getIfAvailable(NoopServiceInstanceSupplier::new); return ((Flux)supplier.get()).collectList().map(this::getInstanceResponse); }} private Response getInstanceResponse(List instances) {if (instances.isEmpty()) {log.warn("No servers available for service: " + this.serviceId); return new EmptyResponse(); } else {int pos = Math.abs(this.position.incrementAndGet()); ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size()); return new DefaultResponse(instance); }}//使用轮询获取实例}

示例:
参数id为偶数时,输出hello new version
网关
配置文件
spring:application:name: hello-gatewaycloud:consul:host: 172.18.0.20port: 8500loadbalancer:ribbon:enabled: falsegateway:routes:- id: myRouteuri: lb://hello-servicepredicates:- Path=/hello

自定义过滤器
@Componentpublic class CustomLoadBalancerClientFilter implements GlobalFilter, Ordered {private static final Log log = LogFactory.getLog(org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.class); @Resourceprivate final LoadBalancerClientFactory clientFactory; @Resourceprivate LoadBalancerProperties properties; public CustomLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) {this.clientFactory = clientFactory; this.properties = properties; } public int getOrder() {return 10149; } public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {URI url = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); String schemePrefix = 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 {URI uri = exchange.getRequest().getURI(); String overrideScheme = null; if (schemePrefix != null) {overrideScheme = url.getScheme(); } int id=Integer.parseInt(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("id"))); if (id%2==0){while (!"new".equals(response.getServer().getMetadata().get("version"))){try {response=this.choose(exchange).toFuture().get(); }catch (Exception e){System.out.println(e.getMessage()); }}} DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(response.getServer(), overrideScheme); System.out.println(exchange.getRequest().getQueryParams().getFirst("id")+"对应server的version为:"+serviceInstance.getMetadata().get("version")); URI requestUrl = LoadBalancerUriTools.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); }} private Mono choose(ServerWebExchange exchange) {URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); assert uri != null; ReactorLoadBalancer loadBalancer = this.clientFactory.getInstance(uri.getHost(), ReactorLoadBalancer.class, new Class[]{ServiceInstance.class}); if (loadBalancer == null) {throw new NotFoundException("No loadbalancer available for " + uri.getHost()); } else {return loadBalancer.choose(this.createRequest()); }} private Request createRequest() {return ReactiveLoadBalancer.REQUEST; }}

同名应用hello-service1
配置文件
spring:application:name: hello-servicecloud:consul:host: 172.18.0.20port: 8500discovery:instance-id: ${spring.application.name}-${random.int}tags: version=old

controller 层
@RestControllerpublic class HelloController { @RequestMapping("/hello")public String hello(){return "hello old version"; }}

同名应用hello-service2
配置文件
spring:application:name: hello-servicecloud:consul:host: 172.18.0.20port: 8500discovery:instance-id: ${spring.application.name}-${random.int}tags: version=new

controller 层
@RestControllerpublic class HelloController { @RequestMapping("/hello")public String hello(){return "hello new version"; }}

测试输出
consul注册的应用
springcloud|springcloud gateway如何实现路由和负载均衡
文章图片

参数测试
springcloud|springcloud gateway如何实现路由和负载均衡
文章图片

当id为偶数时,输出为hello new version
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

    推荐阅读