springcloud gateway如何實現(xiàn)路由和負載均衡
簡介:
gateway主要是做路由 負載,過濾 主要是替代zuul 1.x 性能比zuul好 zuul是基于
Servlet ,gateway是基于spring-webflux 用的netty+reactor
yml文件
實現(xiàn)路由 負載 的配置 親自測試
spring: application: name: xgyx_gateway cloud: discovery: locator: enabled: true gateway: routes: - id: a #隨便定義不重復就好 uri: lb://xgyx-welfareservice-x #服務名稱 predicates: - Path=/m/** #前端訪問需加入例如 http:ip:port/m filters: - StripPrefix=1 #訪問后端服務過濾掉m 必填否則找不到后端服務也可以在服務加上統(tǒng)一路徑 - name: Hystrix #熔斷 args: name: default fallbackUri: forward:/defaultfallback #熔斷后訪問路徑 - id: b uri: lb://xgyx-welfareservice predicates: - Path=/welfare/** filters: - StripPrefix=1 - name: Hystrix args: name: default fallbackUri: forward:/fallback #熔斷時間 hystrix: command: default: execution: isolation: strategy: SEMAPHORE thread: timeoutInMilliseconds: 300000 #熔斷時間
上面是用了兩天時間根據(jù)官網(wǎng)上的demo和說明自己測的可以使用 上面 stripPrefix 用的是 PrefixPath 過濾器 其他過濾器使用可以看官網(wǎng)
springcloud gateway 自定義負載均衡
相關類及接口
LoadbalancerClientFilter
:使用ribbon負載均衡,默認使用該類(已不推薦使用)
/** @deprecated */ @Deprecated public 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<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("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
"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<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))) { //url不為null且協(xié)議為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,直接進行后續(xù)過濾 } } 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(), 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<T> extends ReactiveLoadBalancer<T> { Mono<Response<T>> choose(Request request); default Mono<Response<T>> choose() { return this.choose(REQUEST); } } *********************** public interface ReactorServiceInstanceLoadBalancer extends ReactorLoadBalancer<ServiceInstance> { }
RoundRobinLoadbalancer
:負載均衡使用輪詢
public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer { private static final Log log = LogFactory.getLog(RoundRobinLoadBalancer.class); private final AtomicInteger position; private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider; private final String serviceId; ************ 構造方法 public RoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) { public RoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) { ************ 普通方法 public Mono<Response<ServiceInstance>> 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<ServiceInstance> getInstanceResponse(List<ServiceInstance> 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); } }//使用輪詢獲取實例 }
示例:
參數(shù)id為偶數(shù)時,輸出hello new version
網(wǎng)關
配置文件
spring: application: name: hello-gateway cloud: consul: host: 172.18.0.20 port: 8500 loadbalancer: ribbon: enabled: false gateway: routes: - id: myRoute uri: lb://hello-service predicates: - Path=/hello
自定義過濾器
@Component public class CustomLoadBalancerClientFilter implements GlobalFilter, Ordered { private static final Log log = LogFactory.getLog(org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.class); @Resource private final LoadBalancerClientFactory clientFactory; @Resource private LoadBalancerProperties properties; public CustomLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) { this.clientFactory = clientFactory; this.properties = properties; } public int getOrder() { return 10149; } public Mono<Void> 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<Response<ServiceInstance>> choose(ServerWebExchange exchange) { URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); assert uri != null; ReactorLoadBalancer<ServiceInstance> 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-service cloud: consul: host: 172.18.0.20 port: 8500 discovery: instance-id: ${spring.application.name}-${random.int} tags: version=old
controller 層
@RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "hello old version"; } }
同名應用hello-service2
配置文件
spring: application: name: hello-service cloud: consul: host: 172.18.0.20 port: 8500 discovery: instance-id: ${spring.application.name}-${random.int} tags: version=new
controller 層
@RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "hello new version"; } }
測試輸出
consul注冊的應用
參數(shù)測試
當id為偶數(shù)時,輸出為hello new version
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
關于SpringBoot的@ConfigurationProperties注解和松散綁定、數(shù)據(jù)校驗
這篇文章主要介紹了關于SpringBoot的@ConfigurationProperties注解和松散綁定、數(shù)據(jù)校驗,@ConfigurationProperties主要作用就是將prefix屬性指定的前綴配置項的值綁定到這個JavaBean上?,通過指定的前綴,來綁定配置文件中的配置,需要的朋友可以參考下2023-05-05Java實現(xiàn)XML格式與JSON格式互相轉換的方法
這篇文章主要介紹了Java實現(xiàn)XML格式與JSON格式互相轉換的方法,方法通過實例代碼給大家介紹的非常詳細,選擇使用哪種格式通常取決于項目的需求和上下文,所以格式轉換就成了我們必備的技能,具體實現(xiàn)代碼跟隨小編一起看看吧2023-10-10Java幸運28系統(tǒng)搭建數(shù)組的使用實例詳解
在本篇文章里小編給大家整理了關于Java幸運28系統(tǒng)搭建數(shù)組的使用實例內(nèi)容,有需要的朋友們可以參考學習下。2019-09-09springboot中的Application.properties常用配置
這篇文章主要介紹了springboot中的Application.properties常用配置,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05Java數(shù)據(jù)結構之LinkedList從鏈表到實現(xiàn)
LinkedList是Java中常用的數(shù)據(jù)結構之一,實現(xiàn)了鏈表的特性,支持快速添加、刪除元素,可以用于實現(xiàn)隊列、棧、雙向隊列等數(shù)據(jù)結構。LinkedList的內(nèi)部實現(xiàn)采用了雙向鏈表,其中每個節(jié)點都包含前驅節(jié)點和后繼節(jié)點的引用,可以直接訪問鏈表的頭尾元素2023-04-04Java獲取Jar、War包路徑并生成可編輯修改的本地配置文件
這篇文章主要給大家介紹了關于Java如何獲取Jar、War包路徑并生成可編輯修改的本地配置文件,文中通過代碼介紹的非常詳細,對大家學習或者使用Java具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01