Gateway 和 Zuul 都是网关,Gateway 的推出就是为了替换 Zuul,Getaway 的底层通讯时 Netty,是基于 WebFlux 来做请求处理的,基于异步通讯,效率比 Zuul 高很多
依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
断言(谓词)
spring:
application:
name: component-gateway
cloud:
gateway:
enabled: true # 动态插拔
discovery:
locator:
enabled: true
routes:
- id: user
uri: http://127.0.0.1:5000
predicates:
- After=2020-08-08T22:27:47.000+08:00 # 表示这个时间之后的请求,可以访问
- Cookie=login, username # 必须有 cookie 且 cookie 的值 为 login=username
- Query=name # 必须有 name 属性
- Query=age # 必须有 age 属性
- Header=X-Request-Id, \d+ # 设置 Header 属性
- id: order
uri: lb:http://SERVER-ORDER # 使用微服务名称进行路由
predicates:
- Path=/order/** # 拦截请求地址
过滤器
是在满足断言条件之后,准备路由之前进行的
内置过滤器
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
- AddRequestParameter=color, blue
- AddResponseHeader=X-Response-Red, blue
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
与 Hystrix 整合(实现熔断、降级)
依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>配置 ```yaml spring: application: name: component-gateway cloud: gateway:
enabled: true # 动态插拔 discovery: locator: enabled: true routes: - id: order uri: lb:http://SERVER-ORDER # 使用微服务名称进行路由 predicates: - Query=test, debug - Path=/order/** # 拦截请求地址 filters: - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback # 指本机的 URL 地址
hystrix: command: fallbackcmd: execution: isolation: thread: timeoutInMilliseconds: 1000 # 服务访问超时时间
- **Fallback Controller**
```java
@RestController
@RequestMapping("/fallback")
public class FallbackController {
@RequestMapping
public Mono<R> fallback() {
return Mono.just(R.error("服务降级了"));
}
}
- 首先 filter 里头配置了 name 为 Hystrix 的 filter,实际是对应 HystrixGatewayFilterFactory
- 然后指定了 hystrix command 的名称,及 fallbackUri,注意 fallbackUri 要以 forward 开头
- 最后通过 hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds 指定该 command 的超时时间
服务限流
Spring Cloud Gateway 自带限流器,使用了 Redis 来实现的令牌桶算法进行限流
依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>YML 配置
spring: application: name: component-gateway redis: host: 127.0.0.1 port: 6379 timeout: 5000 cloud: gateway: enabled: true # 动态插拔 discovery: locator: enabled: true routes: - id: order uri: lb:http://SERVER-ORDER # 使用微服务名称进行路由 predicates: - Query=test, debug - Path=/order/** # 拦截请求地址 filters: - name: RequestRateLimiter # 限流,利用 redis 实现令牌桶过滤器 key-resolver: "#{@ipKeyResolver}" # 令牌,对应 AppConfig 的 bean 名称 args: redis-rate-limiter: replenishRate: 1 # 每秒生成的令牌数 burstCapacity: 2 # 最大的令牌数 requestedTokens: 1 # 每次请求获取一个令牌AppConfig 配置 ```java @Configuration public class AppConfig {
// IP 限流 @Bean public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}
// // 用户限流,使用这种方式限流,请求路径中必须携带 userId 参数 // @Bean // public KeyResolver userKeyResolver() { // return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(“userId”)); // }
// // 接口限流,获取请求地址的uri作为限流key // @Bean // public KeyResolver apiKeyResolver() { // return exchange -> Mono.just(exchange.getRequest().getPath().value()); // }
}
```
上述配置如果在一秒内有超过2个以上的请求,就会进行限流操作,网页会报 429 错误
同时,Redis 会产生 2个 key
当有这个两个 key 的时候,此时无法访问该服务,大概 1 秒所有,当令牌桶重新产生了令牌后,该 key 会自动删除,此时即可再次访问服务
