SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer

文章目录

  • POM依赖
  • 环境准备
  • 配置
    • 配置文件
    • 配置类
  • 案例展示

POM依赖

 
        org.springframework.boot
        spring-boot-starter-parent
        2.7.10
        
    
      
        8
        8
        3.1.6
        2021.0.4.0
        UTF-8
    
     
       
            org.springframework.boot
            spring-boot-starter
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
            ${springcloudalibaba.version}
            
                
                    
                    com.alibaba.nacos
                    nacos-client
                
            
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
            ${springcloudalibaba.version}
            
                
                    
                    com.alibaba.nacos
                    nacos-client
                
            
        
        
            org.springframework.cloud
            spring-cloud-starter-bootstrap
            ${springcloud.version}
        
        
            com.alibaba.nacos
            nacos-client
            2.1.1
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
            ${springcloud.version}
        
        
            org.springframework.cloud
            spring-cloud-starter-loadbalancer
            ${springcloud.version}
        
         
                org.springframework.cloud
                spring-cloud-starter-netflix-hystrix
                2.2.9.RELEASE
            
         
            org.springframework.cloud
            spring-cloud-starter-gateway
            3.1.5
        
         
            org.springframework.boot
            spring-boot-starter-web
            
                
                    org.springframework
                    spring-webmvc
                
                
                    spring-boot-starter-tomcat
                    org.springframework.boot
                
            
        
     

环境准备

nacos搭建Nacos standalone单机搭建部署

配置

配置文件

application.yml

server:
  port: 8082
spring:
  profiles:
    active: dev
  main:
    web-application-type: reactive
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: Mes
          uri: lb://Mes
          predicates:
            - Path=/mes/**
        - id: Test
          uri: lb://Test
          predicates:
            - Path=/test/**

bootstrap.properties

spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.cloud.nacos.discovery.group=dev
spring.cloud.nacos.discovery.namespace=1e6d33e2-5f43-45ec-8c1b-9c883c2c71d9
spring.cloud.nacos.config.group=dev
spring.cloud.nacos.config.prefix=gateway
spring.cloud.nacos.config.server-addr=localhost:8848
spring.cloud.nacos.config.file-extension=properties
spring.cloud.nacos.config.namespace=1e6d33e2-5f43-45ec-8c1b-9c883c2c71d9
spring.profiles.active=dev
spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowedOriginPatterns=*
spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowedHeaders=*
spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowedMethods=*
spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowCredentials=true

bootstrap-dev.properties

# 用于配置中心测试
message.name=lisi

配置类

自定义Gateway负载均衡器,采用nacos所配置的权重进行负载均衡调用,随机权重算法

import com.alibaba.cloud.nacos.balancer.NacosBalancer;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.*;
import reactor.core.publisher.Mono;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class CustomRoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    private static final Log log = LogFactory.getLog(RoundRobinLoadBalancer.class);
    final AtomicInteger position;
    final String serviceId;
    ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    /**
     * @param serviceInstanceListSupplierProvider a provider of
     *                                            {@link ServiceInstanceListSupplier} that will be used to get available instances
     * @param serviceId                           id of the service for which to choose an instance
     */
    public CustomRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this(serviceInstanceListSupplierProvider, serviceId, new Random().nextInt(1000));
    }

    /**
     * @param serviceInstanceListSupplierProvider a provider of
     *                                            {@link ServiceInstanceListSupplier} that will be used to get available instances
     * @param serviceId                           id of the service for which to choose an instance
     * @param seedPosition                        Round Robin element position marker
     */
    public CustomRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.position = new AtomicInteger(seedPosition);
    }

    @SuppressWarnings("rawtypes")
    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
        Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }
        return serviceInstanceResponse;
    }

    /**
     * 按nacos权重
     *
     * @return
     */

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> serviceInstances) {
        Map<String, List<ServiceInstance>> collect = serviceInstances.stream().collect(Collectors.groupingBy(g -> {
                        //nacos在2.0版本之后移除了对实例id查询
//            return g.getMetadata().get("nacos.instanceId");
            return g.getHost() +":"+ g.getPort();
        }));
        if (serviceInstances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }
        List<Instance> instances = serviceInstances.stream().map(i -> {
            Instance instance = new Instance();
            instance.setInstanceId(i.getInstanceId());
            Map<String, String> metadata = i.getMetadata();
            instance.setInstanceId(metadata.get("nacos.instanceId"));
            instance.setWeight(new BigDecimal(metadata.get("nacos.weight")).doubleValue());
            instance.setClusterName(metadata.get("nacos.cluster"));
            instance.setEphemeral(Boolean.parseBoolean(metadata.get("nacos.ephemeral")));
            instance.setHealthy(Boolean.parseBoolean(metadata.get("nacos.healthy")));
            instance.setPort(i.getPort());
            instance.setIp(i.getHost());
            instance.setServiceName(i.getServiceId());
            instance.setMetadata(metadata);
            return instance;
        }).collect(Collectors.toList());
        //采用nacos所配置的权重进行负载均衡调用,随机权重算法
        Instance instance = NacosBalancer.getHostByRandomWeight2(instances);
//        // TODO: enforce order?
//        int pos = Math.abs(this.position.incrementAndGet());
//        ServiceInstance instance = instances.get(pos % instances.size());
        return new DefaultResponse(collect.get(instance.getIp()+":"+ instance.getPort()).stream().findFirst().get());
    }
}

负载均衡配置类,指定使用哪一个负载均衡器

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
public class RoundRobinLoadBalancerConfig {
    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new CustomRoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}


LoadBalancerClient,负载均衡调用客户端,指定负载均衡器配置类,LoadBalancerClient注解中value要对用配置文件中路由的id

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@LoadBalancerClients({@LoadBalancerClient(value = "Mes", configuration = RoundRobinLoadBalancerConfig.class), @LoadBalancerClient(value = "Test", configuration = RoundRobinLoadBalancerConfig.class)})
@Configuration
public class RestTemplateConfig {

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

全局过滤器

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;

@Slf4j
@Component
public class RouteRecordGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                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;
    }
}

案例展示

Nacos服务列表
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第1张图片
服务权重配置
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第2张图片

服务测试代码
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第3张图片
负载效果
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第4张图片
配置中心测试代码
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第5张图片
本地配置项
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第6张图片
配置中心配置
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第7张图片
效果
SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer_第8张图片
配置中心注意
这三个配置的拼接等于配置中心的配置 Data ID一定要正确

spring.cloud.nacos.config.prefix=gateway
spring.cloud.nacos.config.file-extension=properties
spring.profiles.active=dev

你可能感兴趣的:(分布式理论&中间件搭建,java基础理论,spring,cloud,gateway,负载均衡)