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

简介:

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=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注册的应用

参数测试

当id为偶数时,输出为hello new version

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Cloud负载均衡及远程调用实现详解

    负载均衡 使用微服务后,为了能够承担高并发的压力,同一个服务可能会启动多个实例.这时候消费者就需要负载均衡,把请求分散到各个实例.负载均衡主要有两种设计: 服务端负载均衡客户端负载均衡 对于传统的分布式服务来说,大多使用服务端负载均衡.一般会使用Nginx或者ELB等工具作为负载均衡器,如下图: 传统负载均衡 而在Spring Cloud中,使用的是「客户端负载均衡」的方式,使用「Ribbon」组件来实现客户端的负载均衡.只要引入了微服务注册中心依赖,就会自动引入Ribbon依赖.客户端负载均衡

  • Java使用Gateway自定义负载均衡过滤器

    背景 最近项目中需要上传视频文件,由于视频文件可能会比较大,但是我们应用服务器tomcat设置单次只支持的100M,因此决定开发一个分片上传接口. 把大文件分成若干个小文件上传.所有文件上传完成后通过唯一标示进行合并文件. 我们的开发人员很快完成了开发,并在单元测试中表现无误.上传代码到测试环境,喔嚯!!!出错了. 经过一段时间的辛苦排查终于发现问题,测试环境多实例,分片上传的接口会被路由到不同的实例,导致上传后的分片文件在不同的机器,那么也就无法被合并. 知道了原因就好解决,经过一系列的过程最

  • spring-cloud-gateway动态路由的实现方法

    概述 线上项目发布一般有以下几种方案: 机发布 蓝绿部署 滚动部署 灰度发布 停机发布 这种发布一般在夜里或者进行大版本升级的时候发布,因为需要停机,所以现在大家都在研究 Devops 方案. 蓝绿部署 需要准备两个相同的环境.一个环境新版本,一个环境旧版本,通过负载均衡进行切换与回滚,目的是为了减少服务停止时间. 滚动部署 就是在升级过程中,并不一下子启动所有新版本,是先启动一台新版本,再停止一台老版本,然后再启动一台新版本,再停止一台老版本,直到升级完成.基于 k8s 的升级方案默认就是滚动

  • 详解SpringCloud的负载均衡

    目录 一.什么是负载均衡 二.负载均衡的简单分类 三.为什么需要做负载均衡 四.springCloud如何开启负载均衡 五.IRule 1.RandomRule:表示随机策略,它将从服务清单中随机选择一个服务: 2.ClientConfigEnabledRoundRobinRule:ClientConfigEnabledRoundRobinRule并没有实现什么特殊的处理逻辑,但是他的子类可以实现一些高级策略, 当一些本身的策略无法实现某些需求的时候,它也可以做为父类帮助实现某些策略,一般情况下

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

    简介: 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:

  • GateWay动态路由与负载均衡详细介绍

    目录 概述 项目实例 1.gateway-server模块 1.1.pom.xml文件 1.2.application.yml文件 1.3.主函数类 2.login-service模块 2.1.pom.xml文件 2.2.application.yml文件 2.3.LoginController文件 2.4.主函数类 3.功能测试 概述 从之前的配置里面我们可以看到我们的 URL 都是写死的,这不符合我们微服务的要求,我们微服务是只要知道服务的名字,根据名字去找,而直接写死就没有负载均衡的效果了

  • 在eigrp做不等值路由的负载均衡

    在eigrp中如何做到不等值路由的负载均衡 EIGRP Load Balancing 每个路由协议都支持等值路径的负载均衡.除此之外,IGRP和EIGRP也支持不等值路径的负载均衡,使用variance命令. Variance命令向路由器通告一个n值,n值使用variance命令指定.n值为1-128之间,默认为1. 网络拓扑 Variance 在上图 中,router E有三个路径到网络X • E-B-A with a metric of 30 • E-C-A with a metric of

  • Java之Springcloud Gateway内置路由案例讲解

    Spring Cloud Gateway路由匹配是Spring WebFlux基础功能的一部分,在Spring Cloud Gateway中内置了很多路由断言工厂类.不同的断言工厂类针对HTTP请求的不同属性.多个断言工厂类可以使用逻辑"and"进行组合使用. 4.1 After Route Predicate Factory        这个Predicate工厂的实现类是AfterRoutePredicateFactory,使用一个时间参数,如果当前请求的时间在配置的赶时间之后,

  • SpringCloud笔记(Hoxton)Netflix之Ribbon负载均衡示例代码

    目录 Ribbon使用 负载均衡 代码示例 注册中心 Provider 接口实现 Consumer 添加依赖 测试 Ribbon使用 Ribbon是管理HTTP和TCP服务客户端的负载均衡器,Ribbon具有一系列带有名称的客户端(Named Client),也就是带有名称的Ribbon客户端(Ribbon Client). 每个客户端由可配置的组件构成,负责一类服务的调用请求.SpringCloud通RibbonClientConfiguration 为每个Ribbon客户端创建Applica

  • 解决SpringCloud Gateway配置自定义路由404的坑

    目录 问题背景 问题现象 解决过程 1 检查网关配置 2 跟源码,查找可能的原因 3 异常原因分析 解决方法 心得 问题背景 将原有项目中的websocket模块迁移到基于SpringCloud Alibaba的微服务系统中,其中网关部分使用的是gateway. 问题现象 迁移后,我们在使用客户端连接websocket时报错: io.netty.handler.codec.http.websocketx.WebSocketHandshakeException: Invalid subprotoc

  • SpringCloud如何实现Zuul集群(负载均衡)

    目录 前言: 一.使用 Nginx+Zuul 实现网关集群 1.创建Eurek注册中心.会员服务.订单服务 (略) 2. 创建Zuul服务 3. 下载Nginx服务器 二. 测试 三.补充 Nginx和网关的区别在什么地方? Nginx也可以实现网关,为什么不用Nginx实现网关呢? 关于Nginx负载均衡故障转移: 前言: 在微服务架构中,有一个组件可以说是必不可少的,那就是微服务网关,微服务网关处理了负载均衡,缓存,路由,访问控制,服务代理,监控,日志等.API网关在微服务架构中正是以微服务

  • SpringCloud Gateway 利用 Mysql 实现动态路由的方法

    需求描述 标准网关动态路由功能是重要的一环,将路由.断言以及过滤器信息,持久化到 Mysql 中,通过配置后台页面实现路由.断言.以及过滤器等配置的增删改查. Spring Cloud Gateway 路由及黑白名单实现背景 Spring Cloud 路由API Spring Cloud Gateway 通过定义 RouteDefinitionRepository 来实现动态路由. //保存路由缓存 public interface RouteDefinitionWriter { Mono<Vo

  • SpringCloud gateway+zookeeper实现网关路由的详细搭建

    目录 准备工作 网关搭建 准备工作 需要两个项目去实现路由demo1为springboot项目用于接入网关,测试网关连通性gateway为网关路由项目 网关搭建 1.电脑安装好zookeeper,并且正常运行服务Zookeeper官网 2.创建一个spring cloud gateway项目,并引入zookeeper功能 pom文件配置 <dependencies> <dependency> <groupId>org.springframework.cloud</

  • SpringCloud GateWay网关示例代码详解

    目录 一.网关基本概念 1.API网关介绍 2.Spring Cloud Gateway 3.Spring Cloud Gateway核心概念 一.网关基本概念 1.API网关介绍 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:(1)客户端会多次请求不同的微服务,增加了客户端的复杂性.(2)存在跨域请求,在一定场景下处理相对复杂.(3)认证复杂,每个服务都

随机推荐