如何使用Spring Cloud Gateway构建可扩展的微服务网关 – wiki基地

使用 Spring Cloud Gateway 构建可扩展的微服务网关

在微服务架构中,服务网关扮演着至关重要的角色。它作为所有外部请求的单一入口点,负责请求路由、负载均衡、认证授权、限流熔断等关键功能。一个设计良好、性能卓越的网关是微服务体系稳定运行的基石。Spring Cloud Gateway 是 Spring Cloud 生态中一个强大的网关组件,它基于 Project Reactor、Spring WebFlux 和 Spring Boot 构建,提供了非阻塞 API 和高性能的请求处理能力。本文将深入探讨如何使用 Spring Cloud Gateway 构建一个可扩展的微服务网关,涵盖其核心概念、配置方法、高级特性以及实践中的最佳实践。

1. Spring Cloud Gateway 核心概念

在深入了解如何使用 Spring Cloud Gateway 之前,我们需要先理解其几个核心概念:

  • Route(路由): 路由是网关最基本的构建块。它由一个 ID、一个目标 URI、一组 Predicate(断言)和一个或多个 Filter(过滤器)组成。当请求到达网关时,会根据 Predicate 的匹配结果来决定是否将请求转发到目标 URI。
  • Predicate(断言): 断言用于匹配 HTTP 请求的各种属性,例如请求头、路径、参数等。只有当请求满足所有 Predicate 的条件时,才会匹配到对应的路由。Spring Cloud Gateway 内置了多种 Predicate,例如 Path、Header、Method、Host 等。
  • Filter(过滤器): 过滤器用于在请求被路由到目标服务之前或之后修改请求和响应。过滤器可以实现各种功能,例如添加请求头、修改响应体、记录日志、执行认证等。Spring Cloud Gateway 提供了两种类型的过滤器:GatewayFilter 和 GlobalFilter。GatewayFilter 应用于特定路由,而 GlobalFilter 应用于所有路由。

这三个核心概念之间的关系可以用下图表示:

+---------------------+ +---------------------+ +---------------------+
| Request | --> | Predicate | --> | Filter | --> | Target Service |
+---------------------+ +---------------------+ +---------------------+ +---------------------+
| (Matching) | | (Modification) |
+---------------------+ +---------------------+

2. 快速入门:构建一个简单的网关

让我们从一个简单的例子开始,构建一个基本的网关,将请求转发到目标服务。

2.1. 添加依赖

首先,我们需要在项目中添加 Spring Cloud Gateway 的依赖:

xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

如果你的项目是基于 Spring Boot 的, 那么可以这样引入, 否则, 还需要引入 Spring Boot 的依赖:

xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>

2.2. 配置路由

接下来,我们需要在 application.yml 文件中配置路由:

yaml
spring:
cloud:
gateway:
routes:
- id: my_route
uri: http://example.com
predicates:
- Path=/foo/**

这个配置定义了一个名为 my_route 的路由。它将所有路径以 /foo/ 开头的请求转发到 http://example.com

2.3. 启动网关

创建一个 Spring Boot 启动类:

“`java
@SpringBootApplication
public class GatewayApplication {

public static void main(String[] args) {
    SpringApplication.run(GatewayApplication.class, args);
}

}
“`

启动应用程序,现在你的网关已经在运行了。你可以通过访问 http://localhost:8080/foo/bar 来测试它,请求将被转发到 http://example.com/bar

3. 深入路由配置

Spring Cloud Gateway 提供了丰富的路由配置选项,可以满足各种复杂的路由需求。

3.1. Predicate 工厂

Spring Cloud Gateway 内置了许多 Predicate 工厂,用于匹配 HTTP 请求的不同属性。以下是一些常用的 Predicate 工厂:

  • Path Route Predicate Factory: 根据请求路径进行匹配。
  • Header Route Predicate Factory: 根据请求头进行匹配。
  • Method Route Predicate Factory: 根据 HTTP 方法进行匹配。
  • Host Route Predicate Factory: 根据请求的 Host 头进行匹配。
  • Query Route Predicate Factory: 根据请求参数进行匹配。
  • After Route Predicate Factory: 在指定时间之后匹配请求。
  • Before Route Predicate Factory: 在指定时间之前匹配请求。
  • Between Route Predicate Factory: 在指定时间范围内匹配请求。
  • Cookie Route Predicate Factory: 匹配请求中是否存在指定的Cookie,以及Cookie的值(可选).
  • RemoteAddr Route Predicate Factory: 匹配请求的来源IP地址。

你可以在路由配置中组合使用多个 Predicate,以实现更精细的匹配规则。例如:

yaml
spring:
cloud:
gateway:
routes:
- id: my_route
uri: http://example.com
predicates:
- Path=/foo/**
- Method=GET
- Header=X-Request-Id, \d+

这个配置将匹配路径以 /foo/ 开头、HTTP 方法为 GET 且包含名为 X-Request-Id 且值为数字的请求头的请求。

3.2. URI 的多种形式

uri 属性指定了路由的目标地址。除了使用 httphttps 协议外,还可以使用以下形式:

  • lb://<serviceId> 使用服务发现机制,将请求转发到名为 <serviceId> 的服务实例。这种方式需要集成服务发现组件,例如 Eureka、Consul 或 Nacos。
  • forward://<path>: 进行本地请求转发, 目标是一个本地的handler.

例如,使用 lb:// 协议:

yaml
spring:
cloud:
gateway:
routes:
- id: my_route
uri: lb://my-service
predicates:
- Path=/bar/**

这个配置将路径以 /bar/ 开头的请求转发到名为 my-service 的服务实例。

3.3 路由排序

当多个路由都能够匹配到同一个请求时,Spring Cloud Gateway 会根据路由的优先级来决定使用哪个路由。

路由的优先级由以下因素决定:

  1. Predicate 的数量: Predicate 数量越多的路由优先级越高。
  2. Predicate 的顺序: Predicate 的顺序越靠前,优先级越高。
  3. 路由的定义顺序: 如果两个路由的Predicate完全相同, 那么定义在前面的优先级更高.

可以使用order属性手动设置路由的优先级,order 值越小,优先级越高。
例如:

yaml
spring:
cloud:
gateway:
routes:
- id: route1
uri: http://example.com/route1
predicates:
- Path=/test/**
order: 1
- id: route2
uri: http://example.com/route2
predicates:
- Path=/test/**
order: 2

对于/test/abc这个路径, 两个路由都能匹配, 但是由于route1order更小, 所以会优先使用route1.

4. 过滤器详解

过滤器是 Spring Cloud Gateway 的另一个核心功能,它允许你在请求被路由到目标服务之前或之后修改请求和响应。

4.1. GatewayFilter

GatewayFilter 应用于特定路由。Spring Cloud Gateway 内置了许多 GatewayFilter 工厂,用于实现各种常见功能。以下是一些常用的 GatewayFilter 工厂:

  • AddRequestHeader GatewayFilter Factory: 添加请求头。
  • AddResponseHeader GatewayFilter Factory: 添加响应头。
  • RemoveRequestHeader GatewayFilter Factory: 删除请求头。
  • RemoveResponseHeader GatewayFilter Factory: 删除响应头。
  • RewritePath GatewayFilter Factory: 重写请求路径。
  • SetStatus GatewayFilter Factory: 设置响应状态码。
  • Hystrix GatewayFilter Factory: 集成 Hystrix 实现熔断。
  • RateLimiter GatewayFilter Factory: 实现限流。
  • Retry GatewayFilter Factory: 为上游服务调用配置重试策略.

你可以在路由配置中添加一个或多个 GatewayFilter:

yaml
spring:
cloud:
gateway:
routes:
- id: my_route
uri: http://example.com
predicates:
- Path=/foo/**
filters:
- AddRequestHeader=X-Request-Foo, Bar
- RewritePath=/foo/(?<segment>.*), /$\{segment}

这个配置为 my_route 添加了两个过滤器:

  • AddRequestHeader=X-Request-Foo, Bar:添加一个名为 X-Request-Foo,值为 Bar 的请求头。
  • RewritePath=/foo/(?<segment>.*), /$\{segment}:将请求路径从 /foo/xxx 重写为 /xxx

4.2. GlobalFilter

GlobalFilter 应用于所有路由。你可以通过实现 GlobalFilter 接口并将其注册为 Spring Bean 来创建自定义的 GlobalFilter。

“`java
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 在请求被路由之前执行的逻辑
    exchange.getAttributes().put("start-time", System.currentTimeMillis());

    return chain.filter(exchange).then(Mono.fromRunnable(() -> {
        // 在请求被路由之后执行的逻辑
        Long startTime = exchange.getAttribute("start-time");
        if (startTime != null) {
            long executeTime = System.currentTimeMillis() - startTime;
             System.out.println(exchange.getRequest().getURI().getRawPath() + ": " + executeTime + "ms");
        }
    }));
}
@Override
public int getOrder() {
  return Ordered.LOWEST_PRECEDENCE; //设置过滤器的执行顺序
}

}
“`

这个 GlobalFilter 在请求被路由之前记录请求开始时间,在请求被路由之后计算并打印请求执行时间。
getOrder()方法用于指定过滤器的执行顺序,值越小,优先级越高。

4.3. 自定义 GatewayFilter

除了使用内置的 GatewayFilter 工厂外,你还可以通过实现 GatewayFilter 接口并将其注册为 Spring Bean 来创建自定义的 GatewayFilter。通常我们会继承AbstractGatewayFilterFactory来实现自定义的GatewayFilterFactory:

“`java
@Component
public class MyCustomGatewayFilterFactory extends AbstractGatewayFilterFactory {

public MyCustomGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 在请求被路由之前执行的逻辑
if(config.isEnabled()) {
// 执行自定义逻辑…
}
return chain.filter(exchange);
};
}

public static class Config {
  private boolean enabled;

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}

}
“`

然后,你可以在路由配置中使用自定义的 GatewayFilter:

yaml
spring:
cloud:
gateway:
routes:
- id: my_route
uri: http://example.com
predicates:
- Path=/foo/**
filters:
- MyCustom=true # 这里的MyCustom 对应MyCustomGatewayFilterFactory的名字(去掉Factory)

5. 高级特性

除了基本的路由和过滤功能外,Spring Cloud Gateway 还提供了一些高级特性,可以帮助你构建更强大、更可靠的网关。

5.1. 限流

限流是保护微服务免受过载的重要手段。Spring Cloud Gateway 集成了 spring-cloud-starter-circuitbreaker-reactor-resilience4j,可以使用RequestRateLimiter过滤器实现限流功能。

yaml
spring:
cloud:
gateway:
routes:
- id: my_route
uri: lb://my-service
predicates:
- Path=/bar/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 #允许用户每秒执行多少个请求
redis-rate-limiter.burstCapacity: 20 # 令牌桶的容量
key-resolver: "#{@ipKeyResolver}" # 使用 SpEL 表达式从 exchange 中提取限流 key, 这里使用ipKeyResolver, 根据请求ip限流

要使用RequestRateLimiter,你需要添加以下依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

并且定义KeyResolver:
java
@Bean
KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

5.2. 熔断

熔断是另一种保护微服务的重要手段。当目标服务出现故障时,熔断器可以阻止请求继续发送到该服务,从而避免级联故障。Spring Cloud Gateway 通过集成 Resilience4j 提供了熔断功能。

yaml
spring:
cloud:
gateway:
routes:
- id: my_route
uri: lb://my-service
predicates:
- Path=/baz/**
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallback

这个配置为 my_route 添加了一个名为 myCircuitBreaker 的熔断器。当请求 my-service 失败时,熔断器会打开,后续请求将被转发到 /fallback 路径。

5.3. 负载均衡

Spring Cloud Gateway 可以与服务发现组件(例如 Eureka、Consul 或 Nacos)集成,实现负载均衡。当使用 lb:// 协议时,Spring Cloud Gateway 会自动从服务发现组件获取服务实例列表,并使用负载均衡算法将请求分发到不同的实例。

Spring Cloud Gateway 默认使用轮询(Round Robin)算法进行负载均衡。你可以通过配置 spring.cloud.gateway.loadbalancer.type 属性来更改负载均衡算法。例如,使用随机(Random)算法:

yaml
spring:
cloud:
gateway:
loadbalancer:
type: random

如果需要使用更复杂的负载均衡策略,可以自定义 ReactorLoadBalancer 类型的 Bean。

5.4. 监控和指标

Spring Cloud Gateway 集成了 Micrometer,可以收集各种网关指标,例如请求数、响应时间、错误率等。你可以通过 Actuator 端点 /actuator/gateway 查看这些指标。
如果需要将这些指标暴露给Prometheus等监控系统,可以添加以下依赖:

xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

然后配置 Actuator 暴露 metrics 端点:

yaml
management:
endpoints:
web:
exposure:
include: gateway, prometheus # 暴露 gateway 和 prometheus 端点

5.5 WebSocket支持

Spring Cloud Gateway本身就支持WebSocket的代理,不需要额外配置,只需要将uri设置为ws://协议即可,例如:

yaml
spring:
cloud:
gateway:
routes:
- id: websocket_route
uri: ws://localhost:9000
predicates:
- Path=/echo

6. 最佳实践

以下是一些使用 Spring Cloud Gateway 的最佳实践:

  • 使用 YAML 配置: 尽量使用 YAML 文件进行路由和过滤器配置,因为它比 Java 代码更简洁、更易读。
  • 合理使用 Predicate 和 Filter: 根据实际需求选择合适的 Predicate 和 Filter,避免过度配置。
  • 配置限流和熔断: 为所有路由配置限流和熔断,以保护微服务免受过载和故障的影响。
  • 监控网关指标: 监控网关的请求数、响应时间、错误率等指标,及时发现并解决问题。
  • 使用服务发现: 与服务发现组件集成,实现动态路由和负载均衡。
  • 安全性考虑: 使用 HTTPS 保护网关与客户端之间的通信,并对请求进行认证和授权。
  • 版本控制: 将网关的配置(例如路由配置)纳入版本控制系统, 以便追踪变更和回滚.
  • 测试: 对网关进行充分的测试, 包括单元测试, 集成测试和性能测试.

总结

Spring Cloud Gateway 是一个功能强大、性能卓越的微服务网关。它提供了丰富的路由和过滤功能,可以满足各种复杂的网关需求。通过合理配置 Predicate、Filter、限流、熔断等特性,你可以构建一个可扩展、可靠的微服务网关,为你的微服务体系保驾护航。希望本文能够帮助你深入理解 Spring Cloud Gateway,并在实践中更好地应用它。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部