当前位置: 代码网 > it编程>编程语言>Java > Spring Cloud Gateway负载均衡

Spring Cloud Gateway负载均衡

2024年08月02日 Java 我要评论
该自动配置类在GatewayLoadBalancerClientAutoConfiguration自动配置类之前执行,也就是前面的基于Ribbon的自动装配类,由此可见,gateway是优先使用ReactiveLoadBalancer的,只有没有开启ReactiveLoadBalancer时才使用使用Ribbon。该自动配置类需要在RibbonAutoConfiguration自动配置类之后执行,该类是spring-cloud-netflix-ribbon的自动配置类,因此需要引入下面的jar包依赖。

一、spring cloud gateway
我们都知道spring cloud gateway是一个基于spring boot、spring webflux、project reactor构建的高性能网关,旨在提供简单、高效的api路由。spring cloud gateway基于netty运行,因此在传统servlet容器中或者打成war包是不能正常运行的。

二、spring cloud gateway两种负载均衡器
2.1 官网说明两种负载均衡器

gateway有两种客户端负载均衡器,loadbalancerclientfilter和reactiveloadbalancerclientfilter。loadbalancerclientfilter使用一个ribbon的阻塞式loadbalancerclient,gateway建议使用reactiveloadbalancerclientfilter。可以通过设置spring.cloud.loadbalancer.ribbon.enabled=false,切换到reactiveloadbalancerclientfilter。无论使用ribbon还是loadbalancer,在route中配置的lb是一样的

一、spring cloud gateway
我们都知道spring cloud gateway是一个基于spring boot、spring webflux、project reactor构建的高性能网关,旨在提供简单、高效的api路由。spring cloud gateway基于netty运行,因此在传统servlet容器中或者打成war包是不能正常运行的。

二、spring cloud gateway两种负载均衡器
2.1 官网说明两种负载均衡器

gateway有两种客户端负载均衡器,loadbalancerclientfilter和reactiveloadbalancerclientfilter。loadbalancerclientfilter使用一个ribbon的阻塞式loadbalancerclient,gateway建议使用reactiveloadbalancerclientfilter。可以通过设置spring.cloud.loadbalancer.ribbon.enabled=false,切换到reactiveloadbalancerclientfilter。无论使用ribbon还是loadbalancer,在route中配置的lb是一样的

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - path=/user/**
        - id: message-service
          uri: lb://message-service
          predicates:
            - path=/message/**
    nacos:
      discovery:
        server-addr: localhost:8848

如果uri以lb开头,比如如上配置中的lb://user-service,spring cloud gateway会用reactiveloadbalancerclientfilter 解析服务名为user-service的实例对应的实际host和端口,并做集群负载均衡。

2.2 跳坑
官网说用lb://lakerservice形式即可,但是配置完成后,并未生效。这个官网没有详细说明,查资料也没有,最后发现必须加入依赖:

<dependency>
    <groupid>org.springframework.cloud</groupid>
    <artifactid>spring-cloud-starter-loadbalancer</artifactid>
  </dependency>

2.3 简易流程说明

client ----> gateway ----> ribbion负载均衡 取一个服务a ---->转发到服务a

2.4 ribbon说明
spring cloud ribbon 在高版本移除了

三、用routerecordglobalfilter记录路由后的实际代理地址

@slf4j
@component
public class routerecordglobalfilter implements globalfilter, ordered {

    @override
    public mono<void> filter(serverwebexchange exchange, gatewayfilterchain chain) {
        // routetorequesturlfilter会把实际路由的url通过该属性保存
        uri proxyrequesturi = exchange.getattribute(serverwebexchangeutils.gateway_request_url_attr);
        long start = system.currenttimemillis();

        return chain.filter(exchange).then(mono.fromrunnable(() -> {
            long end = system.currenttimemillis();
            log.info("实际调用地址为:{},调用耗时为:{}ms", proxyrequesturi, (end - start));
        }));
    }

    @override
    public int getorder() {
        // 优先级设为最低,先让routetorequesturlfilter先调用
        return ordered.lowest_precedence;
    }
}

routerecordglobalfilter 这个全局过滤器我们主要用来记录路由后的实际代理地址,以及调用耗时。我们看下routetorequesturlfilter的描述会发现实际路由地址会通过serverwebexchange中名为serverwebexchangeutils.gateway_request_url_attr的属性保存。

四、源码
4.1 基于ribbon的loadbalancerclientfilter

gateway中的自动配置类gatewayloadbalancerclientautoconfiguration。

package org.springframework.cloud.gateway.config;

import org.springframework.boot.autoconfigure.autoconfigureafter;
import org.springframework.boot.autoconfigure.condition.conditionalonbean;
import org.springframework.boot.autoconfigure.condition.conditionalonclass;
import org.springframework.boot.autoconfigure.condition.conditionalonmissingbean;
import org.springframework.boot.context.properties.enableconfigurationproperties;
import org.springframework.cloud.client.loadbalancer.loadbalancerclient;
import org.springframework.cloud.gateway.config.conditional.conditionalonenabledglobalfilter;
import org.springframework.cloud.gateway.filter.loadbalancerclientfilter;
import org.springframework.cloud.gateway.filter.reactiveloadbalancerclientfilter;
import org.springframework.cloud.netflix.ribbon.ribbonautoconfiguration;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.web.reactive.dispatcherhandler;

@configuration(
    proxybeanmethods = false
)
@conditionalonclass({loadbalancerclient.class, ribbonautoconfiguration.class, dispatcherhandler.class})
@autoconfigureafter({ribbonautoconfiguration.class})
@enableconfigurationproperties({loadbalancerproperties.class})
public class gatewayloadbalancerclientautoconfiguration {
    public gatewayloadbalancerclientautoconfiguration() {
    }

    @bean
    @conditionalonbean({loadbalancerclient.class})
    @conditionalonmissingbean({loadbalancerclientfilter.class, reactiveloadbalancerclientfilter.class})
    @conditionalonenabledglobalfilter
    public loadbalancerclientfilter loadbalancerclientfilter(loadbalancerclient client, loadbalancerproperties properties) {
        return new loadbalancerclientfilter(client, properties);
    }
}

该自动配置类需要在ribbonautoconfiguration自动配置类之后执行,该类是spring-cloud-netflix-ribbon的自动配置类,因此需要引入下面的jar包依赖

<dependency>
     <groupid>org.springframework.cloud</groupid>
     <artifactid>spring-cloud-starter-netflix-ribbon</artifactid>
</dependency>

使用默认的ribbon,则ribbon的配置如下

#=======================ribbon配置(使用netflix的ribbon负载均衡)=======================
#关闭nacos集成ribbon,否则ribbon客户端会从nacos注册中心获取服务列表
ribbon.nacos.enabled=false
#配置serviceid为providerservice的服务list
providerservice.ribbon.listofservers=http://192.168.10.1:8080,http://192.168.10.2:8080
#配置serviceid为providerservice的服务负载均衡
#providerservice.ribbon.nfloadbalancerruleclassname=com.netflix.loadbalancer.roundrobinrule
providerservice.ribbon.nfloadbalancerruleclassname=com.netflix.loadbalancer.availabilityfilteringrule

4.2 spring cloud loadbalancer

spring cloud load balancer并不是一个独立的项目,而是spring-cloud-commons其中的一个模块,因此很多配置和类可以在spring-cloud-common中找到。gateway中的自动配置类gatewayreactiveloadbalancerclientautoconfiguration

spring cloud提供了自己的客户端负载均衡器抽象和实现。对于负载平衡机制,reactiveloadbalancer已添加了接口,并为其提供了基于round-robin和random的实现。为了获得实例以从反应式中进行选择serviceinstancelistsupplier 。当前,我们支持基于服务发现的实现,serviceinstancelistsupplier 该实现使用类路径中可用的发现客户端从服务发现中检索可用实例。

@configuration(
    proxybeanmethods = false
)
@conditionalonclass({loadbalancerclient.class, reactiveloadbalancer.class, loadbalancerautoconfiguration.class, dispatcherhandler.class})
@autoconfigurebefore({gatewayloadbalancerclientautoconfiguration.class})
@autoconfigureafter({loadbalancerautoconfiguration.class})
@enableconfigurationproperties({loadbalancerproperties.class})
public class gatewayreactiveloadbalancerclientautoconfiguration {
    public gatewayreactiveloadbalancerclientautoconfiguration() {
    }

    @bean
    @conditionalonbean({loadbalancerclientfactory.class})
    @conditionalonmissingbean({reactiveloadbalancerclientfilter.class})
    @conditional({gatewayreactiveloadbalancerclientautoconfiguration.onnoribbondefaultcondition.class})
    @conditionalonenabledglobalfilter
    public reactiveloadbalancerclientfilter gatewayloadbalancerclientfilter(loadbalancerclientfactory clientfactory, loadbalancerproperties properties) {
        return new reactiveloadbalancerclientfilter(clientfactory, properties);
    }

    private static final class onnoribbondefaultcondition extends anynestedcondition {
        private onnoribbondefaultcondition() {
            super(configurationphase.register_bean);
        }

        @conditionalonmissingclass({"org.springframework.cloud.netflix.ribbon.ribbonloadbalancerclient"})
        static class ribbonloadbalancernotpresent {
            ribbonloadbalancernotpresent() {
            }
        }

        @conditionalonproperty(
            value = {"spring.cloud.loadbalancer.ribbon.enabled"},
            havingvalue = "false"
        )
        static class ribbonnotenabled {
            ribbonnotenabled() {
            }
        }
    }
}

该自动配置类在loadbalancerautoconfiguration自动配置类之后执行,该配置类在spring-cloud-commons中。
该自动配置类在gatewayloadbalancerclientautoconfiguration自动配置类之前执行,也就是前面的基于ribbon的自动装配类,由此可见,gateway是优先使用reactiveloadbalancer的,只有没有开启reactiveloadbalancer时才使用使用ribbon。

引入依赖:

<!-- 引入spring-cloud-loadbalancer -->
<dependency>
    <groupid>org.springframework.cloud</groupid>
    <artifactid>spring-cloud-starter-loadbalancer</artifactid>
</dependency>

配置如下:
从配置文件中读取服务,而不是从服务注册中心自动发现服务
注意:如果在项目的类路径下存在spring cloud ribbon相关的类,需要通过配置关闭ribbon功能,因为spring cloud默认优先使用ribbon,因此spring.cloud.loadbalancer.ribbon.enabled禁用调ribbon,这也是上面刚提到过的。

#=======================springcloudloadbalancer配置服务列表=======================
#使用reactiveloadbalancerclient时通过该参数禁用调ribbon
spring.cloud.loadbalancer.ribbon.enabled=false
#配置providerservice的instances,不是从注册中心自动发现服务实例
spring.cloud.discovery.client.simple.instances.providerservice[0].uri=http://192.168.10.1:8080
spring.cloud.discovery.client.simple.instances.providerservice[1].uri=http://192.168.10.2:8080
#指定健康检查请求路径,默认健康检查路径是/actuator/health
spring.cloud.loadbalancer.health-check.path.providerservice=/custom/customhealthcheckpath
#运行状况检查计划程序的初始延迟值
spring.cloud.loadbalancer.health-check.initial-delay=0
#重新运行运行状况检查计划程序的时间间隔
spring.cloud.loadbalancer.health-check.interval=5s
#启用预定义的负载平衡器配置
spring.cloud.loadbalancer.configurations=health-check

4.3 simplediscoveryclient

simplediscoveryclient可以结合注册中心使用,也可以静态配置。如果在类路径中没有支持从注册中心发现服务的discoveryclient实例,则将使用simplediscoveryclient实例,该实例使用simplediscoveryproperties来获取有关服务和实例的信息。参考上面的配置文件中的配置。

public class simplediscoveryclient implements discoveryclient {
    private simplediscoveryproperties simplediscoveryproperties;

    public simplediscoveryclient(simplediscoveryproperties simplediscoveryproperties) {
        this.simplediscoveryproperties = simplediscoveryproperties;
    }

    public string description() {
        return "simple discovery client";
    }

    public list<serviceinstance> getinstances(string serviceid) {
        list<serviceinstance> serviceinstances = new arraylist();
        list<defaultserviceinstance> serviceinstanceforservice = (list)this.simplediscoveryproperties.getinstances().get(serviceid);
        if (serviceinstanceforservice != null) {
            serviceinstances.addall(serviceinstanceforservice);
        }

        return serviceinstances;
    }

    public list<string> getservices() {
        return new arraylist(this.simplediscoveryproperties.getinstances().keyset());
    }

    public int getorder() {
        return this.simplediscoveryproperties.getorder();
    }
}

simplediscoveryproperties 服务实例的属性配置

@configurationproperties(
    prefix = "spring.cloud.discovery.client.simple"
)
public class simplediscoveryproperties {
    //在配置文件中配置的实例属性
    private map<string, list<defaultserviceinstance>> instances = new hashmap();
    private defaultserviceinstance local = new defaultserviceinstance((string)null, (string)null, (string)null, 0, false);
    private int order = 0;
}

defaultserviceinstance默认的服务实例定义

public class defaultserviceinstance implements serviceinstance {
    private string instanceid;
    private string serviceid;
    private string host;
    private int port;
    private boolean secure;
    private map<string, string> metadata;
    private uri uri;
    ...省略...
}

4.3.1 在负载均衡算法之间切换
reactiveloadbalancer默认情况下使用的实现是roundrobinloadbalancer。要针对选定的服务或所有服务切换到不同的实现,可以使用自定义loadbalancer配置机制。例如,可以通过@loadbalancerclient注释传递以下配置以切换为使用randomloadbalancer:

public class customloadbalancerconfiguration {

    @bean
    reactorloadbalancer<serviceinstance> randomloadbalancer(environment environment,
            loadbalancerclientfactory loadbalancerclientfactory) {
        string name = environment.getproperty(loadbalancerclientfactory.property_name);
        return new randomloadbalancer(loadbalancerclientfactory
                .getlazyprovider(name, serviceinstancelistsupplier.class),
                name);
    }
}

4.3.2 实例健康检查

可以为loadbalancer启用计划健康检查。为此提供了healthcheckserviceinstancelistsupplier。它定期验证委托serviceinstancelistsupplier提供的实例是否仍然存在,并且只返回健康的实例,除非没有实例—然后返回所有检索到的实例。

在使用simplediscoveryclient时,这种机制特别有用。对于由实际服务注册中心支持的客户端,不需要使用它,因为我们在查询外部servicediscovery之后已经获得了健康的实例。

对于每个服务只有少量实例的设置,也建议使用此供应商,以避免重试调用失败的实例。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com