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

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

目录

一、序言

二、代码示例

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

2、子工程spring-cloud-api-gateway

(1) pom.xml

(2) 配置文件和代码示例

3、子工程spring-cloud-user-service

(1) pom.xml

(2) 配置文件

4、子工程spring-cloud-message-service

(1) pom.xml

(2) 配置文件和代码示例

三、测试结果

1、集群负载均衡测试

2、服务路由测试

一、序言


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

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

二、代码示例


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

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

  <modules>
          <module>spring-cloud-api-gateway</module>
          <module>spring-cloud-user-service</module>
          <module>spring-cloud-message-service</module>
  </modules>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.boot.version>2.3.7.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
        <spring.cloud.alibaba.version>2.2.6.RELEASE</spring.cloud.alibaba.version>
        <commons.lang3.version>3.12.0</commons.lang3.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons.lang3.version}</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

2、子工程spring-cloud-api-gateway

(1) pom.xml

<parent>
        <groupId>com.universe</groupId>
        <artifactId>spring-cloud-gateway-learning</artifactId>
        <version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
</dependencies>

(2) 配置文件和代码示例

  1. bootstrap.yml
spring:
  application:
    name: api-gateway
server:
  port: 9000
  1. 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 实现,官网描述如下:

15.png

  1. 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的属性保存。

16.png

关于RouteToRequestUrlFilter的部分源码如下:

@Override
  public Mono<Void> 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

<parent>
        <groupId>com.universe</groupId>
        <artifactId>spring-cloud-gateway-learning</artifactId>
        <version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
</dependencies>

(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
  1. application.yml
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  1. UserController
@RestController
public class UserController {
  @GetMapping("/info")
  public Map<String, Object> getUserInfo() {
  Random random = new Random();
    int waitTime = random.nextInt(1000);
    LockSupport.parkNanos(1000 * 1000 * waitTime);
    Map<String, Object> result = new HashMap<>();
    result.put("name", "Nick");
    result.put("age", 25);
    return result;
  }
}

4、子工程spring-cloud-message-service

(1) pom.xml

<parent>
        <groupId>com.universe</groupId>
        <artifactId>spring-cloud-gateway-learning</artifactId>
        <version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
</dependencies>

(2) 配置文件和代码示例

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
  1. application.yml
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  1. MessageController
@RestController
public class MessageController {
  @GetMapping("/info")
  public Map<String, Object> getMessageInfo() {
  Random random = new Random();
    int waitTime = random.nextInt(1000);
    LockSupport.parkNanos(1000 * 1000 * waitTime);
    Map<String, Object> result = new HashMap<>();
    result.put("id", 1);
    result.put("title", "我爱中国");
    return result;
  }
}

三、测试结果


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

17.png

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

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

1、集群负载均衡测试

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

18.png

2、服务路由测试

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

19.png


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
5月前
|
负载均衡 算法 Java
【SpringCloud(4)】OpenFeign客户端:OpenFeign服务绑定;调用服务接口;Feign和OpenFeign
Feign是一个WebService客户端。使用Feign能让编写WebService客户端更加简单。 它的使用方法是定义一个服务接口然后再上面添加注解。Feign也支持可拔插式的编码器和解码器。SpringCloud对Feign进行了封装,十七支持了SpringMVC标准注解和HttpMessageConverters。 Feign可用于Eureka和Ribbon组合使用以支持负载均衡
816 138
|
6月前
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
|
5月前
|
缓存 JSON NoSQL
别再手写过滤器!SpringCloud Gateway 内置30 个,少写 80% 重复代码
小富分享Spring Cloud Gateway内置30+过滤器,涵盖请求、响应、路径、安全等场景,无需重复造轮子。通过配置实现Header处理、限流、重试、熔断等功能,提升网关开发效率,避免代码冗余。
577 1
|
8月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
566 0
|
9月前
|
缓存 监控 Java
说一说 SpringCloud Gateway 堆外内存溢出排查
我是小假 期待与你的下一次相遇 ~
1209 5
|
9月前
|
Java API Nacos
|
JSON Java API
利用Spring Cloud Gateway Predicate优化微服务路由策略
Spring Cloud Gateway 的路由配置中,`predicates`​(断言)用于定义哪些请求应该匹配特定的路由规则。 断言是Gateway在进行路由时,根据具体的请求信息如请求路径、请求方法、请求参数等进行匹配的规则。当一个请求的信息符合断言设置的条件时,Gateway就会将该请求路由到对应的服务上。
1341 69
利用Spring Cloud Gateway Predicate优化微服务路由策略
|
前端开发 Java Nacos
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
本文介绍了如何使用Spring Cloud Alibaba 2023.0.0.0技术栈构建微服务网关,以应对微服务架构中流量治理与安全管控的复杂性。通过一个包含鉴权服务、文件服务和主服务的项目,详细讲解了网关的整合与功能开发。首先,通过统一路由配置,将所有请求集中到网关进行管理;其次,实现了限流防刷功能,防止恶意刷接口;最后,添加了登录鉴权机制,确保用户身份验证。整个过程结合Nacos注册中心,确保服务注册与配置管理的高效性。通过这些实践,帮助开发者更好地理解和应用微服务网关。
2199 0
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
|
存储 SpringCloudAlibaba Java
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论。
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
|
JavaScript Java Kotlin
深入 Spring Cloud Gateway 过滤器
Spring Cloud Gateway 是新一代微服务网关框架,支持多种过滤器实现。本文详解了 `GlobalFilter`、`GatewayFilter` 和 `AbstractGatewayFilterFactory` 三种过滤器的实现方式及其应用场景,帮助开发者高效利用这些工具进行网关开发。
2015 1

相关实验场景

更多