简介:
gateway主要是做路由 负载,过滤 主要是替代zuul 1.x 性能比zuul好 zuul是基于
Servlet ,gateway是基于spring-webflux 用的netty+reactor
yml文件
实现路由 负载 的配置 亲自测试
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 必填否则找不到后端服务也可以在服务加上统一路径 - 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 #熔断时间上面是用了两天时间根据官网上的demo和说明自己测的可以使用 上面 stripPrefix 用的是 PrefixPath 过滤器 其他过滤器使用可以看官网
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且协议为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 < 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 ); } } //使用轮询获取实例 }示例:
参数id为偶数时,输出hello new version
网关
配置文件
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 = oldcontroller 层
@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 = newcontroller 层
@RestController public class HelloController { @RequestMapping ( "/hello" ) public String hello (){ return "hello new version" ; } }测试输出
consul注册的应用
参数测试
当id为偶数时,输出为hello new version
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。
原文链接:https://blog.csdn.net/cuixinzhou/article/details/93379130
查看更多关于springcloud gateway如何实现路由和负载均衡的详细内容...