栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Cloud Gateway整合Nacos实现服务路由及集群负载均衡

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Cloud Gateway整合Nacos实现服务路由及集群负载均衡

目录 一、序言

我们都知道 Spring Cloud Gateway 是一个基于 Spring Boot 、 Spring WebFlux 、 Project Reactor 构建的高性能网关,旨在提供简单、高效的API路由。

Spring Cloud Gateway基于 Netty 运行,因此在传统Servlet容器中或者打成war包是不能正常运行的。

二、代码示例

这里我们注册中心选型的是 Nacos ,如果还没有安装Nacos,请参考:Nacos快速安装部署。

1、父工程spring-cloud-gateway-learning

        spring-cloud-api-gateway
        spring-cloud-user-service
        spring-cloud-message-service



    8
    8
    UTF-8
    2.3.7.RELEASE
    Hoxton.SR12
    2.2.6.RELEASE
    3.12.0



    
        org.projectlombok
        lombok
    
    
        org.apache.commons
        commons-lang3
        ${commons.lang3.version}
    



    
        
            org.springframework.boot
            spring-boot-starter-parent
            ${spring.boot.version}
            pom
            import
        

        
            org.springframework.cloud
            spring-cloud-dependencies
            ${spring.cloud.version}
            pom
            import
        
        
            com.alibaba.cloud
            spring-cloud-alibaba-dependencies
            ${spring.cloud.alibaba.version}
            pom
            import
        
    

备注:具体Spring Cloud各版本说明请参考 Spring Cloud Alibaba版本说明 。

2、子工程spring-cloud-api-gateway (1) pom.xml
    

    com.universe
    spring-cloud-gateway-learning
    1.0-SNAPSHOT
   

 
    
        org.springframework.cloud
        spring-cloud-starter-gateway
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
    
  
(2) 配置文件和代码示例
  1. bootstrap.yml

    spring:
    application:
    name: api-gateway
    server:
    port: 9000
  2. application.yml

    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和端口,并做集群负载均衡。

这项功能通过全局过滤器 ReactiveLoadBalancerClientFilter 实现,官网描述如下:

   3.RouteRecordGlobalFilter

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

@Override
public  Mono  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 的属性保存。

关于 RouteToRequestUrlFilter 的部分源码如下:

    
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { 
    Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    if (route == null) { 
        return chain.filter(exchange);
    }
    log.trace("RouteToRequestUrlFilter start");
    URI uri = exchange.getRequest().getURI();
    boolean encoded = containsEncodedParts(uri);
    URI routeUri = route.getUri();

    if (hasAnotherScheme(routeUri)) { 
        // this is a special url, save scheme to special attribute
        // replace routeUri with schemeSpecificPart
        exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR,
                routeUri.getScheme());
        routeUri = URI.create(routeUri.getSchemeSpecificPart());
    }

    if ("lb".equalsIgnoreCase(routeUri.getScheme()) && routeUri.getHost() == null) { 
        // Load balanced URIs should always have a host. If the host is null it is
        // most
        // likely because the host name was invalid (for example included an
        // underscore)
        throw new IllegalStateException("Invalid host: " + routeUri.toString());
    }

    URI mergedUrl = UriComponentsBuilder.fromUri(uri)
            // .uri(routeUri)
            .scheme(routeUri.getScheme()).host(routeUri.getHost())
            .port(routeUri.getPort()).build(encoded).toUri();
    exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);
    return chain.filter(exchange);
}

备注:更多关于全局过滤器的介绍请参考 Spring Cloud Gateway全局过滤器 。

3、子工程spring-cloud-user-service (1) pom.xml
  

    com.universe
    spring-cloud-gateway-learning
    1.0-SNAPSHOT



    
        org.springframework.boot
        spring-boot-starter-web
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
    
(2) 配置文件
  1. bootstrap.yml

    spring:
    application:
    name: user-service
    server:
    servlet:
    context-path: /user
    
    ---
    spring:
    profiles: user-service-master
    server:
    port: 9091
    
    ---
    spring:
    profiles: user-service-slave
    server:
    port: 9092
  2. application.yml

    spring:
    cloud:
    nacos:
    discovery:
    server-addr: localhost:8848
  3. UserController

    @RestController
     public class UserController {
    
    
    @GetMapping("/info")
     public Map getUserInfo() {
    
    Random random = new Random();
    int waitTime = random.nextInt(1000);
    LockSupport.parkNanos(1000 * 1000 * waitTime);
    
    Map result = new HashMap<>();
    result.put("name", "Nick");
    result.put("age", 25);
    return result;
    }
    }
    
4、子工程spring-cloud-message-service (1) pom.xml
   

    com.universe
    spring-cloud-gateway-learning
    1.0-SNAPSHOT
   

  
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
    
   
(2) 配置文件和代码示例
  1. bootstrap.yml

    spring:
    application:
    name: message-service
    server:
    servlet:
    context-path: /message
    
    ---
    spring:
    profiles: message-service-master
    server:
    port: 9093
    
    ---
    spring:
    profiles: message-service-slave
    server:
    port: 9094
    
  2. application.yml

    spring:
    cloud:
    nacos:
    discovery:
    server-addr: localhost:8848
  3. MessageController

@RestController
public class MessageController {
 

    @GetMapping("/info")
    public Map getMessageInfo() {
 
    Random random = new Random();
        int waitTime = random.nextInt(1000);
        LockSupport.parkNanos(1000 * 1000 * waitTime);
    
        Map result = new HashMap<>();
        result.put("id", 1);
        result.put("title", "我爱中国");
        return result;
    }
}
三、测试结果

分别启动api-gateway、指定概要文件启动两个user-service服务实例、和两个message-service服务实例,查看Nacos控制台。

可以看到,api-gateway启动了一个服务实例,user-service和message-service都启动了两个服务实例。

备注:IDEA运行时指定 Active Profiles 即可。

1、集群负载均衡测试

连续访问 http://localhost:9000/user/info ,可以看到user-service集群服务实例被轮询调用。

2、服务路由测试

分别访问 http://localhost:9000/user/info 、 http://localhost:9000/message/info ,我们可以看到基于路径匹配的服务路由分发是成功的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/988745.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号