一、Gateway 网关基础概念
API 网关
概念定义
API 网关(API Gateway)是微服务架构中的核心组件,充当客户端与后端服务之间的统一入口。它负责请求路由、协议转换、安全认证、流量控制、监控日志等核心功能,将复杂的后端服务细节对客户端透明化。
核心功能
1. 路由转发
- 根据请求路径、Header、参数等条件将请求动态路由到对应的微服务实例
- 示例:
/order-service/**
的请求转发到订单微服务集群
2. 协议转换
- 支持 HTTP/HTTPS、WebSocket、gRPC 等协议转换
- 前后端解耦:前端始终使用 RESTful API,后端可自由选择通信协议
3. 安全防护
- 认证鉴权:JWT 验证、OAuth2.0 集成
- 防攻击:IP 黑名单、请求频率限制
- SSL 终端:统一处理 HTTPS 加解密
4. 流量控制
- 熔断降级:Hystrix/Sentinel 集成
- 限流策略:令牌桶/漏桶算法实现
- 负载均衡:轮询/权重/一致性哈希等策略
技术实现对比
方案 | 特点 | 适用场景 |
---|---|---|
Spring Cloud Gateway | 基于 Reactor 的异步非阻塞模型 | Spring Cloud 生态 |
Kong | 基于 Nginx + OpenResty | 高性能需求场景 |
Traefik | 自动服务发现 | Kubernetes 环境 |
配置示例(Spring Cloud Gateway)
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
典型应用场景
- 微服务聚合:将多个微服务的响应组合后返回
- 移动端优化:合并 API 请求减少网络开销
- 灰度发布:通过 Header 路由部分流量到新版本
- 跨域处理:统一配置 CORS 策略
性能优化建议
- 启用响应缓存(Cache-Control)
- 使用二进制协议(如 Protocol Buffers)
- 异步非阻塞 I/O 模型
- 合理设置超时时间(一般 3-10 秒)
监控指标
- 请求成功率(2xx/4xx/5xx)
- 平均响应时间(RT)
- 并发连接数
- 限流触发次数
Spring Cloud Gateway 简介
什么是 Spring Cloud Gateway?
Spring Cloud Gateway 是 Spring Cloud 生态中的一个 API 网关组件,基于 Spring 5、Spring Boot 2 和 Project Reactor 技术栈构建。它旨在为微服务架构提供一种简单、高效的方式来路由请求,以及对请求进行过滤和转换。与传统的 Zuul 网关相比,Spring Cloud Gateway 提供了更好的性能(基于 Netty 的非阻塞模型)和更丰富的功能。
核心功能
- 动态路由:能够根据配置动态地将请求路由到不同的微服务实例。
- 请求过滤(Filter):支持在请求转发前后对请求和响应进行修改或增强(如添加请求头、鉴权、限流等)。
- 负载均衡:集成 Spring Cloud LoadBalancer,支持客户端负载均衡。
- 断路器集成:可与 Resilience4j 或 Hystrix 结合实现熔断降级。
- 路径重写:支持对请求路径进行重写或截取。
- 支持 WebSocket:能够代理 WebSocket 请求。
核心概念
- Route(路由):网关的基本构建块,包含 ID、目标 URI、断言(Predicate)和过滤器(Filter)集合。
- Predicate(断言):用于匹配 HTTP 请求的条件(如路径、请求头、方法等)。
- Filter(过滤器):用于在请求转发前后修改请求或响应。
使用场景
- 统一入口:作为所有微服务的唯一入口,对外隐藏内部服务细节。
- 鉴权与安全:集中处理身份验证(如 JWT 校验)、权限控制。
- 流量控制:实现限流(如基于 Redis 的令牌桶算法)。
- 请求监控与日志:统一收集请求日志和指标数据。
- 灰度发布:通过路由规则将部分流量导到新版本服务。
示例代码(基础配置)
# application.yml 配置示例
spring:
cloud:
gateway:
routes:
- id: user-service # 路由ID
uri: lb://user-service # 目标服务(lb://表示负载均衡)
predicates: # 断言条件
- Path=/api/users/** # 路径匹配
filters: # 过滤器
- StripPrefix=1 # 去掉路径前缀(如 /api/users -> /users)
- AddRequestHeader=X-Request-Red, Blue # 添加请求头
注意事项
- 性能影响:过滤器链过长会增加延迟,需合理设计过滤逻辑。
- 路由顺序:路由按配置顺序匹配,优先匹配第一个满足条件的路由。
- 服务发现依赖:若使用
lb://
负载均衡,需确保服务注册中心(如 Nacos、Eureka)已正确配置。 - WebFlux 兼容性:由于基于 Reactor 模型,不支持传统的 Servlet 容器(如 Tomcat)。
与 Zuul 的对比
- 性能:Gateway 基于 Netty 非阻塞模型,吞吐量更高。
- 功能扩展:Gateway 的 Filter 和 Predicate 更灵活,支持动态配置。
- 维护状态:Spring Cloud 官方已宣布 Zuul 1.x 进入维护模式,推荐使用 Gateway。
网关的核心功能
网关(Gateway)作为微服务架构中的重要组件,承担着请求流量入口的角色,其核心功能主要包括以下几个方面:
1. 路由转发
网关的核心功能之一是动态路由,根据请求的路径、参数、Header等信息,将请求转发到对应的后端服务。例如:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/user/**
这段配置表示所有以 /user
开头的请求都会被转发到 user-service
服务。
2. 负载均衡
网关通常集成了负载均衡功能(如Ribbon或Spring Cloud LoadBalancer),可以将请求均匀地分发到多个服务实例上,提高系统的可用性和性能。
3. 鉴权认证
网关可以集中处理身份验证和授权,常见的实现方式包括:
- JWT(JSON Web Token)验证
- OAuth2.0 认证
- 基本的API Key验证
4. 流量控制
网关可以实施限流策略,保护后端服务不被突发流量冲垮。常见的限流算法包括:
- 令牌桶算法
- 漏桶算法
- 计数器算法
示例配置:
spring:
cloud:
gateway:
routes:
- id: rate-limit
uri: http://example.org
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
5. 请求/响应改写
网关可以在请求到达服务前或响应返回客户端前,对内容进行修改:
- 添加/删除Header
- 修改请求路径
- 改写响应体
6. 熔断降级
当后端服务出现故障时,网关可以实现熔断机制,返回预设的fallback响应,避免级联故障。
7. 监控与日志
网关可以集中收集请求的监控指标和日志,便于:
- 性能分析
- 故障排查
- 审计跟踪
8. 协议转换
网关可以实现不同协议之间的转换,例如:
- HTTP转gRPC
- WebSocket转HTTP
- REST转SOAP
9. 跨域处理
网关可以统一处理跨域请求(CORS),避免每个服务单独配置。
10. 缓存
对于某些静态内容或变化不频繁的数据,网关可以实现缓存机制,减少后端服务压力。
这些核心功能使得网关成为微服务架构中不可或缺的组件,既简化了客户端调用,又为后端服务提供了保护层。
网关与负载均衡的区别
概念定义
-
网关(Gateway)
网关是网络中的核心组件,负责在不同网络或协议之间进行数据转换和路由。它充当系统的入口点,处理所有进入的请求,并执行诸如身份验证、授权、请求转发、协议转换等任务。常见的网关类型包括API网关、服务网关等。 -
负载均衡(Load Balancing)
负载均衡是一种技术,用于将网络流量或计算任务分配到多个服务器或资源上,以提高系统的可用性、性能和容错能力。负载均衡器通常位于后端服务之前,确保请求被均匀分配到多个实例上。
核心功能对比
-
网关的核心功能
- 路由转发:将请求分发到不同的后端服务。
- 协议转换:例如将HTTP请求转换为gRPC或其他协议。
- 安全控制:实现身份验证(如JWT校验)、权限控制、IP黑白名单等。
- 流量管理:限流、熔断、降级等。
- 请求/响应转换:修改请求头、请求体或响应内容。
-
负载均衡的核心功能
- 流量分发:根据算法(如轮询、加权轮询、最小连接数等)将请求分配到多个服务器。
- 健康检查:监控后端服务器的可用性,自动剔除故障节点。
- 会话保持:确保同一用户的请求被分配到同一服务器(如基于Cookie或IP哈希)。
使用场景
-
网关的典型场景
- 微服务架构中作为统一的API入口。
- 需要统一安全策略(如OAuth2认证)的场景。
- 需要聚合多个后端服务的响应(如BFF模式)。
-
负载均衡的典型场景
- 高并发场景下横向扩展服务实例。
- 提高服务的可用性,避免单点故障。
- 需要动态调整服务器权重的场景(如蓝绿部署)。
常见误区
-
网关可以替代负载均衡器?
不能完全替代。网关虽然支持路由转发,但其核心职责是协议转换和安全控制。高性能的流量分发仍需依赖专用负载均衡器(如Nginx、硬件负载均衡设备)。 -
负载均衡器能实现网关的功能?
不能。负载均衡器通常缺乏协议转换、复杂的身份验证等能力,无法替代网关的完整功能。
示例代码
-
网关路由配置(Spring Cloud Gateway)
spring: cloud: gateway: routes: - id: user-service uri: lb://user-service # 负载均衡到user-service predicates: - Path=/api/users/**
-
负载均衡配置(Nginx)
upstream backend { server 10.0.0.1 weight=3; # 权重为3 server 10.0.0.2; # 默认权重1 } server { location / { proxy_pass http://backend; } }
总结
- 网关是系统的“守门人”,专注于请求的全局管控和协议适配。
- 负载均衡是“流量调度员”,专注于优化资源利用和提高吞吐量。
- 实际项目中,二者常结合使用(如网关调用负载均衡后的服务)。
网关的应用场景
网关(Gateway)作为微服务架构中的核心组件,承担着请求路由、负载均衡、安全控制等重要职责。以下是网关在不同场景下的典型应用:
1. 请求路由与负载均衡
- 场景描述:将客户端请求动态路由到后端不同的微服务实例。
- 技术实现:基于路径(
/order/**
)、域名或请求头匹配规则。 - 示例:电商系统中,
/product/
开头的请求路由至商品服务,/user/
开头的请求路由至用户服务。
2. API 聚合与裁剪
- 场景描述:合并多个微服务的返回结果,减少客户端请求次数。
- 示例:移动端首页需展示用户信息、订单列表和推荐商品,网关可聚合三个接口的响应后返回。
- 裁剪优化:过滤不需要的字段,降低网络传输开销。
3. 安全防护
- 常见措施:
- 认证鉴权:集成 OAuth2、JWT 等机制,验证请求合法性。
- IP 黑白名单:阻止恶意 IP 访问。
- 防重放攻击:通过时间戳和随机数(Nonce)校验请求唯一性。
4. 流量控制与熔断
- 场景:
- 限流:通过令牌桶或漏桶算法限制每秒请求数(QPS)。
- 熔断:当后端服务故障时,快速返回降级响应(如缓存数据)。
- 示例配置(Spring Cloud Gateway):
spring: cloud: gateway: routes: - id: order-service uri: lb://order-service predicates: - Path=/order/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 # 每秒10个请求 redis-rate-limiter.burstCapacity: 20 # 峰值20个请求
5. 协议转换
- 场景:统一外部 HTTP 请求与内部 gRPC/Dubbo 等协议。
- 示例:物联网设备使用 MQTT 协议上报数据,网关将其转换为 HTTP 请求转发至业务系统。
6. 灰度发布
- 实现方式:
- 基于 Header:如
version=v2
的请求路由至新版本服务。 - 基于流量比例:10% 的流量导流到新版本实例。
- 基于 Header:如
- 优势:降低全量发布风险。
7. 日志与监控
- 功能:
- 记录请求/响应日志(需脱敏敏感数据)。
- 集成 Prometheus 上报 QPS、延迟等指标。
- 示例(Spring Cloud Gateway 日志过滤器):
@Bean public GlobalFilter loggingFilter() { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest(); log.info("Path: {}, Headers: {}", request.getPath(), request.getHeaders()); return chain.filter(exchange); }; }
8. 跨域处理
- 场景:统一处理前端跨域请求(CORS),避免每个微服务重复配置。
- 网关配置示例:
spring: cloud: gateway: globalcors: cors-configurations: '[/**]': allowedOrigins: "https://example.com" allowedMethods: "GET,POST"
注意事项
- 性能瓶颈:避免在网关中处理复杂业务逻辑。
- 高可用:需部署多个网关实例,结合负载均衡器(如 Nginx)使用。
- 敏感信息:日志中需过滤
Authorization
等头信息。
二、Gateway 核心组件
Route(路由)
概念定义
在Gateway网关中,Route(路由) 是网关的核心组件之一,用于定义请求的转发规则。一个路由通常由以下三部分组成:
- ID:唯一标识符,用于区分不同路由。
- URI:目标服务的地址,即请求最终被转发到的位置。
- Predicate(断言):匹配条件,决定哪些请求会被当前路由处理。
- Filter(过滤器):对请求或响应进行处理的逻辑(如修改请求头、重试机制等)。
路由的核心作用是将符合特定条件的请求转发到指定的服务实例。
使用场景
- 动态路由:根据请求的路径(如
/order/**
)、Header、参数等动态转发到不同微服务。 - 负载均衡:结合服务注册中心(如Nacos、Eureka),通过
lb://service-name
实现负载均衡。 - 灰度发布:通过路由的断言和过滤器,将部分流量导流到新版本服务。
- 跨域处理:在路由层统一配置跨域规则。
配置示例(YAML)
spring:
cloud:
gateway:
routes:
- id: order-service # 路由ID
uri: lb://order-service # 目标服务(负载均衡)
predicates: # 断言条件
- Path=/order/**
filters: # 过滤器
- StripPrefix=1 # 去掉路径前缀(/order)
常见误区与注意事项
-
URI协议:
- 使用
lb://
前缀时需确保服务已注册到注册中心。 - 直接写HTTP地址时需用
http://
或https://
。
- 使用
-
断言顺序:
- 多个路由的断言可能存在重叠,网关会按配置顺序匹配第一个符合条件的路由。
-
路径处理:
StripPrefix
过滤器常用于去掉网关层的前缀(如上述示例中移除/order
)。
-
性能影响:
- 过多的路由或复杂断言会增加匹配耗时,建议合理规划路由规则。
高级配置示例(Java DSL)
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("auth-route", r -> r.path("/auth/**")
.filters(f -> f.rewritePath("/auth/(?<segment>.*)", "/${segment}"))
.uri("http://auth-service"))
.route("payment-route", r -> r.header("X-Scope", "payment")
.uri("lb://payment-service"))
.build();
}
关键点总结
- 路由匹配优先级:ID无特殊含义,实际匹配按配置顺序。
- 过滤器链:每个路由的过滤器仅对当前路由生效。
- 动态更新:可通过Spring Cloud Config或Nacos实现路由热更新。
Predicate(断言)
概念定义
Predicate(断言)是 Java 8 引入的一个函数式接口,位于 java.util.function
包中。它代表一个布尔值函数,接收一个输入参数并返回 true
或 false
。通常用于条件判断、过滤和验证逻辑。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
使用场景
- 集合过滤:结合
Stream
的filter()
方法筛选数据。 - 条件判断:动态定义复杂的业务规则。
- 参数校验:验证输入参数的合法性。
常见方法
test(T t)
:核心方法,执行条件判断。and(Predicate other)
:逻辑与操作。or(Predicate other)
:逻辑或操作。negate()
:逻辑非操作。
示例代码
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 定义断言:判断字符串长度是否大于3
Predicate<String> lengthPredicate = s -> s.length() > 3;
// 使用断言过滤集合
names.stream()
.filter(lengthPredicate)
.forEach(System.out::println); // 输出:Alice, Charlie, David
// 组合断言:长度大于3且以"A"开头
Predicate<String> startsWithA = s -> s.startsWith("A");
names.stream()
.filter(lengthPredicate.and(startsWithA))
.forEach(System.out::println); // 输出:Alice
}
}
注意事项
- 空指针问题:如果输入参数可能为
null
,需在test()
方法中显式处理。 - 性能影响:复杂断言可能影响
Stream
操作的性能,需评估实际场景。 - 组合顺序:
and()
和or()
的组合顺序会影响最终结果,建议用括号明确优先级。
Filter(过滤器)
概念定义
Filter 是 Gateway 网关中的核心组件之一,用于在请求到达目标服务之前或响应返回客户端之前,对请求和响应进行拦截和处理。它类似于 Servlet 中的过滤器(Filter),但专为网关设计,通常用于实现统一的逻辑处理,如鉴权、日志记录、限流等。
使用场景
- 鉴权与认证:验证请求的合法性(如 JWT 校验)。
- 请求/响应修改:添加或删除请求头、修改请求体。
- 日志记录:记录请求和响应的详细信息。
- 限流与熔断:限制请求频率或防止服务过载。
- 路由重定向:根据条件动态路由请求。
常见 Filter 类型
- Global Filter:全局生效,作用于所有路由。
- Gateway Filter:针对特定路由生效。
- Default Filter:默认过滤器,对所有路由生效(需配置)。
示例代码(Spring Cloud Gateway)
1. 自定义全局过滤器
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 优先级,数值越小优先级越高
}
}
2. 配置路由过滤器(YAML)
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
filters:
- AddRequestHeader=X-Request-User, admin # 添加请求头
- StripPrefix=1 # 去除路径前缀
常见误区与注意事项
- 执行顺序问题:过滤器的执行顺序由
Order
接口或配置顺序决定,需明确优先级。 - 阻塞操作:避免在 Filter 中执行阻塞操作(如同步数据库调用),否则会降低网关性能。
- 请求体修改:直接读取请求体会消费流,需使用
CachedBodyOutputMessage
缓存。 - 异常处理:自定义异常需通过
ErrorWebExceptionHandler
处理,而非直接在 Filter 中返回响应。
高级用法
- 动态加载 Filter:通过
RouteLocator
动态添加或移除 Filter。 - 结合 Actuator:使用
/actuator/gateway/filters
端点查看已加载的 Filter。 - 自定义 Filter 工厂:继承
AbstractGatewayFilterFactory
实现更灵活的配置。
Gateway 工作原理
基本概念
Gateway(网关)是微服务架构中的核心组件,充当所有外部请求的统一入口,负责请求的路由、过滤、负载均衡等操作。它位于客户端与后端服务之间,类似于现实中的“海关”,对所有进出流量进行管控。
核心功能模块
-
路由(Routing)
- 根据请求路径(如
/order/**
)、Header、参数等条件,将请求转发到对应的微服务实例。 - 示例配置(Spring Cloud Gateway):
spring: cloud: gateway: routes: - id: order-service uri: lb://order-service predicates: - Path=/order/**
- 根据请求路径(如
-
过滤链(Filter Chain)
- Pre-Filter:在路由前执行(如鉴权、日志记录)。
- Post-Filter:在响应返回前执行(如修改响应头、记录耗时)。
- 示例:添加全局请求头
@Bean public GlobalFilter customFilter() { return (exchange, chain) -> { exchange.getRequest().mutate() .header("X-Gateway-Request", "true"); return chain.filter(exchange); }; }
-
负载均衡
- 通过集成
LoadBalancerClient
(如 Ribbon)实现服务实例的动态选择。 - 使用
lb://service-name
格式指定目标服务。
- 通过集成
-
熔断与限流
- 集成 Resilience4j 或 Sentinel 实现流量控制。
工作流程
- 客户端发起请求 → Gateway 接收请求。
- 匹配路由规则:根据
predicates
选择目标服务。 - 执行过滤链:依次执行 Pre-Filter。
- 转发请求:通过负载均衡选择实例并转发。
- 接收响应:执行 Post-Filter 后返回客户端。
技术实现对比
特性 | Spring Cloud Gateway | Netflix Zuul |
---|---|---|
性能 | 基于 Netty(异步非阻塞) | Servlet(同步阻塞) |
功能扩展 | 支持自定义过滤器、断言 | 插件式扩展 |
维护状态 | 官方持续维护 | 进入维护模式 |
注意事项
- 性能瓶颈:避免在 Gateway 中处理复杂业务逻辑。
- 路由顺序:规则按声明顺序匹配,需将通用路由(如
/api/**
)放在后面。 - 服务发现:确保 Gateway 能正确连接到注册中心(如 Nacos、Eureka)。
高级场景
- 灰度发布:通过 Header 或 Cookie 路由到特定版本服务。
- 跨域处理:直接在 Gateway 配置 CORS,避免每个服务重复处理。
spring: cloud: gateway: globalcors: cors-configurations: '[/**]': allowedOrigins: "*" allowedMethods: "GET,POST"
Gateway 请求处理流程
概念定义
Gateway 请求处理流程是指客户端请求通过 API 网关时,网关内部对请求进行的一系列处理步骤。这些步骤通常包括路由匹配、过滤器链执行、请求转发和响应处理等环节。Spring Cloud Gateway 作为常用的 API 网关,其核心流程基于 Reactor 响应式编程模型实现。
核心处理步骤
1. 请求接收
- 网关通过 Netty 服务器接收 HTTP 请求
- 将原始请求封装为
ServerWebExchange
对象(包含请求、响应、上下文等信息)
2. 路由匹配
- 根据请求路径(Path)、方法(Method)、Header 等属性
- 从路由配置(RouteDefinition)中查找匹配的路由规则
- 匹配成功后获取目标服务 URI 和关联的过滤器链
3. 过滤器链执行
分为两类过滤器:
- Pre 过滤器:在请求转发前执行(认证、限流、日志等)
- Post 过滤器:在收到目标服务响应后执行(修改响应、记录指标等)
常见内置过滤器:
AddRequestHeader
:添加请求头RewritePath
:重写路径Retry
:重试机制CircuitBreaker
:熔断保护
4. 请求转发
- 通过 HTTP 客户端(如 WebClient)将请求转发至目标服务
- 支持负载均衡(集成 LoadBalancerClient)
5. 响应处理
- 接收目标服务响应
- 执行 Post 过滤器链
- 返回最终响应给客户端
示例代码
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/service/**")
.filters(f -> f
.addRequestHeader("X-Request-Id", UUID.randomUUID().toString())
.rewritePath("/service/(?<segment>.*)", "/${segment}")
)
.uri("lb://backend-service"))
.build();
}
注意事项
- 过滤器顺序:通过
Order
注解控制过滤器执行顺序 - 异常处理:自定义
ErrorWebExceptionHandler
处理流程中的异常 - 性能优化:
- 合理配置线程池
- 避免在过滤器中执行阻塞操作
- 缓存考虑:对于频繁访问的路由配置可启用缓存
高级特性
- 动态路由:通过监听配置中心实现路由热更新
- 自定义过滤器:实现
GlobalFilter
接口扩展功能 - 灰度发布:基于 Header 或 Cookie 的路由策略
三、Gateway 基本配置
创建 Gateway 项目
1. 使用 Spring Initializr 创建项目
- 访问 Spring Initializr
- 选择项目配置:
- Project: Maven 或 Gradle
- Language: Java
- Spring Boot: 选择稳定版本(推荐 3.x+)
- 添加依赖:
- 核心依赖:
Spring Web
- 网关依赖:
Gateway
- 可选依赖:
Lombok
(简化代码)
- 核心依赖:
2. Maven 依赖配置
<!-- pom.xml -->
<dependencies>
<!-- Spring Cloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 其他可选依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<!-- 确保 Spring Cloud 版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2023.0.0</version> <!-- 根据 Spring Boot 版本选择 -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3. 基础配置文件
在 application.yml
或 application.properties
中配置路由规则:
# application.yml 示例
spring:
cloud:
gateway:
routes:
- id: example-service
uri: http://example.com
predicates:
- Path=/api/example/**
filters:
- StripPrefix=1
4. 启动类
创建标准的 Spring Boot 启动类:
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
5. 验证网关运行
- 启动项目后访问
http://localhost:8080/api/example
- 网关会将请求转发到
http://example.com
(需确保目标服务可达)
6. 高级配置(可选)
通过 Java DSL 动态配置路由:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("custom-path", r -> r.path("/custom/**")
.filters(f -> f.stripPrefix(1))
.uri("http://custom-service"))
.build();
}
注意事项
- 避免与 WebFlux 冲突:Gateway 基于 WebFlux,不要引入
spring-boot-starter-web
- 路由顺序:通过
order
属性控制路由匹配优先级 - 生产环境建议:
- 集成服务发现(如 Nacos/Eureka)
- 配置熔断(如 Resilience4j)
- 启用指标监控(如 Micrometer)
基础路由配置
概念定义
基础路由配置是API网关的核心功能之一,它定义了如何将客户端请求转发到后端服务。路由配置通常包含以下关键元素:
- 路径匹配规则:指定哪些URL路径会被该路由处理
- 目标服务:定义请求将被转发到的后端服务地址
- 谓词(Predicate):决定请求是否匹配该路由的条件
- 过滤器(Filter):可以在请求转发前后对请求/响应进行修改
使用场景
- 简单的服务代理:将/api/users转发到用户服务
- 版本化路由:如/v1/products和/v2/products指向不同服务实例
- 路径重写:将外部路径/internal/api映射到后端的/private/api
- 多环境路由:将测试环境的请求路由到测试服务集群
常见配置方式
YAML配置示例(Spring Cloud Gateway)
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
Java DSL配置示例
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("product-service", r -> r.path("/api/products/**")
.filters(f -> f.stripPrefix(1))
.uri("lb://product-service"))
.build();
}
关键配置项说明
路径匹配
- 精确匹配:
Path=/api/users
- 通配符匹配:
Path=/api/users/*
(单级)或/api/users/**
(多级) - 正则表达式:
Path=/api/users/[0-9]+
谓词组合
predicates:
- Path=/api/orders/**
- Method=GET,POST
- Header=X-Request-Id, \d+
- After=2023-01-20T17:42:47.789-07:00[America/Denver]
常见误区与注意事项
- 路径匹配顺序:网关按配置顺序匹配路由,第一个匹配的路由会被执行
- 负载均衡:使用
lb://service-name
时需要确保服务注册中心正常运行 - 路径处理:
- 注意
StripPrefix
过滤器的使用,它会移除路径前缀 - 未正确处理路径可能导致404错误
- 注意
- 性能影响:过多复杂路由规则会影响网关性能
- 编码问题:URL中的特殊字符需要正确编码/解码
高级路由示例
routes:
- id: fallback-route
uri: lb://fallback-service
predicates:
- Path=/fallback/**
filters:
- SetPath=/api/${segment}
- SetResponseHeader=Content-Type, application/json
- CircuitBreaker=myCircuitBreaker
调试技巧
- 使用
/actuator/gateway/routes
端点查看所有路由 - 通过日志设置
logging.level.org.springframework.cloud.gateway=DEBUG
查看详细路由匹配过程 - 使用Postman等工具测试不同路径的路由行为
动态路由配置
概念定义
动态路由配置是指网关(如Spring Cloud Gateway)在运行时能够动态地添加、修改或删除路由规则,而无需重启服务。与静态路由(在配置文件中预先定义)相比,动态路由提供了更高的灵活性和可扩展性,特别适合微服务架构中频繁变动的服务实例。
核心实现方式
-
基于内存存储
通过编程方式(如Java代码)动态修改路由规则,但重启后配置会丢失。@Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("dynamic_route", r -> r.path("/api/**") .uri("lb://service-name")) .build(); }
-
持久化存储方案
通常结合数据库(如Redis、MySQL)或配置中心(如Nacos、Apollo)实现路由规则的持久化:@Autowired private RedisTemplate<String, Object> redisTemplate; public void addRoute(String id, String path, String uri) { RouteDefinition definition = new RouteDefinition(); definition.setId(id); definition.setPredicates(List.of( new PredicateDefinition("Path=" + path))); definition.setUri(URI.create(uri)); redisTemplate.opsForValue().set("route_" + id, definition); }
-
监听机制
通过事件监听(如Spring ApplicationEvent)实现实时更新:@Autowired private ApplicationEventPublisher publisher; public void refreshRoutes() { publisher.publishEvent(new RefreshRoutesEvent(this)); }
典型应用场景
- 蓝绿部署:动态切换新旧版本服务路由
- A/B测试:按条件将流量路由到不同服务实例
- 故障转移:自动剔除不可用服务节点
- 多环境管理:动态调整测试/生产环境路由
注意事项
-
线程安全问题
动态修改路由时需保证操作原子性,推荐使用:synchronized(this) { // 路由更新操作 }
-
性能影响
高频路由更新可能导致性能下降,建议:- 批量更新代替单次操作
- 限制最小更新间隔(如500ms)
-
版本兼容性
不同Spring Cloud Gateway版本的路由定义模型可能有差异:<!-- 推荐显式指定版本 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> <version>3.1.3</version> </dependency>
完整示例(基于Nacos)
-
添加依赖:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
配置监听:
@Configuration public class NacosRouteDefinitionRepository { @Bean public RouteDefinitionLocator nacosRouteDefinitionLocator() { return new NacosRouteDefinitionLocator( nacosConfigManager, nacosProperties); } }
-
Nacos配置示例:
spring: cloud: gateway: routes: - id: user-service uri: lb://user-service predicates: - Path=/user/** - id: order-service uri: lb://order-service predicates: - Path=/order/**
路由元数据配置
概念定义
路由元数据(Route Metadata)是附加在网关路由规则上的自定义键值对数据,用于存储与路由相关的额外信息。这些数据不会直接影响路由行为,但可以被过滤器、断言等组件读取并用于逻辑控制。
核心作用
- 扩展路由信息:在标准路由属性之外存储业务相关数据
- 动态控制:实现基于元数据的条件路由
- 标记路由:为路由打上业务标签进行分类管理
常见配置方式
YAML 配置示例
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
metadata:
version: v2
env: production
rate-limit: 1000
Java DSL 配置示例
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("payment-service", r -> r.path("/api/payments/**")
.uri("lb://payment-service")
.metadata("security-level", "high")
.metadata("traceable", "true")
)
.build();
}
元数据使用场景
1. 动态路由控制
public class VersionRoutePredicateFactory extends AbstractRoutePredicateFactory<VersionRoutePredicateFactory.Config> {
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
// 从元数据获取版本信息
String routeVersion = exchange.getAttribute(GATEWAY_PREDICATE_ROUTE_ATTR)
.getMetadata().get("version");
// 与请求头中的版本比较
String clientVersion = exchange.getRequest()
.getHeaders().getFirst("X-API-Version");
return routeVersion.equals(clientVersion);
};
}
}
2. 限流配置传递
public class RateLimitFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
Integer limit = Integer.parseInt(route.getMetadata().get("rate-limit"));
// 应用限流逻辑...
}
}
注意事项
- 类型安全:元数据值都是String类型,需要自行转换
- 性能影响:避免存储过大元数据(建议<1KB)
- 访问控制:敏感信息不应放在元数据中
- 命名规范:建议使用小写+连字符的命名方式(如
x-api-version
)
高级用法
动态更新元数据
@RefreshScope
@Bean
public RouteDefinitionLocator dynamicRoutes() {
return () -> Flux.just(
new RouteDefinition() {{
setId("dynamic-route");
setUri(URI.create("lb://dynamic-service"));
setMetadata(Map.of("refresh-time", Instant.now().toString()));
// 其他配置...
}}
);
}
元数据继承
可通过自定义RouteDefinitionLocator
实现全局元数据的继承:
public class MetadataEnrichingLocator implements RouteDefinitionLocator {
private final RouteDefinitionLocator delegate;
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return delegate.getRouteDefinitions()
.map(definition -> {
definition.getMetadata().put("global-tag", "microservice");
return definition;
});
}
}
默认过滤器配置
概念定义
默认过滤器(Default Filters)是 Spring Cloud Gateway 中预定义的一组全局过滤器,会在所有路由请求上自动生效。这些过滤器提供了常见的网关功能,例如路径重写、请求头修改、负载均衡等。
核心默认过滤器
Spring Cloud Gateway 内置了以下常用默认过滤器:
- AddRequestHeader:添加请求头
- AddRequestParameter:添加请求参数
- AddResponseHeader:添加响应头
- DedupeResponseHeader:去除重复响应头
- PrefixPath:添加路径前缀
- PreserveHostHeader:保留主机头
- RemoveRequestHeader:移除请求头
- RemoveResponseHeader:移除响应头
- RewritePath:重写路径
- SetPath:设置路径
- SetRequestHeader:设置请求头
- SetResponseHeader:设置响应头
- SetStatus:设置响应状态码
配置方式
默认过滤器可以通过以下两种方式配置:
1. 配置文件方式(application.yml)
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=X-Request-Foo, Bar
- AddResponseHeader=X-Response-Foo, Bar
- PrefixPath=/api
2. Java 配置方式
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("example_route", r -> r.path("/example/**")
.filters(f -> f.addRequestHeader("X-Request-Foo", "Bar")
.addResponseHeader("X-Response-Foo", "Bar")
.prefixPath("/api"))
.uri("http://example.org"))
.build();
}
使用场景
- 统一添加安全头信息:为所有请求添加认证头
- API 版本控制:为所有请求添加路径前缀(如 /v1)
- 请求/响应修改:统一修改请求或响应内容
- 路径重写:将外部路径映射到内部微服务路径
注意事项
- 执行顺序:默认过滤器的执行顺序可以通过
order
属性控制 - 性能影响:过多的过滤器会增加请求处理时间
- 覆盖问题:后定义的过滤器会覆盖先定义的相同类型过滤器
- 调试困难:默认过滤器对所有路由生效,可能增加调试复杂度
示例:路径重写
spring:
cloud:
gateway:
default-filters:
- name: RewritePath
args:
regexp: /api/(?<segment>.*)
replacement: /$\{segment}
此配置会将 /api/users
重写为 /users
,适用于微服务架构中去除公共前缀的场景。
四、Predicate 断言配置
Path 路径匹配
概念定义
Path 路径匹配是 Gateway 网关中的核心路由规则之一,用于根据 HTTP 请求的 URL 路径(Path)决定请求应该被路由到哪个微服务。它通过定义特定的路径模式(如精确匹配、前缀匹配、正则匹配等)来实现请求的转发逻辑。
使用场景
- 微服务路由:将不同路径的请求路由到不同的后端服务(例如
/user/**
转发到用户服务)。 - 版本控制:通过路径区分 API 版本(如
/v1/order
和/v2/order
)。 - 静态资源代理:将特定路径(如
/static/**
)映射到静态资源服务器。 - 灰度发布:通过路径规则将部分流量导向新版本服务(如
/canary/**
)。
匹配模式
Gateway 支持以下常见路径匹配方式:
-
精确匹配
完全匹配指定路径,例如/api/user
仅匹配该路径。predicates: - Path=/api/user
-
通配符匹配
/**
:匹配任意多级路径(如/api/user/123
)。/*
:仅匹配一级路径(如/api/user
,但不匹配/api/user/123
)。
predicates: - Path=/api/**
-
正则表达式匹配
使用{regex}
语法,例如匹配数字 ID:predicates: - Path=/api/user/{id:\d+}
示例代码
以下是一个完整的 Spring Cloud Gateway 配置示例,展示多种 Path 匹配方式:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**, /api/profile/*
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/{version:v[1-9]}/{id:\d+}
- id: static-resources
uri: http://static-server
predicates:
- Path=/static/**
注意事项
-
匹配优先级
Gateway 按配置顺序匹配路由,第一个匹配成功的路由会被执行。应将更具体的路径(如/api/user/details
)放在通用路径(如/api/user/**
)之前。 -
路径重写
使用RewritePath
过滤器修改转发时的路径。例如移除前缀:filters: - RewritePath=/api/(?<segment>.*), /$\{segment}
-
编码问题
URL 中的特殊字符(如/
编码为%2F
)可能导致匹配失败,需确保路径解码一致性。 -
性能影响
复杂的正则表达式会增加匹配开销,尽量避免在高频路径中使用。 -
结尾斜杠
/api/user
和/api/user/
被视为不同路径,建议统一规范或使用重定向。
Method 请求方法匹配
概念定义
Method 请求方法匹配是 API 网关(如 Spring Cloud Gateway)中的一种路由断言(Predicate),用于根据 HTTP 请求方法(GET、POST、PUT、DELETE 等)来路由请求。网关会检查传入请求的 HTTP 方法,并与配置的方法进行匹配,只有匹配的请求才会被路由到指定的服务。
使用场景
- RESTful API 路由:根据不同的 HTTP 方法(如 GET、POST)将请求路由到不同的后端服务或处理逻辑。
- 方法限制:确保只有特定的 HTTP 方法(如 POST)才能访问某些敏感接口。
- 请求过滤:拦截不符合预期的 HTTP 方法(如禁用 PUT 或 DELETE 方法)。
配置示例(Spring Cloud Gateway)
以下是一个基于 YAML 的配置示例,展示如何根据 HTTP 方法匹配路由:
spring:
cloud:
gateway:
routes:
- id: method_route
uri: http://example.org
predicates:
- Method=GET,POST # 匹配 GET 或 POST 请求
代码示例(Java DSL)
如果使用 Java 代码配置路由,可以这样实现:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("method_route", r -> r
.method(HttpMethod.GET, HttpMethod.POST) // 匹配 GET 或 POST
.uri("http://example.org"))
.build();
}
注意事项
- 方法大小写敏感:HTTP 方法必须大写(如
GET
,不能写get
)。 - 多方法匹配:可以配置多个方法(如
Method=GET,POST
),用逗号分隔。 - 与其他断言结合:通常需要与其他断言(如 Path、Header)结合使用,以实现更精确的路由逻辑。
- 默认行为:如果不配置 Method 断言,网关会忽略 HTTP 方法,仅根据其他条件路由。
常见误区
- 忽略方法限制:未配置 Method 断言可能导致不安全的 HTTP 方法(如 DELETE)被意外允许。
- 拼写错误:错误拼写 HTTP 方法(如
METHD=GET
)会导致匹配失败。 - 过度匹配:仅依赖 Method 断言可能无法满足复杂路由需求,需结合其他断言使用。
通过合理配置 Method 请求方法匹配,可以增强 API 的安全性和可维护性。
Header 请求头匹配
概念定义
Header 请求头匹配是 API 网关(如 Spring Cloud Gateway)中的一种路由断言(Predicate)机制,用于根据 HTTP 请求头(Headers)中的键值对进行路由决策。网关会检查请求头是否满足预设的条件(如存在某个头、值匹配正则表达式等),从而决定是否将请求路由到指定的服务。
核心特性
- 精确匹配:检查请求头是否包含指定键值对(如
X-Request-Id=123
)。 - 正则匹配:支持通过正则表达式匹配头值(如
User-Agent~=curl.*
)。 - 存在性检查:仅验证请求头是否存在某个键(如
Authorization
)。
使用场景
- 版本控制:通过
Accept-Version
头路由到不同版本的微服务。predicates: - Header=Accept-Version, ^v2.*
- 灰度发布:根据
X-Traffic-Type
头将部分流量导到新服务。 - 认证拦截:验证
Authorization
头是否存在合法 JWT。 - 设备适配:按
User-Agent
头区分移动端/PC 端路由。
配置示例(YAML 格式)
spring:
cloud:
gateway:
routes:
- id: auth-service
uri: lb://auth-service
predicates:
- Header=X-Request-Type, Auth # 精确匹配
- Header=User-Agent, ~(Mobile|Android) # 正则匹配
Java DSL 配置
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("admin-route", r -> r.header("X-Role", "Admin")
.uri("lb://admin-service"))
.build();
}
常见误区
- 大小写敏感:HTTP 头键名通常不区分大小写,但部分网关实现可能敏感。
- 多值头处理:若头有多个值(如
Accept: json, xml
),需明确匹配逻辑。 - 性能影响:复杂正则表达式可能增加路由延迟。
高级技巧
- 负向匹配:通过
!
排除特定头。predicates: - Header=!X-Debug-Mode
- 默认值兜底:结合
Default
过滤器处理缺失头。 - 动态头匹配:通过
Metadata
实现动态路由规则。
调试建议
- 使用
curl -H "Header: Value"
快速测试。 - 开启网关的
DEBUG
日志查看头匹配过程:logging.level.org.springframework.cloud.gateway=DEBUG
Query 参数匹配
概念定义
Query 参数匹配是 API 网关(如 Spring Cloud Gateway)中用于根据 HTTP 请求的查询字符串(URL 中 ?
后的部分)进行路由判断的机制。它允许开发者通过配置规则,将请求路由到不同的后端服务或执行不同的逻辑。
使用场景
- 版本控制:通过
?version=v1
或?version=v2
路由到不同版本的服务。 - 灰度发布:根据
?env=canary
将部分流量导向新版本服务。 - 多租户隔离:通过
?tenant=companyA
路由到特定租户的后端。 - 调试路由:如
?debug=true
路由到调试服务。
配置语法(Spring Cloud Gateway 示例)
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://example.org
predicates:
- Query=foo, ba. # 匹配 foo=bar 或 foo=baz 等(正则)
- Query=baz # 仅要求存在 baz 参数,不校验值
匹配规则详解
-
精确匹配
- Query=param,value
:要求参数param
的值完全等于value
。- Query=color, red # 仅匹配 ?color=red
-
正则匹配
使用正则表达式(Java 语法)进行模糊匹配:- Query=id, \d+ # 匹配数字ID(如 ?id=123) - Query=code, A|B # 匹配 code=A 或 code=B
-
存在性匹配
仅检查参数是否存在,不校验值:- Query=debug # 匹配 ?debug 或 ?debug=true
注意事项
-
大小写敏感
参数名和值默认区分大小写,?Name=John
不匹配- Query=name, John
。 -
URL 编码问题
如果参数值包含特殊字符(如空格、=
),需确保客户端正确编码:原始请求:?filter=price>100 正确编码:?filter=price%3E100
-
多值参数处理
对于?color=red&color=blue
这类多值参数:- 正则匹配会检查所有值(任一匹配即通过)
- 精确匹配需完全一致(极少使用)
-
性能影响
复杂正则表达式可能增加路由计算开销,建议:- 优先使用精确匹配
- 避免
.*
这种宽泛正则
高级示例
routes:
- id: multi_param_route
uri: http://service-v2
predicates:
- Query=version, v[1-9] # 版本号 v1~v9
- Query=!beta # 不能有 beta 参数
- Query=token, ^.+$ # token 必须有值
常见误区
-
混淆 Path 和 Query
# 错误:试图用 Path 匹配查询参数 - Path=/api?foo=bar # 无效! # 正确: - Path=/api - Query=foo, bar
-
忽略参数顺序
?a=1&b=2
和?b=2&a=1
会被视为相同,无需特殊处理。 -
过度依赖 Query 路由
对于重要路由决策,建议:- 优先使用 Path 或 Header
- Query 参数适合非关键路由(如调试、可选功能)
Cookie 匹配
概念定义
Cookie 匹配是指在网关(Gateway)层面对请求中的 Cookie 进行解析、验证或过滤的过程。网关可以通过 Cookie 中的特定字段(如 sessionId
、token
或其他自定义字段)来判断请求的合法性、用户身份或其他业务逻辑。Cookie 匹配通常用于权限控制、会话管理、负载均衡等场景。
使用场景
- 会话管理:通过匹配 Cookie 中的
sessionId
或token
来验证用户是否已登录。 - 权限控制:根据 Cookie 中的角色或权限字段,限制用户访问某些接口或资源。
- 灰度发布:通过 Cookie 中的
version
或group
字段,将用户路由到不同版本的微服务。 - 多租户隔离:通过 Cookie 中的
tenantId
字段,实现租户数据的隔离。
常见误区或注意事项
- Cookie 安全性:Cookie 可能被篡改或伪造,建议结合加密或签名机制(如 JWT)使用。
- 性能问题:频繁解析 Cookie 可能增加网关的 CPU 负载,需合理设计匹配规则。
- 跨域问题:如果网关和前端域名不同,需配置
SameSite
和CORS
策略。 - Cookie 大小限制:单个 Cookie 通常不超过 4KB,避免存储过多数据。
示例代码(基于 Spring Cloud Gateway)
以下是一个通过 Cookie 匹配实现路由过滤的示例:
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
public class CookieMatchFilter extends AbstractGatewayFilterFactory<CookieMatchFilter.Config> {
public CookieMatchFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 获取名为 "token" 的 Cookie
String token = request.getCookies().getFirst("token") != null
? request.getCookies().getFirst("token").getValue()
: null;
if (token == null || !isValidToken(token)) {
// 如果 Cookie 无效,返回 401 未授权
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
};
}
private boolean isValidToken(String token) {
// 实际业务中需验证 token 合法性(如 JWT 校验)
return token.startsWith("valid_");
}
public static class Config {
// 可配置的过滤参数(如 Cookie 名称、预期值等)
}
}
配置路由规则
在 application.yml
中配置网关路由,使用自定义的 CookieMatchFilter
:
spring:
cloud:
gateway:
routes:
- id: auth-service
uri: lb://auth-service
predicates:
- Path=/api/auth/**
filters:
- name: CookieMatchFilter
通过以上方式,网关可以基于 Cookie 实现灵活的请求控制。
Host 主机名匹配
概念定义
Host 主机名匹配是 API 网关(如 Spring Cloud Gateway)中的一种路由断言(Predicate),用于根据 HTTP 请求头中的 Host
字段来匹配路由规则。当客户端发送请求时,网关会检查请求头中的 Host
值是否与配置的主机名规则匹配,从而决定是否将请求路由到对应的服务。
使用场景
- 多租户系统:根据不同的域名将请求路由到不同的服务实例。
- 环境隔离:通过不同的主机名(如
dev.example.com
、prod.example.com
)区分开发环境和生产环境。 - 自定义域名:为不同的服务配置独立的域名,提升用户体验。
配置方式
在 Spring Cloud Gateway 中,可以通过 YAML 或 Java 代码配置 Host 主机名匹配规则。
YAML 配置示例
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://example-service
predicates:
- Host=example.com,*.example.org
Java 代码配置示例
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("host_route", r -> r.host("example.com", "*.example.org")
.uri("http://example-service"))
.build();
}
匹配规则
- 精确匹配:如
example.com
,仅匹配该域名。 - 通配符匹配:如
*.example.org
,匹配所有以.example.org
结尾的子域名(如api.example.org
、test.example.org
)。 - 多值匹配:可以配置多个主机名,用逗号分隔(如
example.com,*.example.org
)。
注意事项
- 区分大小写:Host 匹配默认是区分大小写的,需确保配置与请求头完全一致。
- 端口问题:如果请求中包含端口(如
example.com:8080
),需在配置中显式指定端口或使用通配符。 - 优先级:如果多个路由规则匹配同一个 Host,网关会根据路由定义的顺序选择第一个匹配的路由。
- 通配符位置:通配符
*
只能用于子域名部分(如*.example.com
),不能用于顶级域名(如example.*
是无效的)。
示例请求
假设配置了 Host=api.example.com
,以下请求会匹配成功:
GET /resource HTTP/1.1
Host: api.example.com
以下请求不会匹配:
GET /resource HTTP/1.1
Host: example.com
常见误区
- 忽略端口:未在 Host 配置中包含端口号,导致
example.com:8080
无法匹配example.com
。 - 过度依赖通配符:滥用
*
可能导致路由规则过于宽松,引发安全问题。 - 未测试大小写:未验证大小写敏感性,导致生产环境因域名大小写不一致而路由失败。
时间相关断言
概念定义
时间相关断言(Time-based Predicates)是 API 网关中用于根据时间条件进行路由判断的规则配置。它允许开发者基于当前时间、日期或时间段来控制请求的路由行为,常用于实现限时活动、维护窗口、节假日特殊逻辑等场景。
核心断言类型
-
After Route Predicate
仅在指定时间戳之后生效:- After=2025-01-20T17:42:47.789-05:00[America/New_York]
-
Before Route Predicate
仅在指定时间戳之前生效:- Before=2024-12-31T23:59:59.999+08:00[Asia/Shanghai]
-
Between Route Predicate
在时间区间内生效(包含边界):- Between=2024-10-01T00:00:00.000+08:00[Asia/Shanghai], 2024-10-07T23:59:59.999+08:00[Asia/Shanghai]
时间格式规范
- 必须符合
java.time.ZonedDateTime
格式 - 建议包含时区(如
[Asia/Shanghai]
) - 示例格式:
yyyy-MM-dd'T'HH:mm:ss.SSSZZ[时区]
使用场景
-
灰度发布控制
在特定时间段内将流量路由到新版本服务:- id: canary-release uri: lb://new-service predicates: - Path=/api/v2/** - Between=2024-09-01T09:00:00+08:00, 2024-09-30T18:00:00+08:00
-
系统维护拦截
维护期间返回统一提示:- id: maintenance uri: lb://maintenance-service predicates: - After=2024-12-25T00:00:00+08:00 - Before=2024-12-25T06:00:00+08:00
-
节假日特殊路由
春节期间的业务逻辑隔离:// 动态计算春节日期 ZoneId zone = ZoneId.of("Asia/Shanghai"); ZonedDateTime springFestivalStart = ZonedDateTime.of(2025,1,28,0,0,0,0,zone);
注意事项
-
时区陷阱
未显式指定时区时默认使用系统时区,可能导致生产环境与本地测试不一致:# 错误示例(隐式依赖系统时区) - After=2024-08-01T00:00:00
-
时间同步问题
确保网关服务器时间准确,推荐使用NTP服务同步时间 -
夏令时影响
对于实行夏令时的地区(如欧美),需要特别处理时间跳变 -
性能考虑
高频调用的网关应避免使用Between
等需要实时时间计算的断言
动态时间配置
结合配置中心实现动态时间规则(以Nacos为例):
spring:
cloud:
gateway:
routes:
- id: dynamic-time
uri: lb://special-service
predicates:
- name: After
args:
datetime: ${nacos.config.time-rule}
调试技巧
-
使用
curl
测试时强制指定时区:curl -H "X-Forwarded-For: 1.2.3.4" \ -H "Time-Zone: Asia/Shanghai" \ http://gateway/api
-
在日志中输出时区信息:
@Bean public GlobalFilter timeLogFilter() { return (exchange, chain) -> { log.info("Current zone: {}", ZonedDateTime.now().getZone()); return chain.filter(exchange); }; }
失效场景处理
当时间断言失效时(如系统时间异常),建议:
- 添加默认路由作为fallback
- 实现健康检查接口验证时间服务
- 监控时间断言匹配率指标
自定义断言实现
概念定义
自定义断言(Custom Predicate)是 Spring Cloud Gateway 中用于扩展路由匹配条件的机制。通过实现 Predicate
接口或继承 AbstractRoutePredicateFactory
类,开发者可以定义自己的路由匹配规则,实现更灵活的请求过滤逻辑。
使用场景
- 需要基于业务参数(如 header、body 内容)进行路由
- 实现复杂的多条件组合路由逻辑
- 需要动态配置的路由规则(如灰度发布)
- 特殊协议或自定义协议的请求过滤
实现步骤
1. 继承 AbstractRoutePredicateFactory
public class CustomHeaderPredicateFactory extends AbstractRoutePredicateFactory<CustomHeaderPredicateFactory.Config> {
public CustomHeaderPredicateFactory() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
// 实现断言逻辑
String headerValue = exchange.getRequest()
.getHeaders()
.getFirst(config.getHeaderName());
return config.getExpectedValue().equals(headerValue);
};
}
// 配置类
public static class Config {
private String headerName;
private String expectedValue;
// getters and setters
}
}
2. 注册为 Spring Bean
@Configuration
public class GatewayConfig {
@Bean
public CustomHeaderPredicateFactory customHeaderPredicateFactory() {
return new CustomHeaderPredicateFactory();
}
}
3. 在配置文件中使用
spring:
cloud:
gateway:
routes:
- id: custom_route
uri: http://example.org
predicates:
- name: CustomHeader
args:
headerName: X-Custom-Header
expectedValue: special-value
高级实现技巧
支持快捷配置
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("headerName", "expectedValue");
}
支持验证配置
@Override
public void validate(Config config) {
if (config.getHeaderName() == null) {
throw new IllegalArgumentException("headerName is required");
}
}
注意事项
- 线程安全:断言实现必须是无状态的且线程安全
- 性能考虑:避免在断言中执行耗时操作(如数据库查询)
- 配置验证:务必验证配置参数的有效性
- 短路逻辑:对于可能快速失败的检查应放在前面
- 日志记录:适当添加调试日志,但避免高频日志输出
示例:时间范围断言
public class TimeBetweenPredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenPredicateFactory.Config> {
public TimeBetweenPredicateFactory() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
LocalTime now = LocalTime.now();
return !now.isBefore(config.getStart()) && !now.isAfter(config.getEnd());
};
}
public static class Config {
private LocalTime start;
private LocalTime end;
// getters and setters
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("start", "end");
}
}
五、Filter 过滤器配置
请求头过滤器(AddRequestHeader GatewayFilter)
概念定义
请求头过滤器是Spring Cloud Gateway中的一种内置过滤器,用于在请求转发到下游服务前,向HTTP请求头中添加指定的键值对。该过滤器属于GatewayFilter
接口的实现类,作用于单个路由配置。
核心功能
- 动态修改请求:在网关层面统一添加业务所需的请求头
- 协议转换:如为下游服务添加
X-Forwarded-Proto
等标准头 - 身份透传:传递认证信息(如JWT Token)到微服务
配置语法
spring:
cloud:
gateway:
routes:
- id: demo_route
uri: lb://service-name
filters:
- AddRequestHeader=X-Request-Color, Blue
- AddRequestHeader=Trace-Id, 123e4567-e89b-12d3
参数说明
参数格式 | 说明 |
---|---|
AddRequestHeader=<header_name>, <header_value> | 头名称和值支持占位符表达式 |
{regexp} | 可使用${...} 获取变量(如路径变量) |
动态值示例
filters:
- AddRequestHeader=X-User-Id, ${user.id} # 从上下文获取
- AddRequestHeader=Version, v1.${segment} # 组合路径参数
常见使用场景
- 全链路追踪:添加
Trace-Id
等分布式追踪标识- AddRequestHeader=Sleuth-Trace-Id, ${traceId}
- 灰度发布:通过
Version
头实现流量染色- AddRequestHeader=X-Request-Version, v2.1
- 跨服务认证:传递解密后的用户信息
- AddRequestHeader=X-User-Info, ${user.claims}
注意事项
- 头名称规范:建议使用
X-
前缀的自定义头(RFC 6648) - 值安全性:敏感信息需加密后传递
- 覆盖风险:与下游服务已有头冲突时会覆盖原值
- 性能影响:过多过滤器会增加网关处理延迟
调试技巧
- 通过
/actuator/gateway/routefilters
端点验证配置 - 在全局过滤器中使用
ServerWebExchange
检查头信息:exchange.getRequest().getHeaders().forEach((k,v) -> log.debug(k + "=" + v));
与相关过滤器对比
过滤器类型 | 功能差异 |
---|---|
SetRequestHeader | 会覆盖同名头 |
AddResponseHeader | 操作响应头而非请求头 |
RemoveRequestHeader | 删除指定请求头 |
添加响应头过滤器
概念定义
响应头过滤器(AddResponseHeader Filter)是 API 网关中用于在响应返回给客户端之前,向 HTTP 响应头中添加自定义头部信息的组件。它属于 Gateway Filter 的一种,通常用于添加跨域支持、安全策略、版本信息等通用响应头。
使用场景
- 跨域支持:添加
Access-Control-Allow-*
系列头部 - 安全加固:添加
X-Content-Type-Options
、X-Frame-Options
等安全头 - 版本标识:添加
X-API-Version
等自定义版本信息 - 缓存控制:添加
Cache-Control
等缓存相关头部 - 追踪信息:添加请求链路追踪 ID
配置方式(YAML示例)
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- AddResponseHeader=X-Response-Red, Blue
- AddResponseHeader=Cache-Control, max-age=3600
Java DSL 配置示例
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("product-service", r -> r.path("/api/products/**")
.filters(f -> f.addResponseHeader("X-API-Version", "v1")
.addResponseHeader("X-Custom-Header", "Gateway"))
.uri("lb://product-service"))
.build();
}
动态添加头部
可以通过自定义过滤器实现动态值:
public class VersionHeaderFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("X-API-Version", getCurrentVersion());
}));
}
private String getCurrentVersion() {
// 实现版本获取逻辑
return "2.1.0";
}
}
注意事项
- 头部覆盖:如果响应已包含同名字段,默认行为是追加而非覆盖
- 性能影响:过多响应头会增加网络传输开销
- 敏感信息:避免在响应头中添加敏感数据
- 大小写敏感:HTTP 头部名称通常不区分大小写,但建议保持一致性
- 特殊字符:值中包含逗号等特殊字符时需要正确处理
常见问题解决
- 头部未生效:检查过滤器顺序,确保没有后续过滤器覆盖了头部
- 中文乱码:对非ASCII字符进行URL编码
- 动态值失效:确保在响应提交前(
then
阶段)添加头部
高级用法
可以结合配置中心实现动态配置:
filters:
- name: AddResponseHeader
args:
name: X-Env
value: ${spring.profiles.active}
安全相关最佳实践
filters:
- AddResponseHeader=Strict-Transport-Security, max-age=31536000 ; includeSubDomains
- AddResponseHeader=X-Content-Type-Options, nosniff
- AddResponseHeader=X-Frame-Options, DENY
- AddResponseHeader=X-XSS-Protection, 1; mode=block
重写路径过滤器
概念定义
重写路径过滤器(RewritePath Filter)是 API 网关(如 Spring Cloud Gateway)中的一个核心过滤器组件,用于在请求转发到下游服务之前,动态修改请求的路径。它通过正则表达式匹配原始路径,并按照预设规则生成新的目标路径。
核心作用
- 路径转换:将客户端请求的路径转换为后端服务实际需要的路径格式。
- 版本兼容:实现 API 版本的无缝升级(如
/v1/api
→/api
)。 - 路径隐藏:隐藏后端服务的真实路径结构,增强安全性。
配置语法(Spring Cloud Gateway 示例)
spring:
cloud:
gateway:
routes:
- id: rewrite_path_route
uri: http://backend-service
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}
参数详解
参数 | 说明 |
---|---|
/foo/(.*) | 正则表达式捕获组,匹配以 /foo/ 开头的路径 |
/${segment} | 替换模板,${segment} 引用正则捕获组,最终路径移除 /foo 前缀 |
典型使用场景
场景 1:去除路径前缀
原始请求:/api/user-service/users
目标服务路径:/users
filters:
- RewritePath=/api/user-service/(?<path>.*), /$\{path}
场景 2:多版本 API 支持
客户端请求:/v2/products
实际服务路径:/products
filters:
- RewritePath=/v(?<version>\d+)/(?<path>.*), /$\{path}
注意事项
- 正则表达式性能:复杂正则可能影响网关性能,建议使用简单明确的模式。
- 捕获组命名:推荐使用命名捕获组(如
(?<name>pattern)
)提升可读性。 - 斜杠处理:注意路径开头是否需要保留
/
,错误的正则可能导致 404。 - 测试验证:使用
curl
或 Postman 严格测试路径改写结果。
高级用法示例
# 同时处理多个路径模式
filters:
- RewritePath=/old-api/(?<svc>[^/]+)/(?<rest>.*), /$\{svc}/api/$\{rest}
- RewritePath=/legacy/(?<path>.*), /modern/$\{path}
常见问题排查
- 改写未生效:检查正则是否匹配成功,可通过
logging.level.org.springframework.cloud.gateway=DEBUG
开启调试日志。 - 404 错误:确认目标服务是否存在改写后的路径。
- 特殊字符转义:路径中的
$
、{
等字符需要正确转义。
与其他过滤器的协作
可与以下过滤器链式使用:
PrefixPath
:在改写后添加统一前缀StripPrefix
:移除固定层级的路径前缀SetPath
:完全覆盖路径(非正则方式)
重试过滤器
概念定义
重试过滤器(Retry Filter)是 API 网关(如 Spring Cloud Gateway)中的一种机制,用于在请求失败时自动重试。它通过拦截请求和响应,在特定条件下(如网络超时、服务不可用等)重新发送请求,以提高系统的容错性和可用性。
使用场景
- 服务暂时不可用:当目标服务因短暂故障(如网络抖动、服务重启)不可用时,重试可以避免直接返回错误。
- 高并发场景:在流量突增时,服务可能因资源不足短暂超时,重试可以缓解瞬时压力。
- 依赖服务不稳定:对于依赖的第三方服务,重试可以掩盖其不稳定性。
核心配置参数
在 Spring Cloud Gateway 中,重试过滤器通常通过 RetryGatewayFilterFactory
配置,主要参数包括:
retries
:最大重试次数。statuses
:触发重试的 HTTP 状态码(如5xx
)。methods
:支持重试的 HTTP 方法(如GET
)。series
:触发重试的状态码系列(如SERVER_ERROR
)。exceptions
:触发重试的异常类型(如TimeoutException
)。backoff
:退避策略(如指数退避)。
示例代码
# application.yml 配置示例
spring:
cloud:
gateway:
routes:
- id: retry_route
uri: http://example.com
predicates:
- Path=/api/**
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY, SERVICE_UNAVAILABLE
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 1000ms
factor: 2
basedOnPreviousValue: false
注意事项
- 幂等性:仅对幂等操作(如
GET
)启用重试,避免非幂等操作(如POST
)因重试导致数据不一致。 - 超时设置:重试会延长总请求时间,需合理设置全局超时和重试间隔。
- 资源消耗:频繁重试可能加剧服务负载,需结合熔断机制(如 Hystrix)使用。
- 异常类型:明确配置需要重试的异常(如
ConnectTimeoutException
),避免重试无效错误。
底层原理
- 过滤器链:重试过滤器在
GatewayFilterChain
中拦截请求,捕获异常后触发重试逻辑。 - 重试上下文:通过
RetryContext
记录当前重试次数和退避时间。 - 响应检查:根据配置的
statuses
或exceptions
决定是否重试。
高级配置
// 通过 Java DSL 配置重试过滤器
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("retry_route", r -> r.path("/api/**")
.filters(f -> f.retry(config -> config
.setRetries(3)
.setStatuses(HttpStatus.INTERNAL_SERVER_ERROR)
.setMethods(HttpMethod.GET)
.setBackoff(50, 1000, 2, true))
.uri("http://example.com"))
.build();
}
请求限流过滤器
概念定义
请求限流过滤器(Request Rate Limiting Filter)是API网关中的一种核心过滤器,用于控制单位时间内通过网关的请求流量,防止后端服务因突发流量过载而崩溃。它基于令牌桶、漏桶等算法实现流量整形,通常以QPS(每秒查询数)或并发连接数为限制维度。
核心算法实现
1. 令牌桶算法
// 伪代码示例
public class TokenBucket {
private final int capacity; // 桶容量
private double tokens; // 当前令牌数
private long lastTime; // 上次补充时间
public synchronized boolean tryAcquire() {
refillTokens(); // 补充令牌
if (tokens >= 1) {
tokens--;
return true;
}
return false;
}
}
2. 漏桶算法
public class LeakyBucket {
private final long capacity; // 桶容量
private long water = 0; // 当前水量
private long lastLeakTime; // 上次漏水时间
public synchronized boolean tryConsume() {
leakWater(); // 漏水处理
if (water < capacity) {
water++;
return true;
}
return false;
}
}
配置示例(Spring Cloud Gateway)
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100 # 每秒补充令牌数
redis-rate-limiter.burstCapacity: 200 # 令牌桶总容量
key-resolver: "#{@ipKeyResolver}" # 限流维度
常见限流维度
维度类型 | 适用场景 | 示例KeyResolver实现 |
---|---|---|
IP地址 | 防止单IP攻击 | exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostString()) |
用户ID | 限制单个用户访问频率 | 从JWT或Session提取用户ID |
接口路径 | 保护特定高负载接口 | 根据请求路径动态生成Key |
业务参数 | 如手机号、商品ID等特殊维度限制 | 从请求参数/Header提取特定值 |
高级配置技巧
- 分级限流:对VIP用户设置更高限流阈值
@Bean
KeyResolver customKeyResolver() {
return exchange -> {
String userLevel = exchange.getRequest()
.getHeaders()
.getFirst("X-User-Level");
return Mono.just(userLevel != null ? userLevel : "DEFAULT");
};
}
- 动态规则:结合配置中心实现热更新
@RefreshScope
@Bean
public RateLimiterConfig rateLimiterConfig() {
// 从Nacos/Apollo读取配置
}
注意事项
- 雪崩效应:被限流的请求应返回429状态码,而非直接丢弃
- 分布式一致性:Redis集群模式下注意RedLock等分布式锁方案
- 预热模式:突发流量场景可使用Guava RateLimiter的warmupPeriod参数
- 监控埋点:需记录限流触发日志并接入告警系统
性能优化建议
- 使用Lua脚本保证Redis操作的原子性
- 对静态资源路由禁用限流过滤器
- 本地缓存+分布式限流的混合模式
// 二级缓存示例
public boolean allowRequest(String key) {
if (localCache.allow(key)) { // 本地检查
return redisLimiter.allow(key); // 分布式检查
}
return false;
}
熔断降级联动
当限流触发时,可结合Hystrix或Sentinel执行预定义的降级策略:
.filter(new RequestRateLimiterGatewayFilterFactory()
.apply(c -> c.setRateLimiter(redisRateLimiter())
.setDenyEmptyKey(false))
.filter(new HystrixGatewayFilterFactory()
.apply(c -> c.setName("fallbackCmd")
.setFallbackUri("forward:/fallback")))
熔断过滤器
概念定义
熔断过滤器(Circuit Breaker Filter)是 API 网关中的一种关键组件,用于在微服务架构中防止系统级联故障。其核心思想借鉴电路保险丝机制:当后端服务出现异常(如超时、高错误率)时,自动切断请求链路,避免资源耗尽,并快速返回降级响应。
核心功能
- 故障检测:监控请求失败率、响应时间等指标
- 熔断触发:达到阈值时自动打开熔断器
- 快速失败:熔断期间直接拒绝请求
- 自动恢复:定期尝试探测服务可用性
- 降级处理:返回预设的fallback响应
常见实现指标
指标类型 | 说明 | 典型阈值 |
---|---|---|
错误率 | HTTP 5xx错误比例 | >50%(10秒窗口) |
慢调用比例 | 超过设定响应时间的请求比例 | >80%(1秒阈值) |
最小请求数 | 触发统计的最低请求量 | 5次/10秒 |
Spring Cloud Gateway 配置示例
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: CircuitBreaker
args:
name: userCircuitBreaker
fallbackUri: forward:/fallback/user
statusCodes: 500,502,503
Resilience4j 熔断器配置
@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultConfig() {
return factory -> factory.configureDefault(id -> new CircuitBreakerConfig.Builder()
.failureRateThreshold(50) // 错误率阈值%
.slowCallRateThreshold(80) // 慢调用阈值%
.waitDurationInOpenState(Duration.ofSeconds(30)) // 熔断持续时间
.build());
}
典型使用场景
- 第三方服务不可用时的快速失败
- 数据库连接池耗尽保护
- 突发流量下的服务自我保护
- 微服务雪崩效应预防
注意事项
- 阈值设置:需根据实际业务调整,过高导致保护不足,过低影响正常业务
- 熔断粒度:建议按API维度而非服务维度熔断
- 降级策略:fallback响应应包含足够上下文信息
- 监控对接:需与Prometheus等监控系统集成
- 测试验证:通过Chaos Engineering验证熔断有效性
高级配置技巧
// 自定义熔断事件处理器
CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults();
registry.getEventPublisher()
.onStateTransition(event -> {
if (event.getStateTransition() == StateTransition.CLOSED_TO_OPEN) {
log.warn("服务熔断触发:{}", event.getCircuitBreakerName());
}
});
常见误区
- 忽略慢调用:仅监控错误率而忽视响应延迟
- 全局熔断:未区分重要/非重要接口
- 恢复策略不当:直接切换回CLOSED状态而非HALF_OPEN
- 日志缺失:未记录熔断事件影响问题排查
- 测试不足:未在生产前验证熔断配置
请求/响应日志过滤器
概念定义
请求/响应日志过滤器(Request/Response Logging Filter)是网关中用于记录HTTP请求和响应详细信息的组件。它通常作为全局过滤器或路由过滤器存在,用于捕获经过网关的所有流量数据。
核心功能
-
请求日志记录:
- HTTP方法(GET/POST等)
- 请求路径
- 请求头信息
- 查询参数
- 请求体内容(需注意敏感信息过滤)
-
响应日志记录:
- 响应状态码
- 响应头信息
- 响应体内容(可配置截断长度)
实现方式(Spring Cloud Gateway示例)
基础日志过滤器
@Component
public class LoggingFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(LoggingFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 请求日志
ServerHttpRequest request = exchange.getRequest();
log.info("Request: {} {} from {}",
request.getMethod(),
request.getPath(),
request.getRemoteAddress());
// 响应日志
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
log.info("Response: {} with status {}",
request.getPath(),
response.getStatusCode());
}));
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
增强版(带请求体记录)
public class RequestResponseLoggingFilter extends AbstractGatewayFilterFactory<Object> {
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
// 请求日志
logRequest(exchange.getRequest());
// 支持重复读取请求体
ServerHttpRequest decoratedRequest = logRequestBody(exchange.getRequest());
return chain.filter(exchange.mutate().request(decoratedRequest).build())
.then(Mono.fromRunnable(() ->
logResponse(exchange.getResponse())
));
};
}
private void logRequest(ServerHttpRequest request) {
// 实现请求日志记录逻辑
}
private ServerHttpRequest logRequestBody(ServerHttpRequest request) {
// 实现请求体缓存和记录逻辑
return new CachingRequestBodyServerHttpRequest(request);
}
private void logResponse(ServerHttpResponse response) {
// 实现响应日志记录逻辑
}
}
最佳实践
-
敏感信息过滤:
// 在日志输出前过滤敏感头字段 private Map<String, String> filterHeaders(HttpHeaders headers) { return headers.entrySet().stream() .filter(entry -> !SENSITIVE_HEADERS.contains(entry.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, entry -> String.join(",", entry.getValue()))); }
-
性能优化:
- 异步日志记录
- 限制日志体大小
- 采样率控制(如只记录10%的请求)
-
日志格式标准化:
{ "timestamp": "2023-01-01T12:00:00Z", "type": "gateway", "request": { "method": "POST", "path": "/api/users", "headers": {...} }, "response": { "status": 200, "timeMs": 45 } }
常见问题处理
-
大文件请求:
- 添加body大小检查
- 对multipart/form-data特殊处理
-
二进制内容:
if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) { log.debug("Binary content omitted"); return; }
-
日志风暴:
- 使用RateLimiter限制日志频率
- 关键路径与非关键路径分离记录
监控集成
可与以下系统集成:
- ELK日志系统
- Prometheus指标收集
- 分布式追踪系统(如Zipkin)
// 与Micrometer指标集成示例
Metrics.timer("gateway.requests")
.tag("path", request.getPath().value())
.record(() -> chain.filter(exchange));
自定义过滤器实现
概念定义
自定义过滤器(Custom Filter)是 Gateway 网关中用于对请求和响应进行自定义处理的组件。开发者可以通过实现特定的接口或继承抽象类,编写自己的业务逻辑,例如权限验证、日志记录、请求参数修改等。
使用场景
- 权限验证:检查请求头中的 Token 是否有效
- 日志记录:记录请求和响应的详细信息
- 请求/响应修改:添加或删除请求头/参数
- 流量控制:实现限流、熔断等功能
- 数据转换:修改请求体或响应体的数据格式
实现方式
1. 实现 GatewayFilter 接口
@Component
public class CustomGatewayFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 前置处理逻辑
System.out.println("Pre-filter logic: " + exchange.getRequest().getPath());
// 继续执行过滤器链
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 后置处理逻辑
System.out.println("Post-filter logic: " + exchange.getResponse().getStatusCode());
}));
}
}
2. 继承 AbstractGatewayFilterFactory
@Component
public class CustomFilterFactory extends AbstractGatewayFilterFactory<CustomFilterFactory.Config> {
public CustomFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 使用配置参数
if (config.isEnabled()) {
// 过滤逻辑
System.out.println("Custom filter is enabled");
}
return chain.filter(exchange);
};
}
public static class Config {
private boolean enabled;
// getters and setters
}
}
配置方式
1. 通过代码配置
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("custom_route", r -> r.path("/api/**")
.filters(f -> f.filter(new CustomGatewayFilter()))
.uri("http://localhost:8080"))
.build();
}
2. 通过配置文件(application.yml)
spring:
cloud:
gateway:
routes:
- id: custom_route
uri: http://localhost:8080
predicates:
- Path=/api/**
filters:
- name: CustomFilterFactory
args:
enabled: true
执行顺序控制
可以通过实现 Ordered
接口或使用 @Order
注解来控制过滤器的执行顺序:
@Component
public class OrderedFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 过滤逻辑
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 数字越小优先级越高
}
}
常见注意事项
- 线程安全:确保过滤器中的逻辑是线程安全的
- 性能影响:避免在过滤器中执行耗时操作
- 异常处理:妥善处理可能出现的异常,避免影响正常请求
- 响应修改:注意响应可能已经被提交的情况
- 配置验证:对自定义过滤器的配置参数进行有效性验证
示例:认证过滤器
@Component
public class AuthFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !isValidToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
private boolean isValidToken(String token) {
// 实现实际的token验证逻辑
return true;
}
}
六、Gateway 高级配置
全局过滤器配置
概念定义
全局过滤器(Global Filter)是 Spring Cloud Gateway 中的一种核心组件,它会对所有路由请求生效,无需针对特定路由进行配置。全局过滤器在请求进入网关时执行,可以用于实现统一的逻辑处理,如认证、日志记录、请求修改等。
使用场景
- 统一认证鉴权:验证所有请求的 Token 或权限
- 全局日志记录:记录所有请求的入参、响应时间等
- 请求/响应修改:统一添加请求头、修改响应内容
- 流量监控:统计请求量、异常请求等
- 防重放攻击:检查请求时间戳或 Nonce
配置方式
1. 通过代码配置
@Configuration
public class GlobalFilterConfig {
@Bean
@Order(-1) // 执行顺序,值越小优先级越高
public GlobalFilter customGlobalFilter() {
return (exchange, chain) -> {
// 前置处理
ServerHttpRequest request = exchange.getRequest()
.mutate()
.header("X-Global-Filter", "activated")
.build();
// 记录请求开始时间
long startTime = System.currentTimeMillis();
return chain.filter(exchange.mutate().request(request).build())
.then(Mono.fromRunnable(() -> {
// 后置处理
long duration = System.currentTimeMillis() - startTime;
System.out.println(
"Request to " + request.getURI() +
" took " + duration + "ms");
}));
};
}
}
2. 通过配置文件配置(部分功能)
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=X-Request-Foo, Bar
- AddResponseHeader=X-Response-Foo, Bar
执行顺序控制
- 通过
@Order
注解指定顺序 - 实现
Ordered
接口的getOrder()
方法 - 默认顺序为
0
,值越小优先级越高
常见内置全局过滤器
过滤器名称 | 功能描述 |
---|---|
NettyWriteResponseFilter | 处理响应写入 |
ForwardPathFilter | 处理转发请求 |
RouteToRequestUrlFilter | 路由URL转换 |
LoadBalancerClientFilter | 负载均衡处理 |
注意事项
- 性能影响:全局过滤器会对所有请求生效,需确保逻辑高效
- 异常处理:建议在过滤器中捕获异常并转换为统一错误响应
- 顺序依赖:注意过滤器之间的执行顺序依赖关系
- 资源释放:使用 Reactor 编程时注意资源的正确释放
- 调试困难:多个全局过滤器叠加时,建议添加 traceId 便于日志追踪
高级示例:认证过滤器
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest()
.getHeaders()
.getFirst("Authorization");
if (!validateToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
private boolean validateToken(String token) {
// 实现实际的token验证逻辑
return token != null && token.startsWith("Bearer ");
}
@Override
public int getOrder() {
return -100; // 高优先级
}
}
与路由过滤器的区别
特性 | 全局过滤器 | 路由过滤器 |
---|---|---|
作用范围 | 所有路由 | 特定路由 |
配置方式 | 编程式 | 声明式/编程式 |
执行顺序 | 可通过@Order控制 | 在路由定义中指定顺序 |
典型用途 | 跨切面关注点 | 路由特定处理 |
过滤器执行顺序控制
概念定义
在 Gateway 网关中,过滤器(Filter)是处理请求和响应的核心组件。过滤器执行顺序控制指的是通过特定机制来管理和调整过滤器的执行顺序,以确保请求按照预期的流程进行处理。
为什么需要控制执行顺序
- 依赖关系:某些过滤器需要在其他过滤器之前或之后执行(如认证过滤器通常需要在业务逻辑过滤器之前执行)
- 功能完整性:确保关键处理(如日志记录、权限校验)不被跳过
- 性能优化:将高开销的过滤器放在合适的位置
Spring Cloud Gateway 的执行顺序机制
Spring Cloud Gateway 提供了两种主要的顺序控制方式:
1. 通过 Ordered 接口控制
public class AuthFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 过滤逻辑
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 数字越小优先级越高
}
}
2. 通过配置文件的 order 属性控制
spring:
cloud:
gateway:
routes:
- id: my_route
uri: http://example.org
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
order: -2
- name: AddRequestHeader
args:
name: X-Request-Foo
value: Bar
order: -1
执行顺序规则
- 全局过滤器(GlobalFilter)和路由过滤器(GatewayFilter)统一排序
- 按 order 值从小到大依次执行
- 默认 order 值为 0
- 相同 order 值的过滤器执行顺序不确定
常见误区
-
认为路由配置中的顺序就是执行顺序:
- 实际执行顺序由 order 值决定,不是配置文件的书写顺序
-
忽略默认 order 值:
- 未显式设置 order 的过滤器默认为 0,可能导致意外顺序
-
过度依赖负值:
- 大量使用负值可能导致维护困难,建议建立清晰的顺序规范
最佳实践
-
建立明确的 order 值规范,例如:
- 安全相关:-100 到 -50
- 日志记录:-49 到 0
- 业务处理:1 及以上
-
使用枚举或常量管理 order 值:
public interface FilterOrders {
int AUTH = -100;
int RATE_LIMIT = -90;
int LOGGING = -50;
// ...
}
- 为关键过滤器添加顺序注释:
/**
* 认证过滤器
* 执行顺序:最高优先级(-100)
*/
public class AuthFilter implements GlobalFilter, Ordered {
// 实现代码
}
调试技巧
- 启用调试日志查看过滤器顺序:
logging:
level:
org.springframework.cloud.gateway: DEBUG
- 使用 Actuator 端点检查路由信息:
GET /actuator/gateway/routes
通过合理控制过滤器执行顺序,可以构建出高效、可靠的网关处理流水线,确保请求按照设计预期被正确处理。
服务发现集成配置
概念定义
服务发现集成配置是指网关(如Spring Cloud Gateway)动态获取后端服务实例信息的能力,通过与服务注册中心(如Eureka、Nacos、Consul等)集成,自动感知服务实例的上线、下线或变更,无需手动维护服务地址列表。
核心价值
- 动态路由:实时响应服务实例变化
- 负载均衡:自动分配请求到不同实例
- 故障隔离:自动剔除不可用实例
- 配置简化:避免硬编码服务地址
常见服务注册中心集成
Eureka 集成示例
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 开启服务发现
lower-case-service-id: true # 服务ID小写
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
Nacos 集成示例
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
nacos:
discovery:
server-addr: 127.0.0.1:8848
路由配置方式
自动路由(约定式)
通过服务ID自动创建路由(需开启discovery.locator.enabled
):
http://网关地址/service-id/path
手动路由(声明式)
routes:
- id: user-service
uri: lb://user-service # lb://表示负载均衡
predicates:
- Path=/api/users/**
关键配置参数
参数 | 说明 | 默认值 |
---|---|---|
spring.cloud.gateway.discovery.locator.enabled | 启用发现集成 | false |
spring.cloud.gateway.discovery.locator.lowerCaseServiceId | 服务ID大小写转换 | false |
spring.cloud.gateway.discovery.locator.include-expression | 服务包含表达式 | true |
spring.cloud.gateway.discovery.locator.url-expression | 服务URL表达式 | “‘lb://’+serviceId” |
高级配置技巧
元数据路由
routes:
- id: metadata-route
uri: lb://user-service
predicates:
- Path=/v2/api/**
- Metadata=version,2.0
权重路由
spring:
cloud:
nacos:
discovery:
metadata:
traffic-weight: "0.8" # 在服务实例元数据中设置权重
注意事项
- 健康检查依赖:确保注册中心健康检查机制正常工作
- 缓存时效:注意服务列表缓存更新时间(Eureka默认30秒)
- 命名规范:服务ID避免特殊字符,推荐使用中划线命名法
- 双注册问题:避免网关同时注册为服务实例
- 负载均衡器:确保引入对应实现(如Ribbon或Spring Cloud LoadBalancer)
故障排查指南
- 检查服务是否正常注册到注册中心
- 验证网关是否成功连接到注册中心
- 检查路由配置中的服务ID是否匹配
- 确认负载均衡器依赖已正确引入
- 查看网关日志中的
DiscoveryClient
相关输出
性能优化建议
- 调整
ribbon.ServerListRefreshInterval
(Eureka) - 启用Nacos的推送式服务发现
- 对频繁变动的服务使用独立命名空间
- 合理设置缓存过期时间
负载均衡配置
概念定义
负载均衡(Load Balancing)是一种将网络流量或请求分发到多个服务器或服务实例的技术,目的是优化资源使用、最大化吞吐量、最小化响应时间,并避免任何单一服务器过载。在 Gateway 网关中,负载均衡通常用于将客户端请求均匀地分发到后端服务实例,确保高可用性和可扩展性。
使用场景
- 微服务架构:在微服务架构中,多个服务实例可能运行在不同的服务器或容器中,负载均衡可以确保请求均匀分发。
- 高并发访问:当单个服务实例无法处理大量请求时,负载均衡可以将请求分发到多个实例,提高系统吞吐量。
- 故障转移:如果某个服务实例宕机,负载均衡可以自动将请求路由到其他健康的实例,提高系统可用性。
常见负载均衡策略
- 轮询(Round Robin):按顺序将请求依次分发到每个服务实例。
- 随机(Random):随机选择一个服务实例处理请求。
- 加权轮询(Weighted Round Robin):根据服务实例的权重分配请求,权重高的实例处理更多请求。
- 最少连接(Least Connections):将请求分发到当前连接数最少的服务实例。
- 响应时间(Response Time):根据服务实例的响应时间动态调整请求分发。
配置示例(以 Spring Cloud Gateway 为例)
以下是一个简单的负载均衡配置示例,使用 LoadBalancerClientFilter
实现请求的分发:
spring:
cloud:
gateway:
routes:
- id: service-route
uri: lb://service-name # 使用负载均衡前缀 lb://
predicates:
- Path=/api/**
filters:
- name: LoadBalancerClientFilter
注意事项
- 服务注册与发现:负载均衡通常依赖于服务注册中心(如 Eureka、Consul 或 Nacos),确保服务实例已正确注册。
- 健康检查:负载均衡器需要定期检查服务实例的健康状态,避免将请求分发到不可用的实例。
- 权重调整:在加权负载均衡中,动态调整权重可以更好地适应服务实例的性能变化。
- 会话保持(Session Affinity):某些场景需要确保同一用户的请求始终分发到同一服务实例,可通过配置会话保持实现。
常见误区
- 忽略服务实例的容量:负载均衡策略未考虑服务实例的实际处理能力,可能导致某些实例过载。
- 未配置健康检查:如果负载均衡器未检查服务实例的健康状态,可能会将请求分发到已宕机的实例。
- 过度依赖单一策略:不同场景可能需要不同的负载均衡策略,应根据实际需求灵活选择。
通过合理配置负载均衡,可以显著提高系统的可用性、性能和可扩展性。
跨域配置
什么是跨域?
跨域(Cross-Origin Resource Sharing,简称 CORS)是指浏览器出于安全考虑,限制从一个源(域名、协议、端口)加载的脚本与另一个源的资源进行交互。例如,前端应用运行在 http://localhost:8080
,而后端 API 部署在 http://api.example.com
,此时浏览器会阻止前端直接访问后端 API,除非后端明确允许跨域请求。
为什么需要跨域配置?
- 安全性:防止恶意网站通过脚本窃取用户数据。
- 同源策略:浏览器默认遵循同源策略,限制跨域请求。
- 前后端分离:现代应用通常前后端分离部署,需要跨域支持。
Gateway 中的跨域配置
在 Spring Cloud Gateway 中,可以通过以下方式配置跨域:
1. 全局跨域配置(推荐)
在 application.yml
或 application.properties
中配置:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowedHeaders: "*"
allowCredentials: true
maxAge: 3600
2. 通过代码配置
在配置类中定义 CorsWebFilter
:
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
常见配置项说明
配置项 | 说明 | 示例值 |
---|---|---|
allowedOrigins | 允许的源(域名) | "*" (允许所有)或 "http://example.com" |
allowedMethods | 允许的 HTTP 方法 | GET , POST , PUT , DELETE , OPTIONS |
allowedHeaders | 允许的请求头 | "*" (允许所有)或 "Content-Type" |
allowCredentials | 是否允许携带凭证(如 Cookie) | true 或 false |
maxAge | 预检请求缓存时间(秒) | 3600 |
注意事项
- 生产环境慎用
*
:allowedOrigins: "*"
会允许所有域名访问,存在安全风险,建议明确指定允许的域名。 allowCredentials
限制:如果设置为true
,则allowedOrigins
不能为"*"
,必须指定具体域名。- OPTIONS 预检请求:复杂请求(如带自定义头的请求)会先发送 OPTIONS 请求,网关需要正确处理。
- 与微服务冲突:如果下游微服务也配置了 CORS,可能会导致冲突,建议统一在网关层处理。
HTTPS 配置
什么是 HTTPS 配置?
HTTPS(HyperText Transfer Protocol Secure)是 HTTP 的安全版本,通过 SSL/TLS 协议对通信数据进行加密,确保数据传输的安全性。HTTPS 配置是指在网关(如 Spring Cloud Gateway)中启用 HTTPS 协议,并配置相关的证书和密钥,以实现安全的通信。
为什么需要 HTTPS 配置?
- 数据加密:防止敏感信息(如密码、信用卡号)在传输过程中被窃取。
- 身份验证:确保客户端与服务器之间的通信是可信的,防止中间人攻击。
- SEO 优化:搜索引擎(如 Google)会优先展示 HTTPS 网站。
- 合规性:许多行业标准(如 PCI DSS)要求使用 HTTPS。
HTTPS 配置的核心组件
- SSL/TLS 证书:由受信任的证书颁发机构(CA)签发,用于验证服务器身份。
- 私钥(Private Key):与证书配对的密钥,用于加密和解密数据。
- 密钥库(Keystore):存储证书和私钥的文件(如
.jks
或.p12
格式)。 - 信任库(Truststore):存储受信任的 CA 证书,用于验证客户端证书(双向 HTTPS)。
在 Spring Cloud Gateway 中配置 HTTPS
1. 生成或获取 SSL 证书
- 从 CA(如 Let’s Encrypt)获取证书,或使用自签名证书(仅用于测试)。
- 示例(生成自签名证书):
keytool -genkeypair -alias mygateway -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore gateway.p12 -validity 365
2. 配置 Spring Cloud Gateway
在 application.yml
或 application.properties
中配置 HTTPS:
server:
port: 8443
ssl:
enabled: true
key-store: classpath:gateway.p12
key-store-password: yourpassword
key-store-type: PKCS12
key-alias: mygateway
3. 强制重定向 HTTP 到 HTTPS(可选)
通过自定义过滤器实现:
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/**")
.uri("http://example.com")
.filters(f -> f.redirect(302, "https://example.com"))
.id("https-redirect"))
.build();
}
常见问题与注意事项
- 证书过期:定期检查证书有效期并及时更新。
- 混合内容:确保网页中所有资源(如图片、JS)均通过 HTTPS 加载。
- 性能开销:HTTPS 会增加少量 CPU 开销,可通过 TLS 优化(如会话复用)缓解。
- 自签名证书:仅用于测试环境,生产环境必须使用 CA 签发的证书。
- Cipher Suites:配置强加密算法,禁用不安全的协议(如 SSLv3、TLS 1.0)。
高级配置(双向 HTTPS)
如果需要客户端验证,需配置信任库:
server:
ssl:
client-auth: need
trust-store: classpath:truststore.p12
trust-store-password: yourpassword
示例:完整的 HTTPS 网关配置
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return factory -> factory.addConnectorCustomizers(connector -> {
connector.setScheme("https");
connector.setSecure(true);
});
}
}
通过以上配置,你的网关将能够安全地处理 HTTPS 请求。
监控与指标配置
概念定义
监控与指标配置是 Gateway 网关中用于实时跟踪和记录系统运行状态、性能数据以及请求流量的重要功能。通过收集和分析这些指标,可以帮助开发者及时发现潜在问题、优化系统性能,并确保服务的稳定性。
核心指标
- 请求量(Request Count):记录单位时间内 Gateway 处理的请求数量。
- 响应时间(Response Time):统计请求从进入 Gateway 到返回响应所花费的时间。
- 错误率(Error Rate):统计请求失败的比率,如 4xx 或 5xx 状态码的请求占比。
- 吞吐量(Throughput):单位时间内 Gateway 处理的请求数据量(如字节数)。
- 并发连接数(Concurrent Connections):当前活跃的客户端连接数。
常用监控工具
- Prometheus + Grafana:
- Prometheus 用于收集和存储指标数据。
- Grafana 用于可视化展示监控数据。
- Spring Boot Actuator:
- 提供内置的监控端点(如
/actuator/metrics
)。 - 支持与 Micrometer 集成,对接多种监控系统。
- 提供内置的监控端点(如
- ELK Stack(Elasticsearch + Logstash + Kibana):
- 主要用于日志收集和分析,但也可以结合指标数据使用。
配置示例(基于 Spring Cloud Gateway)
1. 启用 Actuator 监控
在 application.yml
中配置:
management:
endpoints:
web:
exposure:
include: "*" # 暴露所有监控端点
metrics:
tags:
application: ${spring.application.name} # 添加应用标签
2. 集成 Prometheus
添加依赖:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
配置 Prometheus 的 scrape_configs
:
scrape_configs:
- job_name: 'gateway'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080'] # Gateway 服务地址
3. 自定义指标
通过 Micrometer 自定义指标:
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Component;
@Component
public class CustomMetrics {
private final Counter customCounter;
public CustomMetrics(MeterRegistry registry) {
this.customCounter = Counter.builder("gateway.custom.requests")
.description("Total custom requests")
.tag("type", "custom")
.register(registry);
}
public void incrementCounter() {
customCounter.increment();
}
}
使用场景
- 性能优化:通过分析响应时间和吞吐量,定位性能瓶颈。
- 故障排查:监控错误率和异常请求,快速发现服务异常。
- 容量规划:根据请求量和并发连接数,合理分配资源。
- 告警设置:基于阈值(如错误率 > 1%)触发告警通知。
注意事项
- 指标标签设计:
- 避免使用高基数字段(如用户 ID)作为标签,可能导致存储压力。
- 使用有意义的标签(如
route_id
、status_code
)便于筛选。
- 采样频率:
- 高频采样可能增加系统负载,需根据实际需求平衡。
- 数据保留策略:
- 监控数据通常不需要长期存储,可设置合理的保留周期(如 15 天)。
- 安全性:
- 确保监控端点(如
/actuator
)仅对内部开放,避免敏感信息泄露。
- 确保监控端点(如
高级配置
动态路由监控
通过 RouteDefinitionLocator
获取路由信息并关联指标:
@Bean
public RouteMetrics routeMetrics(
RouteDefinitionLocator locator,
MeterRegistry registry) {
return new RouteMetrics(locator, registry);
}
分布式追踪集成
结合 Sleuth 和 Zipkin 实现请求链路追踪:
spring:
sleuth:
enabled: true
zipkin:
base-url: http://localhost:9411
七、Gateway 安全配置
JWT 认证集成
概念定义
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为 JSON 对象。它由三部分组成:
- Header:包含令牌类型(JWT)和签名算法(如 HMAC SHA256 或 RSA)。
- Payload:包含声明(claims),即用户信息和其他数据。
- Signature:用于验证令牌的完整性和真实性,防止篡改。
JWT 通常用于身份验证和授权,尤其在微服务架构中,Gateway 网关可以通过验证 JWT 来保护后端服务。
使用场景
- 用户认证:用户登录后,服务器生成 JWT 并返回给客户端,客户端在后续请求中携带 JWT 进行身份验证。
- API 保护:Gateway 网关验证 JWT,确保只有合法请求才能访问后端服务。
- 跨域认证:JWT 是无状态的,适合分布式系统和跨域场景。
常见误区或注意事项
- 敏感信息泄露:JWT 的 Payload 是 Base64 编码的,可以被解码,因此不应存储敏感信息(如密码)。
- 令牌过期:JWT 应设置合理的过期时间(
exp
),避免长期有效导致安全风险。 - 签名算法:务必使用强签名算法(如 HS256 或 RS256),避免使用
none
算法。 - 令牌存储:客户端通常将 JWT 存储在
localStorage
或cookie
中,需注意防范 XSS 和 CSRF 攻击。
示例代码(Spring Cloud Gateway 集成 JWT)
1. 添加依赖
在 pom.xml
中添加 JWT 相关依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2. 创建 JWT 工具类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtUtil {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION_TIME = 86400000; // 24小时
// 生成 JWT
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
// 验证并解析 JWT
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}
3. 配置 Gateway 过滤器
在 Gateway 中创建全局过滤器验证 JWT:
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class JwtAuthenticationFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
try {
String jwt = token.substring(7);
Claims claims = JwtUtil.parseToken(jwt);
// 将用户信息添加到请求头中
ServerHttpRequest request = exchange.getRequest().mutate()
.header("username", claims.getSubject())
.build();
return chain.filter(exchange.mutate().request(request).build());
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
}
4. 配置路由规则
在 application.yml
中配置需要认证的路由:
spring:
cloud:
gateway:
routes:
- id: auth-service
uri: http://localhost:8081
predicates:
- Path=/api/auth/**
filters:
- name: JwtAuthenticationFilter
总结
通过 JWT 认证集成,Gateway 网关可以实现无状态、安全的身份验证机制。开发者需注意令牌的安全性和有效期,并结合实际业务需求调整过滤逻辑。
OAuth2 集成
概念定义
OAuth2(Open Authorization 2.0)是一种授权框架,允许第三方应用在用户授权后,有限访问其资源服务器上的资源,而无需直接暴露用户凭证。它通过**令牌(Token)**机制实现安全的授权流程,是微服务架构中网关集成的核心认证方案之一。
核心角色
- 资源所有者(Resource Owner):用户(最终授权方)。
- 客户端(Client):申请访问资源的应用(如前端或第三方服务)。
- 授权服务器(Authorization Server):颁发令牌的服务(如Keycloak、Okta)。
- 资源服务器(Resource Server):托管受保护资源的服务(如API服务)。
常用授权模式
- 授权码模式(Authorization Code)
- 最安全的模式,适用于有后端的Web应用。
- 流程:用户授权 → 获取授权码 → 用授权码换取令牌。
- 密码模式(Password Credentials)
- 直接通过用户名/密码换取令牌,仅信任度高的场景使用(如自家应用)。
- 客户端模式(Client Credentials)
- 服务端间通信,无需用户参与。
网关集成场景
在Spring Cloud Gateway中,OAuth2常用于:
- 统一认证:所有请求通过网关时校验令牌。
- 权限中继:将令牌传递给下游微服务(如通过
Authentication
头)。 - 令牌转换:将JWT转换为内部令牌格式。
配置示例(Spring Security + Keycloak)
# application.yml
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: gateway-client
client-secret: xxxxxx
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/keycloak"
provider:
keycloak:
issuer-uri: http://localhost:8080/auth/realms/myrealm
关键代码(网关过滤器)
@Bean
SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/public/**").permitAll()
.anyExchange().authenticated()
)
.oauth2Login(withDefaults())
.oauth2ResourceServer(server -> server.jwt(Customizer.withDefaults()));
return http.build();
}
注意事项
- 令牌有效期:设置合理的
access_token
和refresh_token
过期时间。 - 安全传输:强制使用HTTPS,避免令牌泄露。
- 范围限制:通过
scope
参数限制客户端权限范围。 - CSRF防护:在授权码模式中启用CSRF保护。
常见误区
- 直接存储用户凭证:OAuth2应通过令牌交互,而非传递原始密码。
- 过度开放
scope
:避免授予客户端不必要的权限。 - 忽略令牌刷新:未处理
refresh_token
会导致用户体验中断。
权限控制配置
概念定义
权限控制配置是 Gateway 网关中的核心功能之一,用于定义和管理对 API 或路由的访问权限。它确保只有经过授权的用户、服务或客户端才能访问特定的资源。权限控制通常基于角色、用户身份、IP 地址或其他自定义规则。
使用场景
- API 访问控制:限制某些 API 只能由特定角色或用户访问。
- 微服务安全:在微服务架构中,网关作为入口点,统一管理服务的访问权限。
- 防止未授权访问:通过权限控制阻止恶意请求或未授权的客户端访问敏感数据。
- 多租户系统:为不同租户配置不同的访问权限。
常见权限控制方式
-
基于角色的访问控制(RBAC):
- 定义角色(如
ADMIN
、USER
),并为角色分配权限。 - 示例:只有
ADMIN
角色可以访问/admin
路径。
- 定义角色(如
-
基于 JWT 的权限控制:
- 解析 JWT 令牌中的声明(如
roles
或scopes
)进行权限验证。
- 解析 JWT 令牌中的声明(如
-
IP 白名单/黑名单:
- 允许或拒绝特定 IP 地址的访问。
-
自定义断言(Predicate):
- 通过自定义逻辑(如请求头、参数)动态控制访问。
配置示例(基于 Spring Cloud Gateway)
1. 基于角色的路由配置
spring:
cloud:
gateway:
routes:
- id: admin-route
uri: http://admin-service
predicates:
- Path=/admin/**
filters:
- name: JwtFilter
args:
requiredRoles: ADMIN
2. 自定义权限过滤器
@Component
public class JwtRoleFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 解析 JWT 并验证角色
Claims claims = JwtUtils.parseToken(token);
String role = claims.get("role", String.class);
if (!"ADMIN".equals(role)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
3. IP 白名单配置
spring:
cloud:
gateway:
routes:
- id: secure-route
uri: http://secure-service
predicates:
- Path=/secure/**
- RemoteAddr=192.168.1.0/24, 10.0.0.1
常见误区与注意事项
-
过度依赖网关权限控制:
- 网关权限控制是第一道防线,但内部服务仍需实现自己的权限验证(纵深防御)。
-
硬编码权限规则:
- 避免将权限规则硬编码在配置中,建议使用动态配置(如数据库或配置中心)。
-
JWT 令牌泄露:
- 确保 JWT 使用 HTTPS 传输,并设置合理的过期时间。
-
性能影响:
- 复杂的权限校验逻辑可能增加网关延迟,需优化过滤器和缓存机制。
-
日志与监控:
- 记录权限失败的请求,便于审计和排查问题。
高级配置建议
- 与 OAuth2/OIDC 集成:
- 结合 Keycloak 或 Auth0 实现更完善的权限管理。
- 动态路由权限:
- 通过
RouteLocator
动态加载权限规则。
- 通过
- 分布式缓存:
- 使用 Redis 缓存权限数据,减少数据库查询压力。
IP 白名单配置
概念定义
IP 白名单是一种网络安全机制,用于限制只有特定 IP 地址或 IP 地址范围的请求才能访问网关或服务。通过配置 IP 白名单,可以有效地防止未经授权的访问,提升系统的安全性。
使用场景
- 内部系统访问控制:仅允许公司内部网络的 IP 访问某些敏感接口。
- 第三方服务集成:仅允许合作伙伴或第三方服务的 IP 访问 API。
- 防止恶意攻击:通过限制访问来源,减少 DDoS 攻击或暴力破解的风险。
配置方式
在 Gateway 中,可以通过以下方式配置 IP 白名单:
1. 基于 Spring Cloud Gateway 的配置
spring:
cloud:
gateway:
routes:
- id: ip-whitelist-route
uri: http://example.com
predicates:
- Path=/api/**
filters:
- RemoteAddr=192.168.1.1/24, 10.0.0.1
2. 自定义过滤器实现
@Component
public class IpWhitelistFilter implements GatewayFilter {
private final List<String> allowedIps = Arrays.asList("192.168.1.1", "10.0.0.1");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
if (!allowedIps.contains(clientIp)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
常见误区与注意事项
- 动态 IP 问题:如果客户端使用动态 IP,白名单可能无法正常工作。可以考虑使用 VPN 或固定 IP 解决。
- 代理服务器的影响:如果请求经过代理(如 Nginx、负载均衡器),需要确保获取的是真实客户端 IP 而非代理服务器 IP。
- IPv4 与 IPv6:确保白名单配置支持 IPv6 地址(如
2001:db8::1
)。 - 性能影响:对于高并发场景,频繁的 IP 检查可能影响性能,建议结合缓存优化。
示例代码(获取真实 IP)
如果网关前有代理服务器,需要从 X-Forwarded-For
头中获取真实 IP:
String clientIp = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
if (clientIp == null) {
clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
}
高级配置
支持 CIDR 格式的 IP 范围匹配(如 192.168.1.0/24
):
private boolean isIpAllowed(String ip) {
try {
SubnetUtils utils = new SubnetUtils("192.168.1.0/24");
return utils.getInfo().isInRange(ip);
} catch (IllegalArgumentException e) {
return false;
}
}
请求频率限制
概念定义
请求频率限制(Rate Limiting)是一种用于控制客户端在特定时间段内向服务器发送请求数量的机制。它通过限制每个客户端(如IP地址、用户ID等)在单位时间内的请求次数,防止系统因过载而崩溃,确保服务的稳定性和公平性。
使用场景
- 防止恶意攻击:如DDoS攻击或暴力破解。
- 保护后端资源:避免单个客户端过度占用API或数据库资源。
- 公平分配资源:确保所有用户均衡使用服务,避免少数用户垄断带宽或计算资源。
- 应对突发流量:平滑流量峰值,避免服务雪崩。
常见实现方式
-
令牌桶算法(Token Bucket):
- 系统以固定速率向桶中添加令牌。
- 每个请求消耗一个令牌,桶空时拒绝请求。
- 示例代码(基于Guava库):
RateLimiter limiter = RateLimiter.create(10.0); // 每秒10个令牌 if (limiter.tryAcquire()) { // 处理请求 } else { // 返回429 Too Many Requests }
-
漏桶算法(Leaky Bucket):
- 请求以固定速率从桶中“漏出”处理,超限请求被丢弃或排队。
-
固定窗口计数器:
- 统计单位时间(如1分钟)内的请求数,超限则拒绝。
-
滑动窗口日志:
- 记录每个请求的时间戳,统计最近时间窗口内的请求数。
网关中的配置示例(Spring Cloud Gateway)
spring:
cloud:
gateway:
routes:
- id: rate_limited_route
uri: http://backend-service
predicates:
- Path=/api/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒允许的请求数
redis-rate-limiter.burstCapacity: 20 # 瞬时最大请求数
key-resolver: "#{@ipKeyResolver}" # 按IP限流
注意事项
-
限流粒度选择:
- 按IP限流可能导致共享IP的用户被误伤。
- 按用户ID限流需先完成身份认证。
-
突发流量处理:
- 结合
burstCapacity
允许短时突发,避免过于严格的限制。
- 结合
-
分布式环境一致性:
- 使用Redis等中间件存储计数,避免单机限流失效。
-
响应设计:
- 返回
429 Too Many Requests
状态码,并在Retry-After
头中提示重试时间。
- 返回
-
白名单机制:
- 对内部服务或可信IP免除限流。
高级策略
- 动态限流:
- 根据系统负载自动调整限流阈值。
- 分层限流:
- 对API、用户、IP等多维度分别设置限制。
- 预热模式:
- 冷启动时逐步提高限流阈值,避免瞬间放行大量请求。
八、Gateway 性能优化
网关缓存配置
概念定义
网关缓存配置是指在API网关层面对请求和响应数据进行缓存,以减少后端服务的负载、提高响应速度并降低延迟。通过缓存策略,网关可以存储频繁访问的数据,并在后续相同请求时直接返回缓存结果,而无需再次访问后端服务。
使用场景
- 高频访问数据:适用于短时间内被多次请求的静态或半静态数据(如商品详情、配置信息等)。
- 降低后端压力:当后端服务处理能力有限时,缓存可以显著减少直接调用次数。
- 提升用户体验:通过快速返回缓存结果,减少用户等待时间。
- 应对突发流量:在秒杀或热点事件中,缓存可以避免后端服务被击垮。
缓存类型
- 本地缓存:存储在网关进程内存中(如Caffeine、Guava Cache),速度快但容量有限。
- 分布式缓存:使用Redis等中间件,适合多网关实例共享缓存数据。
- HTTP缓存:基于HTTP头(如
Cache-Control
)实现浏览器或CDN缓存。
常见配置项(以Spring Cloud Gateway为例)
spring:
cloud:
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
filters:
- name: CacheRequestBody
args:
cacheName: productCache
ttl: 60s # 缓存存活时间
maxSize: 1000 # 最大缓存条目数
缓存策略
- TTL(Time-To-Live):设置缓存过期时间(如30秒)。
- LRU(Least Recently Used):淘汰最近最少使用的缓存项。
- 按需刷新:通过
Cache-Control: max-age
或手动清除缓存。
注意事项
- 数据一致性:缓存可能导致脏读,需根据业务容忍度设置合理的过期时间。
- 缓存穿透:对不存在的Key大量请求时,应设置空值缓存或布隆过滤器。
- 缓存雪崩:避免大量缓存同时失效,可采用随机TTL。
- 敏感数据:不应缓存含用户隐私或动态凭证(如CSRF Token)的响应。
高级技巧
- 条件缓存:通过
Header
或QueryParam
决定是否缓存(如?nocache=true
跳过缓存)。 - 缓存分区:按用户角色或设备类型划分不同缓存空间。
- 手动清除:提供管理接口主动清除指定缓存(如商品变更时)。
示例代码(Caffeine本地缓存)
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("cached_route", r -> r.path("/api/items/**")
.filters(f -> f.filter(new CacheFilter(
Caffeine.newBuilder()
.maximumSize(500)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build()
)))
.uri("lb://inventory-service"))
.build();
}
监控建议
- 记录缓存命中率(Hit/Miss Ratio)
- 监控缓存大小和淘汰频率
- 设置缓存异常告警(如Redis连接失败)
响应压缩配置
概念定义
响应压缩(Response Compression)是指网关在将响应返回给客户端之前,对响应内容进行压缩处理,以减少传输数据量,提高网络传输效率的技术。常见的压缩算法包括 Gzip、Deflate 等。
使用场景
- 大文本内容传输:如 JSON、XML、HTML 等文本数据,压缩率较高。
- 带宽敏感场景:移动端网络或低带宽环境下,减少流量消耗。
- 性能优化:减少传输时间,提升用户体验。
常见配置项
- 启用压缩:设置是否开启响应压缩功能。
- 压缩算法:指定支持的压缩算法(如 Gzip、Deflate)。
- 最小压缩阈值:仅当响应体大小超过该值时才会压缩。
- MIME类型过滤:指定哪些类型的响应需要压缩(如
text/*
,application/json
)。
示例代码(Spring Cloud Gateway)
# application.yml 配置示例
spring:
cloud:
gateway:
routes:
- id: service-route
uri: http://example.com
predicates:
- Path=/api/**
filters:
- name: ModifyResponseBody
- name: Compress
args:
enabled: true
algorithms: gzip,deflate
min-response-size: 1024
mime-types: text/plain,application/json
注意事项
- CPU 开销:压缩操作会增加服务器 CPU 负担,需权衡性能。
- 已压缩内容:如图片、视频等二进制文件已压缩,无需重复处理。
- 客户端支持:需确保客户端支持
Accept-Encoding
头指定的算法。 - HTTPS 影响:HTTPS 本身会加密数据,压缩对安全性的影响需评估。
常见误区
- 盲目启用压缩:对小文件或已压缩内容启用压缩反而降低性能。
- 算法选择单一:未考虑客户端支持的算法,导致回退到未压缩传输。
- 忽略阈值设置:对极小响应压缩可能得不偿失(如 100 字节的响应)。
连接池优化
概念定义
连接池是一种用于管理数据库连接、网络连接或其他资源连接的技术。它通过预先创建并维护一定数量的连接对象,避免频繁创建和销毁连接带来的性能开销。连接池优化是指通过调整连接池的配置参数和使用策略,提高系统性能和资源利用率。
使用场景
- 数据库访问:如 MySQL、Oracle 等数据库连接池(HikariCP、Druid)
- HTTP 客户端:如 Apache HttpClient、OkHttp 的连接池
- RPC 框架:如 Dubbo、gRPC 的连接池
- Gateway 网关:管理后端服务的连接
核心配置参数
1. 连接数配置
// HikariCP 示例配置
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(20); // 最大连接数
config.setMinimumIdle(5); // 最小空闲连接数
2. 连接生命周期
config.setMaxLifetime(1800000); // 连接最大存活时间(毫秒)
config.setIdleTimeout(600000); // 空闲连接超时时间
3. 连接验证
config.setConnectionTestQuery("SELECT 1"); // 测试查询语句
config.setConnectionTimeout(30000); // 获取连接超时时间
优化策略
1. 连接数调优
- 计算公式:
最大连接数 ≈ (核心数 * 2) + 有效磁盘数
- 考虑因素:并发请求量、SQL 执行时间、事务特性
2. 连接复用
- 使用
try-with-resources
确保连接正确关闭
try (Connection conn = dataSource.getConnection()) {
// 使用连接
}
3. 监控与动态调整
- 监控指标:活跃连接数、空闲连接数、等待线程数
- 动态调整:根据监控数据调整连接池参数
常见误区
- 盲目增大连接数:可能导致数据库过载
- 不设置连接超时:可能造成请求堆积
- 忽略连接泄漏:未正确关闭连接会导致连接耗尽
- 固定配置:不同业务场景需要不同配置
高级优化技巧
1. 分业务隔离
// 为重要业务创建独立连接池
HikariConfig orderConfig = new HikariConfig();
orderConfig.setPoolName("OrderDBPool");
2. 预热连接池
// 启动时预先建立最小连接数
HikariDataSource ds = new HikariDataSource(config);
for (int i = 0; i < config.getMinimumIdle(); i++) {
ds.getConnection().close();
}
3. 自适应调整
- 根据系统负载自动调整连接数
- 实现连接池的弹性伸缩
性能对比指标
优化项 | 优化前 QPS | 优化后 QPS |
---|---|---|
默认配置 | 1200 | - |
调优连接数 | - | 1800 |
添加连接验证 | - | 1750 |
连接池预热 | - | 1900 |
推荐工具
- 监控工具:Prometheus + Grafana
- 连接池实现:
- Java:HikariCP、Druid
- Go:sqlx、pgxpool
- Python:DBUtils、SQLAlchemy
通过合理的连接池优化,可以显著提高系统吞吐量,降低资源消耗,是高性能网关配置中不可或缺的环节。
线程池配置
概念定义
线程池是一种多线程处理形式,它预先创建一组线程,并将任务分配给这些线程执行,避免了频繁创建和销毁线程的开销。在Gateway网关中,线程池用于处理并发请求,提高系统的吞吐量和响应速度。
核心参数
- corePoolSize:核心线程数,线程池中始终保持存活的线程数量。
- maximumPoolSize:最大线程数,线程池允许创建的最大线程数量。
- keepAliveTime:空闲线程存活时间,当线程数超过核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
- workQueue:任务队列,用于存放待执行的任务。
- threadFactory:线程工厂,用于创建新线程。
- handler:拒绝策略,当线程池和队列都满时,如何处理新提交的任务。
使用场景
- 高并发请求处理:网关需要处理大量并发请求时,线程池可以有效管理线程资源。
- 资源限制:防止系统因过多线程而耗尽资源。
- 任务排队:当请求量突增时,任务队列可以缓冲请求。
常见配置示例(以Java的ThreadPoolExecutor为例)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, // corePoolSize
50, // maximumPoolSize
60, // keepAliveTime
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100), // workQueue
new NamedThreadFactory("gateway-worker"), // threadFactory
new ThreadPoolExecutor.CallerRunsPolicy() // handler
);
拒绝策略
- AbortPolicy:直接抛出RejectedExecutionException异常。
- CallerRunsPolicy:由提交任务的线程自己执行该任务。
- DiscardPolicy:直接丢弃任务,不做任何处理。
- DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试提交新任务。
注意事项
-
合理设置核心参数:
- 核心线程数应根据系统负载和硬件资源设置。
- 最大线程数不宜过大,避免资源耗尽。
- 任务队列大小需要权衡内存使用和响应延迟。
-
线程泄漏:
- 确保任务不会无限期阻塞,否则会导致线程无法释放。
-
监控和调优:
- 监控线程池的运行状态(如活跃线程数、队列大小等)。
- 根据实际运行情况动态调整参数。
-
线程命名:
- 使用有意义的线程名称,便于问题排查。
Gateway中的线程池配置
在Spring Cloud Gateway中,可以通过以下方式配置线程池:
spring:
cloud:
gateway:
httpclient:
pool:
type: fixed
max-connections: 200
acquire-timeout: 10000
max-idle-time: 60s
最佳实践
- CPU密集型任务:建议使用较小的线程池(如CPU核心数+1)。
- IO密集型任务:可以设置较大的线程池,因为线程大部分时间在等待IO。
- 混合型任务:根据任务特点拆分线程池,或使用动态调整策略。
高可用部署方案
概念定义
高可用部署方案(High Availability Deployment)是指通过一系列技术手段和架构设计,确保系统在面临硬件故障、网络问题或其他异常情况时,仍能持续提供服务,最大限度地减少停机时间。通常以“几个9”(如99.9%、99.99%)来衡量系统的可用性。
核心目标
- 故障自动转移(Failover):当主节点故障时,备用节点能自动接管服务。
- 负载均衡:将请求均匀分配到多个节点,避免单点过载。
- 数据冗余:通过多副本存储或同步机制防止数据丢失。
- 快速恢复:具备监控和自动恢复能力,缩短MTTR(平均修复时间)。
常见实现方案
1. 主从架构(Active-Standby)
- 原理:主节点处理请求,备用节点实时同步数据。主节点故障时,备用节点升级为主节点。
- 适用场景:数据库(如MySQL主从复制)、单点服务。
- 示例工具:Keepalived、Pacemaker。
2. 集群模式(Active-Active)
- 原理:多个节点同时提供服务,通过负载均衡分发请求。
- 适用场景:无状态服务(如API网关、微服务)。
- 示例工具:Nginx、Kubernetes。
3. 分布式一致性协议
- 原理:使用Raft、Paxos等算法保证多节点数据一致性。
- 适用场景:分布式数据库(如Etcd、Zookeeper)。
- 代码示例(Etcd集群配置):
# etcd1 配置 name: etcd1 listen-peer-urls: http://10.0.0.1:2380 initial-cluster: "etcd1=http://10.0.0.1:2380,etcd2=http://10.0.0.2:2380"
4. 多可用区部署(Multi-AZ)
- 原理:将节点部署在不同物理位置(如不同机房或云可用区),避免区域性故障。
- 适用场景:对容灾要求高的业务(如金融系统)。
关键技术组件
-
负载均衡器
- 硬件:F5、A10
- 软件:Nginx、HAProxy
upstream gateway { server 10.0.0.1:8080; server 10.0.0.2:8080 backup; # 备用节点 }
-
服务发现
- 工具:Consul、Eureka
- 作用:动态管理节点状态,更新负载均衡配置。
-
健康检查
- 方式:HTTP探针、TCP端口检测。
- 示例(Kubernetes):
livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30
注意事项
-
脑裂问题
- 现象:主备节点同时认为自己是主节点。
- 解决方案:使用Quorum机制或第三方仲裁服务。
-
数据同步延迟
- 主从架构中,备节点数据可能滞后。
- 优化:使用半同步复制(如MySQL的
semi-sync
)。
-
成本权衡
- 多节点部署会增加硬件和运维成本,需根据业务需求平衡。
示例:Spring Cloud Gateway高可用部署
-
架构:
- 部署多个Gateway实例,通过Nginx负载均衡。
- 注册中心使用Eureka实现服务发现。
-
配置片段:
# application.yml spring: cloud: gateway: routes: - id: user-service uri: lb://user-service # 通过负载均衡调用
-
扩展建议:
- 结合熔断工具(如Hystrix)防止级联故障。
- 使用分布式缓存(如Redis)共享会话数据。
九、Gateway 常见问题
路由匹配失败排查
概念定义
路由匹配失败是指当请求到达网关时,网关无法根据配置的路由规则找到对应的目标服务。这种情况通常会导致404错误或网关返回默认错误响应。
常见原因分析
1. 路径配置错误
- 前端请求路径与网关配置不匹配
- 大小写敏感问题
- 路径前缀/后缀多余或缺失
2. 请求方法不匹配
- 配置了特定HTTP方法(GET/POST等)但实际请求方法不符
- 方法名称大小写问题
3. 请求头匹配失败
- 配置了必须的请求头但实际请求未携带
- 请求头值不匹配正则表达式
4. 查询参数匹配失败
- 缺少必须的查询参数
- 参数值不符合配置规则
5. 路由优先级问题
- 多个路由规则冲突
- 更具体的路由未被优先匹配
排查工具与方法
1. 启用调试日志
# application.yml
logging:
level:
org.springframework.cloud.gateway: DEBUG
2. 检查路由配置
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("example_route", r -> r.path("/api/**")
.uri("http://example.com"))
.build();
}
3. 使用Actuator端点
GET /actuator/gateway/routes
常见解决方案
1. 路径匹配修正
spring:
cloud:
gateway:
routes:
- id: service_route
uri: lb://SERVICE-NAME
predicates:
- Path=/api/v1/**
2. 方法匹配修正
predicates:
- Method=GET,POST
3. 请求头匹配修正
predicates:
- Header=X-Request-Id, \d+
4. 查询参数匹配修正
predicates:
- Query=name, kevin.+
高级排查技巧
1. 自定义路由过滤器
@Component
public class RouteCheckFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 打印路由匹配信息
System.out.println("Matched Route: " +
exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR));
return chain.filter(exchange);
}
}
2. 使用WireMock测试
@SpringBootTest
@AutoConfigureWireMock(port = 0)
public class RouteTest {
@Test
void testRouteMatching() {
// 测试路由匹配逻辑
}
}
注意事项
- 路径匹配默认是大小写敏感的
- 查询参数匹配需要考虑URL编码问题
- 负载均衡路由(lb://)需要确保服务注册正常
- 正则表达式需要正确转义
- 路由顺序会影响匹配结果
过滤器执行异常
概念定义
过滤器执行异常是指在网关(如Spring Cloud Gateway)中,过滤器(Filter)在处理请求或响应时发生的错误或异常情况。这些异常可能由多种原因引起,例如网络问题、业务逻辑错误、配置不当等。
常见异常类型
- 全局过滤器异常:所有请求都会经过的过滤器发生的异常。
- 路由过滤器异常:特定路由配置的过滤器发生的异常。
- 自定义过滤器异常:开发者自定义的过滤器逻辑中抛出的异常。
常见原因
- 业务逻辑错误:过滤器中的代码存在逻辑缺陷。
- 依赖服务不可用:过滤器依赖的下游服务无法访问。
- 配置错误:过滤器的配置参数不正确。
- 网络问题:请求转发时网络连接失败。
- 权限不足:认证或授权失败。
异常处理机制
Spring Cloud Gateway 提供了多种方式来处理过滤器执行异常:
1. 使用 GlobalFilter
和 ErrorWebExceptionHandler
@Component
public class CustomGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
try {
// 过滤器逻辑
return chain.filter(exchange);
} catch (Exception e) {
// 异常处理
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
return exchange.getResponse().setComplete();
}
}
}
@Order(-1)
@Component
public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
// 全局异常处理逻辑
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
}
2. 使用 GatewayFilter
工厂
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {
public CustomGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
try {
// 过滤器逻辑
return chain.filter(exchange);
} catch (Exception e) {
// 异常处理
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
};
}
public static class Config {
// 配置参数
}
}
最佳实践
- 日志记录:在过滤器中添加详细的日志记录,便于排查问题。
- 异常分类处理:根据不同的异常类型采取不同的处理策略。
- 熔断机制:对于依赖下游服务的过滤器,考虑实现熔断机制。
- 单元测试:为自定义过滤器编写充分的单元测试。
- 监控告警:集成监控系统,对过滤器异常进行告警。
常见问题排查
- 检查过滤器顺序:确保过滤器的执行顺序符合预期。
- 验证配置:检查过滤器的配置参数是否正确。
- 查看日志:通过网关日志定位异常发生的具体位置。
- 测试隔离:单独测试可疑的过滤器逻辑。
示例:自定义异常处理
@Component
public class ExceptionHandlingFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange)
.onErrorResume(e -> {
if (e instanceof RuntimeException) {
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
DataBuffer buffer = exchange.getResponse().bufferFactory()
.wrap("Custom error message".getBytes());
return exchange.getResponse().writeWith(Mono.just(buffer));
}
return Mono.error(e);
});
}
}
性能瓶颈分析
概念定义
性能瓶颈分析是指通过系统化的方法,识别和定位影响系统性能的关键因素或限制点。这些瓶颈可能出现在硬件资源(如CPU、内存、磁盘I/O)、网络带宽、应用程序代码、数据库查询或外部服务调用等环节。
常见性能瓶颈类型
硬件资源瓶颈
- CPU瓶颈:高CPU使用率导致请求处理延迟
- 内存瓶颈:内存不足引发频繁GC或OOM错误
- 磁盘I/O瓶颈:高磁盘读写延迟影响数据存取速度
- 网络带宽瓶颈:网络吞吐量达到上限导致通信延迟
软件层面瓶颈
- 线程阻塞:锁竞争、同步等待等导致的线程停滞
- 低效算法:时间复杂度高的算法实现
- 数据库问题:慢查询、缺少索引、连接池不足
- 缓存失效:缓存命中率低下或缓存雪崩
分析方法论
监控工具
-
JVM工具:
jstack <pid> # 线程分析 jstat -gcutil <pid> # GC分析 jmap -heap <pid> # 内存分布
-
系统级工具:
top/htop # Linux系统监控 vmstat 1 # 虚拟内存统计 iostat -x 1 # 磁盘I/O监控
性能剖析
-
火焰图生成:
# 使用async-profiler ./profiler.sh -d 60 -f flamegraph.html <pid>
-
Arthas诊断:
trace com.example.Service methodName # 方法调用追踪 monitor -c 5 com.example.Service methodName # 方法执行统计
典型优化案例
数据库慢查询优化
-
识别慢查询:
-- MySQL配置 SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1;
-
添加适当索引:
ALTER TABLE orders ADD INDEX idx_customer_status (customer_id, status);
线程池优化配置
// 最佳实践示例
ThreadPoolExecutor executor = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(), // 核心线程数
Runtime.getRuntime().availableProcessors() * 2, // 最大线程数
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadPoolExecutor.CallerRunsPolicy());
注意事项
- 避免过早优化:应先确认瓶颈再实施优化
- 监控基线建立:需有正常状态下的性能数据作为基准
- 变更验证:每次优化后必须进行对比测试
- 全链路分析:分布式系统需要追踪完整调用链
高级工具链
- APM系统:SkyWalking、Pinpoint
- 压力测试:JMeter、Gatling
- 云原生方案:Prometheus + Grafana监控体系
常见配置错误
路由配置错误
-
路径匹配错误
- 使用
Path
断言时,未正确处理通配符(如/api/**
与/api/*
的区别)。 - 示例错误配置:
routes: - id: wrong-path uri: http://backend-service predicates: - Path=/api/* # 仅匹配单级路径(如 `/api/user`),不匹配多级(如 `/api/user/1`)
- 修正方案:使用
/api/**
匹配多级路径。
- 使用
-
优先级冲突
- 多个路由规则未明确设置
order
,导致请求被错误路由。 - 示例:两个路由均匹配
/api/**
,但未定义优先级,可能随机命中。
- 多个路由规则未明确设置
过滤器配置错误
-
过滤器顺序问题
- 全局过滤器(如
GlobalFilter
)与局部过滤器执行顺序未协调,导致逻辑异常。 - 关键点:通过
@Order
注解或实现Ordered
接口明确顺序。
- 全局过滤器(如
-
重复修改请求/响应
- 多个过滤器对
Request/Response
的Body
重复读写,导致数据丢失。 - 解决方案:使用
CachedBodyOutputMessage
缓存请求体。
- 多个过滤器对
负载均衡配置
-
未启用负载均衡
- 直接使用
http://backend-service
而非lb://backend-service
,导致无法通过服务名调用。 - 错误配置:
uri: http://backend-service # 无法解析服务实例
- 正确配置:
uri: lb://backend-service # 通过注册中心负载均衡
- 直接使用
-
缺失服务发现依赖
- 未添加
spring-cloud-starter-loadbalancer
或spring-cloud-starter-netflix-ribbon
。
- 未添加
跨域配置
-
全局与局部 CORS 冲突
- 同时配置了全局 CORS 和路由级 CORS,导致策略覆盖。
- 建议:统一通过
spring.cloud.gateway.globalcors
配置。
-
通配符滥用
- 错误允许所有来源:
allowedOrigins: "*" # 生产环境应避免
- 错误允许所有来源:
超时与重试
-
未设置超时
- 默认无超时限制,可能导致请求长时间阻塞。
- 示例配置:
spring: cloud: gateway: httpclient: connect-timeout: 1000 response-timeout: 5s
-
重试条件不明确
- 未限制重试的 HTTP 方法(如对
POST
请求重试可能引发数据重复提交)。 - 示例安全配置:
retries: methods: GET statuses: 502,503
- 未限制重试的 HTTP 方法(如对
安全配置
-
敏感头信息泄露
- 未清除下游服务的敏感头(如
Cookie
、Authorization
)。 - 解决方案:
filters: - RemoveRequestHeader=Authorization
- 未清除下游服务的敏感头(如
-
路由暴露
- 生产环境未关闭
Actuator
的/gateway
端点,可能泄露路由信息。 - 修正方案:
management: endpoint: gateway: enabled: false endpoints: web: exposure: exclude: gateway
- 生产环境未关闭
动态配置问题
-
文件监听失效
- 使用文件配置时,未启用
spring.cloud.gateway.config.enabled=true
或文件路径错误。
- 使用文件配置时,未启用
-
数据库配置未刷新
- 动态路由从数据库加载时,缺少
RefreshScope
或未调用/actuator/refresh
。
- 动态路由从数据库加载时,缺少
日志调试技巧
日志级别
- TRACE:最详细的日志信息,通常用于调试阶段
- DEBUG:调试信息,开发环境常用
- INFO:程序运行关键节点信息
- WARN:潜在问题警告
- ERROR:错误信息,但不影响系统继续运行
- FATAL:严重错误,导致系统崩溃
最佳实践
- 合理使用占位符:
// 推荐
log.debug("User {} login from {}", username, ip);
// 不推荐
log.debug("User " + username + " login from " + ip);
- 避免过度日志:
- 生产环境避免DEBUG级别
- 高频操作减少日志输出
- 日志格式统一:
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
上下文信息
- 添加请求ID:
MDC.put("requestId", UUID.randomUUID().toString());
try {
// 业务逻辑
} finally {
MDC.clear();
}
- 异常日志规范:
try {
// 业务代码
} catch (Exception e) {
log.error("Failed to process order {}: {}", orderId, e.getMessage(), e);
// 注意保留异常堆栈(最后一个参数)
}
性能优化
- 日志级别判断:
if (log.isDebugEnabled()) {
log.debug("Expensive log message: {}", expensiveOperation());
}
- 异步日志:
- 使用Log4j2或Logback的AsyncAppender
常见问题排查
- 无日志输出:
- 检查日志配置文件路径
- 确认日志级别设置
- 验证Appender配置
- 日志文件过大:
- 配置滚动策略
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
工具推荐
- 日志分析工具:
- ELK Stack (Elasticsearch + Logstash + Kibana)
- Graylog
- Splunk
- 实时监控:
- 配置日志告警规则
- 关键错误即时通知(邮件/短信)
十、Gateway 实战案例
微服务网关配置实例
1. 什么是微服务网关?
微服务网关(API Gateway)是微服务架构中的核心组件,充当所有客户端请求的统一入口。它负责请求路由、协议转换、安全认证、流量控制等核心功能,简化客户端与后端微服务之间的交互。
2. 典型配置场景
2.1 路由配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
id
: 路由唯一标识uri
: 目标服务地址(lb://表示负载均衡)predicates
: 路由条件(此处匹配以/api/users开头的请求)filters
: 过滤器(StripPrefix=1表示去掉第一个路径段)
2.2 跨域配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
allowedHeaders: "*"
3. 安全配置示例
3.1 JWT认证
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("secure-service", r -> r.path("/api/secure/**")
.filters(f -> f.filter(new JwtAuthenticationFilter()))
.uri("lb://secure-service"))
.build();
}
3.2 IP白名单
spring:
cloud:
gateway:
routes:
- id: admin-service
uri: lb://admin-service
predicates:
- Path=/admin/**
filters:
- name: RemoteAddr
args:
sources: 192.168.1.0/24, 10.0.0.1
4. 流量控制配置
4.1 限流配置
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/orders/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
4.2 熔断配置
spring:
cloud:
gateway:
routes:
- id: inventory-service
uri: lb://inventory-service
predicates:
- Path=/inventory/**
filters:
- name: CircuitBreaker
args:
name: inventoryCircuit
fallbackUri: forward:/fallback/inventory
5. 日志与监控配置
spring:
cloud:
gateway:
httpclient:
wiretap: true # 启用请求/响应日志
metrics:
enabled: true # 启用指标收集
logging:
level:
org.springframework.cloud.gateway: DEBUG
6. 常见问题解决方案
-
路由不生效:
- 检查predicates路径是否匹配
- 验证目标服务是否注册到服务发现
- 查看网关日志中的路由匹配情况
-
跨域问题:
- 确保网关层和微服务层不要重复配置CORS
- 检查allowedOrigins是否包含实际请求来源
-
性能问题:
- 避免在网关进行复杂业务逻辑
- 对频繁调用的路由启用缓存
- 合理配置连接池参数
7. 生产环境建议
- 启用HTTPS:
server:
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: changeit
key-store-type: PKCS12
- 启用健康检查:
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health
- 配置合理的超时时间:
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
灰度发布实现方案
概念定义
灰度发布(Gray Release),也称为金丝雀发布(Canary Release),是一种渐进式的软件发布策略。它允许新版本应用在小范围用户群体中进行测试,逐步扩大发布范围,最终覆盖所有用户。这种方案可以降低发布风险,及时发现并修复问题,避免大规模故障。
使用场景
- 新功能上线:验证新功能的稳定性和用户体验。
- 重大版本升级:避免因兼容性问题导致服务不可用。
- A/B 测试:对比不同版本的效果(如 UI、算法等)。
- 紧急修复:快速验证修复方案的有效性。
常见实现方案
1. 基于流量比例的灰度发布
通过网关(如 Spring Cloud Gateway、Nginx)按比例分配流量到新旧版本。
# Spring Cloud Gateway 示例
spring:
cloud:
gateway:
routes:
- id: new-version
uri: lb://new-service
predicates:
- Path=/api/**
- Weight=new-service, 10 # 10% 流量到新版本
- id: old-version
uri: lb://old-service
predicates:
- Path=/api/**
- Weight=old-service, 90 # 90% 流量到旧版本
2. 基于用户特征的灰度发布
根据用户属性(如用户 ID、地域、设备类型)路由流量。
// 自定义网关过滤器(Spring Cloud Gateway)
public class GrayReleaseFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String userId = exchange.getRequest().getHeaders().getFirst("User-ID");
if (userId != null && userId.endsWith("0")) { // 用户ID以0结尾的访问新版本
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, "lb://new-service");
}
return chain.filter(exchange);
}
}
3. 基于请求头的灰度发布
通过 HTTP 头(如 X-Gray-Release: true
)控制流量走向。
# Nginx 配置示例
location /api {
if ($http_x_gray_release = "true") {
proxy_pass http://new-service;
}
proxy_pass http://old-service;
}
4. 基于服务注册中心的灰度发布
利用服务注册中心(如 Nacos、Eureka)的分组功能隔离新旧版本实例。
# 新版本服务注册时添加元数据
spring.cloud.nacos.discovery.metadata.version=new
注意事项
- 监控与回滚:实时监控灰度版本的性能指标(如错误率、延迟),准备快速回滚方案。
- 数据一致性:确保新旧版本兼容同一数据库或消息队列,避免数据冲突。
- 用户一致性:同一用户的请求应始终路由到同一版本(可通过 Cookie 或用户 ID 绑定)。
- 测试覆盖:灰度前需完成单元测试、集成测试和压测。
扩展工具
- Spring Cloud Gateway:支持权重路由和自定义过滤器。
- Nginx/Lua:灵活实现复杂路由逻辑。
- Istio:通过 VirtualService 实现流量镜像和百分比分发。
- Apollo:动态调整灰度规则,无需重启服务。
AB 测试路由配置
概念定义
AB 测试路由配置是指在网关层(如 Spring Cloud Gateway)通过路由规则,将流量按比例分配到不同版本的服务实例(A 版本和 B 版本),用于对比不同版本的性能、功能或用户体验。通常用于灰度发布、功能验证或性能优化场景。
使用场景
- 灰度发布:逐步将新版本(B 版本)暴露给部分用户,降低全量发布风险。
- 功能对比:验证新功能(B 版本)是否比旧功能(A 版本)更优。
- 性能测试:对比不同版本服务的响应时间、吞吐量等指标。
核心配置方式
1. 基于权重的路由(Weight-based Routing)
通过配置权重比例分配流量,例如 80% 流量到 A 版本,20% 流量到 B 版本。
spring:
cloud:
gateway:
routes:
- id: ab-test-route
uri: lb://service-name
predicates:
- Path=/api/**
filters:
- name: Weight
args:
group: service-version
weights:
A: 80
B: 20
2. 基于请求头的路由(Header-based Routing)
通过请求头(如 X-Version: A
)动态路由到指定版本。
spring:
cloud:
gateway:
routes:
- id: version-a-route
uri: lb://service-a
predicates:
- Path=/api/**
- Header=X-Version, A
- id: version-b-route
uri: lb://service-b
predicates:
- Path=/api/**
- Header=X-Version, B
3. 基于 Cookie 的路由
通过 Cookie 值(如 version=B
)区分用户路由。
spring:
cloud:
gateway:
routes:
- id: version-a-route
uri: lb://service-a
predicates:
- Path=/api/**
- Cookie=version, A
- id: version-b-route
uri: lb://service-b
predicates:
- Path=/api/**
- Cookie=version, B
注意事项
- 流量分配准确性:权重路由依赖负载均衡器,需确保网关与服务实例间的负载均衡策略一致。
- 会话保持:若 AB 版本涉及用户状态(如登录),需通过 Cookie 或 Header 保证同一用户始终访问同一版本。
- 监控与回滚:配置监控(如 Prometheus)实时观察各版本指标,并支持快速回滚。
- 服务发现:确保不同版本的服务在注册中心(如 Nacos、Eureka)中有明确标识(如元数据
version: A/B
)。
示例代码(Spring Cloud Gateway + Java 配置)
@Bean
public RouteLocator abTestRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("service-a-route", r -> r
.path("/api/**")
.and()
.weight("service-version", 80)
.uri("lb://service-a"))
.route("service-b-route", r -> r
.path("/api/**")
.and()
.weight("service-version", 20)
.uri("lb://service-b"))
.build();
}
高级场景
- 动态权重调整:结合配置中心(如 Apollo)动态修改权重比例,无需重启网关。
- 条件路由:根据请求参数、地理位置等复杂条件分配流量。
Gateway 网关配置
概念定义
Gateway 网关配置是指在微服务架构中,通过配置 API 网关(如 Spring Cloud Gateway)来管理请求路由、负载均衡、安全认证、限流熔断等功能的设置过程。网关作为系统的统一入口,负责将外部请求转发到内部微服务,同时提供统一的策略管理。
使用场景
- 请求路由:根据请求路径、Header、参数等条件将请求转发到不同的微服务实例。
- 负载均衡:结合服务注册中心(如 Nacos、Eureka)实现动态路由和负载均衡。
- 安全认证:集成 OAuth2、JWT 等机制,统一处理鉴权逻辑。
- 限流熔断:通过配置限流规则(如令牌桶算法)或熔断策略(如 Hystrix)保护后端服务。
- 日志与监控:统一收集请求日志,集成 Prometheus 等监控工具。
常见配置示例(Spring Cloud Gateway)
1. 基础路由配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
id
:路由唯一标识。uri
:目标服务地址(lb://
表示负载均衡)。predicates
:匹配条件(此处匹配以/api/user
开头的请求)。filters
:过滤器(StripPrefix=1
表示移除路径的第一部分)。
2. 集成限流
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒允许的请求数
redis-rate-limiter.burstCapacity: 20 # 最大突发流量
注意事项
- 性能调优:网关是流量入口,需合理设置线程池和连接超时时间。
- 路由顺序:路由规则按顺序匹配,应将通用规则(如
/api/**
)放在最后。 - 敏感信息:避免在配置文件中明文存储证书、密钥等敏感信息。
- 动态更新:生产环境建议通过配置中心(如 Nacos)实现动态路由更新,避免重启服务。
常见误区
- 过度依赖网关:业务逻辑应尽量下沉到微服务,网关仅负责跨横切面功能。
- 忽略熔断:未配置熔断可能导致网关被下游服务拖垮。
- 路径处理错误:如未正确配置
StripPrefix
,可能导致后端服务接收错误路径。
异常统一处理方案
概念定义
异常统一处理方案是指在网关层或应用层对所有异常进行集中捕获、分类和处理的设计模式。它避免了代码中大量重复的try-catch块,提供一致的错误响应格式,并简化异常处理逻辑。
核心价值
- 统一响应格式:所有异常返回相同结构的错误信息
- 减少重复代码:消除分散在各处的异常处理代码
- 增强可维护性:集中管理异常处理逻辑
- 安全控制:避免敏感异常信息泄露
常见实现方式
Spring Cloud Gateway 实现方案
@Configuration
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
// 1. 异常分类处理
if (ex instanceof RateLimiterException) {
return handleRateLimitException(exchange, ex);
} else if (ex instanceof AuthException) {
return handleAuthException(exchange, ex);
}
// 2. 构建统一响应
ErrorResult result = ErrorResult.builder()
.code(500)
.message("Server Error")
.path(exchange.getRequest().getPath().value())
.timestamp(System.currentTimeMillis())
.build();
// 3. 返回JSON响应
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
return exchange.getResponse()
.writeWith(Mono.just(exchange.getResponse()
.bufferFactory()
.wrap(JSON.toJSONBytes(result)));
}
}
Spring Boot 实现方案(ControllerAdvice)
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResult> handleException(Exception ex) {
ErrorResult result = new ErrorResult(
500,
"System Error",
System.currentTimeMillis()
);
return ResponseEntity.status(500).body(result);
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResult> handleBusinessException(BusinessException ex) {
ErrorResult result = new ErrorResult(
ex.getCode(),
ex.getMessage(),
System.currentTimeMillis()
);
return ResponseEntity.status(400).body(result);
}
}
异常分类策略
-
业务异常:可预知的业务规则违规
- 特点:已知错误码和提示信息
- 处理:返回400状态码和业务提示
-
系统异常:未捕获的运行时异常
- 特点:未知错误
- 处理:返回500状态码,日志记录详细堆栈
-
第三方服务异常:依赖服务调用失败
- 特点:需要重试或降级
- 处理:返回503状态码
-
网关特定异常:限流、熔断等
- 特点:网关层拦截
- 处理:返回429/504等特定状态码
最佳实践
- 错误信息设计
{
"code": "AUTH_401",
"message": "Invalid access token",
"requestId": "req_123456",
"timestamp": 1630000000000,
"path": "/api/user"
}
- 日志记录要点
- 记录完整异常堆栈
- 包含请求参数和上下文
- 区分错误级别(ERROR/WARN)
- 安全注意事项
- 生产环境隐藏堆栈信息
- 敏感信息过滤
- 错误信息国际化支持
常见问题解决方案
- 异常信息丢失问题
- 使用
org.springframework.web.util.pattern.PathPattern
匹配路由 - 确保异常传播到最外层处理器
- 响应类型不一致
- 强制设置Content-Type为application/json
- 统一使用ResponseEntity或ServerResponse
- 异步处理异常
- 对于WebFlux需要返回Mono/Flux
- 使用onErrorResume处理异步流异常
性能优化建议
- 避免在异常处理中进行复杂业务逻辑
- 对频繁发生的业务异常使用缓存错误信息
- 考虑使用AOP实现异常处理的横切关注点
监控集成方案
- 对接APM系统(SkyWalking/Prometheus)
- 异常统计和报警机制
- 错误率监控仪表盘配置