第27集SpringCloudAlibaba全网最全讲解之Gateway
|字数总计:2.7k|阅读时长:13分钟|阅读量:
引言
SpringCloudAlibaba Gateway是SpringCloudAlibaba生态中的核心网关组件,基于Spring WebFlux和Project Reactor构建,提供统一的API网关服务。作为微服务架构的入口,Gateway承担着路由转发、负载均衡、安全认证、限流熔断等重要职责。
本文将深入讲解SpringCloudAlibaba Gateway的核心概念、配置方式、过滤器机制以及实际应用场景,帮助开发者掌握微服务网关的设计与实现。
Gateway核心概念
1. 什么是API网关
API网关是微服务架构中的统一入口,所有外部请求都通过网关进行路由和转发。Gateway的主要职责包括:
- 路由转发:根据请求路径将请求转发到对应的微服务
- 负载均衡:在多个服务实例间进行负载均衡
- 安全认证:统一处理身份验证和授权
- 限流熔断:保护后端服务,防止系统过载
- 监控统计:收集请求日志和性能指标
2. Gateway架构特点
1 2 3 4 5 6 7 8 9
| graph TB A[客户端请求] --> B[Gateway网关] B --> C{路由匹配} C --> D[用户服务] C --> E[订单服务] C --> F[商品服务] D --> G[数据库] E --> G F --> G
|
核心特性:
- 基于WebFlux异步非阻塞模型
- 支持动态路由配置
- 丰富的过滤器机制
- 集成SpringCloud生态组件
- 支持WebSocket协议
项目搭建与配置
1. 创建Gateway项目
步骤1:添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-gateway</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies>
|
步骤2:配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| server: port: 8080
spring: application: name: gateway-service cloud: nacos: discovery: server-addr: localhost:8848 config: server-addr: localhost:8848 file-extension: yaml gateway: discovery: locator: enabled: true lower-case-service-id: true routes: - id: user-service uri: lb://user-service predicates: - Path=/user/** filters: - StripPrefix=1 - id: order-service uri: lb://order-service predicates: - Path=/order/** filters: - StripPrefix=1
|
2. 启动类配置
1 2 3 4 5 6 7
| @SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
|
路由配置详解
1. 静态路由配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| spring: cloud: gateway: routes: - id: user-service-route uri: http://localhost:8001 predicates: - Path=/user/** - Method=GET,POST filters: - StripPrefix=1 - AddRequestHeader=X-Gateway-Source, Gateway - id: order-service-route uri: http://localhost:8002 predicates: - Path=/order/** - Header=X-Request-Id, \d+ filters: - StripPrefix=1 - AddResponseHeader=X-Response-Time, ${timestamp}
|
2. 动态路由配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @Configuration public class DynamicRouteConfig { @Autowired private RouteDefinitionWriter routeDefinitionWriter; @Autowired private ApplicationEventPublisher publisher;
public void addRoute(RouteDefinition routeDefinition) { routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe(); publisher.publishEvent(new RefreshRoutesEvent(this)); }
public void deleteRoute(String routeId) { routeDefinitionWriter.delete(Mono.just(routeId)).subscribe(); publisher.publishEvent(new RefreshRoutesEvent(this)); }
public void updateRoute(RouteDefinition routeDefinition) { routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())).subscribe(); routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe(); publisher.publishEvent(new RefreshRoutesEvent(this)); } }
|
3. 路由谓词详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| spring: cloud: gateway: routes: - id: complex-route uri: lb://backend-service predicates: - Path=/api/v1/** - Method=GET,POST,PUT - Header=X-Request-Id, \d+ - Query=name, \w+ - Cookie=sessionId, \w+ - Host=**.example.com - RemoteAddr=192.168.1.1/24 - After=2024-01-01T00:00:00+08:00 - Before=2024-12-31T23:59:59+08:00 - Weight=group1, 80
|
过滤器机制
1. 内置过滤器
请求头过滤器:
1 2 3 4 5 6 7 8 9 10
| filters: - AddRequestHeader=X-Gateway-Source, Gateway - AddRequestHeader=X-Forwarded-For, ${remoteAddr} - AddRequestParameter=timestamp, ${timestamp} - RemoveRequestHeader=X-Secret-Key
|
响应头过滤器:
1 2 3 4 5 6 7
| filters: - AddResponseHeader=X-Response-Time, ${timestamp} - AddResponseHeader=X-Gateway-Version, 1.0 - RemoveResponseHeader=X-Internal-Info
|
路径处理过滤器:
1 2 3 4 5 6 7
| filters: - StripPrefix=2 - PrefixPath=/api/v1 - RewritePath=/old/(?<segment>.*), /new/${segment}
|
2. 自定义过滤器
全局过滤器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Component @Slf4j public class GlobalAuthFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String path = request.getURI().getPath(); log.info("请求路径: {}", path); if (needAuth(path)) { String token = request.getHeaders().getFirst("Authorization"); if (StringUtils.isEmpty(token)) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } if (!validateToken(token)) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.FORBIDDEN); return response.setComplete(); } } return chain.filter(exchange); } private boolean needAuth(String path) { return path.startsWith("/api/user") || path.startsWith("/api/order"); } private boolean validateToken(String token) { return !StringUtils.isEmpty(token) && token.startsWith("Bearer "); } @Override public int getOrder() { return -100; } }
|
局部过滤器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Component @Slf4j public class RequestLogFilter implements GatewayFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); log.info("请求开始: {} {}", request.getMethod(), request.getURI()); long startTime = System.currentTimeMillis(); return chain.filter(exchange).then( Mono.fromRunnable(() -> { long endTime = System.currentTimeMillis(); log.info("请求结束: {} {}, 耗时: {}ms", request.getMethod(), request.getURI(), endTime - startTime); }) ); } @Override public int getOrder() { return -50; } }
|
3. 限流过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Component public class RateLimitFilter implements GatewayFilter, Ordered { private final RedisTemplate<String, String> redisTemplate; public RateLimitFilter(RedisTemplate<String, String> redisTemplate) { this.redisTemplate = redisTemplate; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String clientId = getClientId(request); String key = "rate_limit:" + clientId; String count = redisTemplate.opsForValue().get(key); if (count == null) { redisTemplate.opsForValue().set(key, "1", Duration.ofMinutes(1)); } else { int currentCount = Integer.parseInt(count); if (currentCount >= 100) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS); return response.setComplete(); } redisTemplate.opsForValue().increment(key); } return chain.filter(exchange); } private String getClientId(ServerHttpRequest request) { String clientId = request.getHeaders().getFirst("X-Client-Id"); if (StringUtils.isEmpty(clientId)) { clientId = request.getRemoteAddress().getAddress().getHostAddress(); } return clientId; } @Override public int getOrder() { return -200; } }
|
集成SpringCloudAlibaba组件
1. 集成Nacos服务发现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring: cloud: nacos: discovery: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP gateway: discovery: locator: enabled: true lower-case-service-id: true predicates: - name: Path args: pattern: "'/'+serviceId+'/**'"
|
2. 集成Sentinel限流
1 2 3 4 5 6 7 8
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12
| spring: cloud: sentinel: transport: dashboard: localhost:8080 datasource: ds1: nacos: server-addr: localhost:8848 dataId: gateway-flow-rules groupId: SENTINEL_GROUP rule-type: flow
|
3. 集成Seata分布式事务
1 2 3 4 5 6 7 8
| @Configuration public class SeataConfig { @Bean public GlobalTransactionScanner globalTransactionScanner() { return new GlobalTransactionScanner("gateway-service", "default"); } }
|
监控与运维
1. 健康检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @RestController @RequestMapping("/actuator") public class HealthController { @Autowired private ReactiveHealthIndicator healthIndicator; @GetMapping("/health") public Mono<Health> health() { return healthIndicator.health(); } @GetMapping("/routes") public Flux<RouteDefinition> routes() { return routeDefinitionLocator.getRouteDefinitions(); } }
|
2. 指标监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Component public class GatewayMetrics { private final MeterRegistry meterRegistry; private final Counter requestCounter; private final Timer requestTimer; public GatewayMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; this.requestCounter = Counter.builder("gateway.requests.total") .description("Total number of gateway requests") .register(meterRegistry); this.requestTimer = Timer.builder("gateway.request.duration") .description("Gateway request duration") .register(meterRegistry); } public void recordRequest(String routeId, String method, int status) { requestCounter.increment( Tags.of( "route", routeId, "method", method, "status", String.valueOf(status) ) ); } public Timer.Sample startTimer() { return Timer.start(meterRegistry); } }
|
3. 日志配置
1 2 3 4 5 6 7 8 9
| logging: level: org.springframework.cloud.gateway: DEBUG reactor.netty: DEBUG pattern: console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" file: name: logs/gateway.log
|
性能优化
1. 连接池配置
1 2 3 4 5 6 7 8 9 10
| spring: cloud: gateway: httpclient: connect-timeout: 1000 response-timeout: 5000 pool: max-connections: 500 max-idle-time: 30s max-life-time: 60s
|
2. 缓存配置
1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration public class CacheConfig { @Bean public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES)); return cacheManager; } }
|
3. 异步处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Component public class AsyncFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return Mono.fromRunnable(() -> { CompletableFuture.runAsync(() -> { processAsyncTask(exchange); }); }).then(chain.filter(exchange)); } private void processAsyncTask(ServerWebExchange exchange) { } @Override public int getOrder() { return -10; } }
|
常见问题与解决方案
1. 路由不生效
问题描述: 配置的路由规则不生效,请求无法正确转发
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| spring: cloud: gateway: routes: - id: test-route uri: lb://test-service predicates: - Path=/test/** filters: - StripPrefix=1 discovery: locator: enabled: true
|
2. 过滤器执行顺序
问题描述: 多个过滤器的执行顺序不符合预期
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12
| @Component @Order(-100) public class FirstFilter implements GlobalFilter { }
@Component @Order(-50) public class SecondFilter implements GlobalFilter { }
|
3. 内存泄漏问题
问题描述: 长时间运行后出现内存泄漏
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Component public class ResourceFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange) .doFinally(signalType -> { cleanupResources(); }); } private void cleanupResources() { } }
|
最佳实践
1. 安全配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Configuration public class SecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { return http .authorizeExchange() .pathMatchers("/actuator/**").permitAll() .pathMatchers("/api/public/**").permitAll() .anyExchange().authenticated() .and() .oauth2ResourceServer() .jwt() .and() .build(); } }
|
2. 错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Component public class GlobalErrorHandler implements ErrorWebExceptionHandler { @Override public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) { ServerHttpResponse response = exchange.getResponse(); if (ex instanceof ResponseStatusException) { response.setStatusCode(((ResponseStatusException) ex).getStatus()); } else { response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); } String body = "{\"error\":\"" + ex.getMessage() + "\"}"; DataBuffer buffer = response.bufferFactory().wrap(body.getBytes()); return response.writeWith(Mono.just(buffer)); } }
|
3. 配置管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @ConfigurationProperties("gateway") @Data public class GatewayProperties { private List<RouteConfig> routes = new ArrayList<>(); private SecurityConfig security = new SecurityConfig(); private RateLimitConfig rateLimit = new RateLimitConfig(); @Data public static class RouteConfig { private String id; private String uri; private List<String> predicates; private List<String> filters; } @Data public static class SecurityConfig { private boolean enabled = true; private List<String> whitelist = new ArrayList<>(); } @Data public static class RateLimitConfig { private int defaultLimit = 100; private Duration windowSize = Duration.ofMinutes(1); } }
|
总结
SpringCloudAlibaba Gateway作为微服务架构的核心组件,提供了强大的路由转发、负载均衡、安全认证等功能。通过本文的详细讲解,我们了解了:
- 核心概念:Gateway的基本架构和职责
- 配置方式:静态路由和动态路由的配置方法
- 过滤器机制:内置过滤器和自定义过滤器的使用
- 集成组件:与Nacos、Sentinel、Seata的集成
- 监控运维:健康检查、指标监控和日志配置
- 性能优化:连接池、缓存和异步处理
- 最佳实践:安全配置、错误处理和配置管理
在实际应用中,建议:
- 合理设计路由规则,避免过于复杂的匹配条件
- 使用过滤器实现横切关注点,保持代码的整洁性
- 配置适当的监控和告警,及时发现和处理问题
- 定期进行性能测试和优化,确保系统的稳定性
通过掌握这些知识和技能,开发者可以构建高性能、高可用的微服务网关系统。
参考资料
- SpringCloudAlibaba官方文档
- Spring Cloud Gateway官方文档
- Nacos官方文档
- Sentinel官方文档
- WebFlux官方文档