跨境派

跨境派

跨境派,专注跨境行业新闻资讯、跨境电商知识分享!

当前位置:首页 > 卖家故事 > Spring Cloud Gateway负载均衡

Spring Cloud Gateway负载均衡

时间:2024-04-25 18:20:32 来源:网络cs 作者:纳雷武 栏目:卖家故事 阅读:

标签: 均衡  负载 
阅读本书更多章节>>>>

一、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@Componentpublic 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的服务ListproviderService.ribbon.listOfServers=http://192.168.10.1:8080,http://192.168.10.2:8080#配置serviceId为providerService的服务负载均衡#providerService.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRuleproviderService.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时通过该参数禁用调ribbonspring.cloud.loadbalancer.ribbon.enabled=false#配置providerService的instances,不是从注册中心自动发现服务实例spring.cloud.discovery.client.simple.instances.providerService[0].uri=http://192.168.10.1:8080spring.cloud.discovery.client.simple.instances.providerService[1].uri=http://192.168.10.2:8080#指定健康检查请求路径,默认健康检查路径是/actuator/healthspring.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之后已经获得了健康的实例。

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

阅读本书更多章节>>>>

本文链接:https://www.kjpai.cn/gushi/2024-04-25/162274.html,文章来源:网络cs,作者:纳雷武,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!

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

文章评论