目录
容错
pom文件
容错控制器
配置
测试
限流
依赖
修改启动项,配置限流的Bean
配置文件配置限流过滤器
测试
端点
依赖
配置文件开启端点支持
添加动态路由
路由容错主要通过处理未定义的路由和熔断器来实现。本文主要讲述网关结合熔断器来进行容错限流的处理。
熔断器主要应用在超时、服务器端错误等使用场景中。可以将Gateway和Hystrix集成,通过过滤器配置,加入fallbackUri来实现。因为netflix-hystrix停止更新的缘故,在spring-cloud-gateway-server 2.x版本中,还有HystrixGatewayFilterFactory这个类,但在spring-cloud-gateway-server 3.x版本中,HystrixGatewayFilterFactory不在了,取而代之的是SpringCloudCircuitBreakerFilterFactory。推荐使用Spring Cloud CircuitBreaker GatewayFilter Factory。
SpringCloudCircuitBreaker API是对多种断路器提供的一层抽象API,SpringCloudCircuitBreaker本身提供了对4种断路器组件的支持:
- Netfix Hystrix
- Resilience4J
- Sentinel
- Spring Retry
如果要在Spring Cloud Gateway中使用CircuitBreaker功能,则只能使用其中的2个组件:Netfix Hystrix和Resilience4J
容错
pom文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Spring Cloud Consul 的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
<version>2.0.0</version>
</dependency>
容错控制器
package com.example.demo.ch09.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;
@RestController
public class NotFoundController {
@RequestMapping(value = "/fallback")
public Mono<Map<String, String>> notFound() {
Map<String, String> stringMap = new HashMap<>();
stringMap.put("code", "100");
stringMap.put("data", "Service Not Available");
return Mono.just(stringMap);
}
}
配置
这里使用YAML配置
server:
port: 8220
spring:
application:
name: gateway-consul
cloud:
gateway:
routes:
- id: hello
uri: lb://service-provider/hello/
predicates:
- Path=/hello
- Method=GET
filters:
- AddRequestParameter=name,songyunhui
- name: CircuitBreaker
args:
name: fallbackcmd
fallbackUri: forward:/fallback #配置了fallback时要回调的路径,当 Hystrix的 fallback被调用时,请求将转发到fallback
discovery:
locator:
enabled: true #是否与服务中心的发现组件进行整合
consul:
host: 10.1.12.22
port: 8500
discovery:
instance-id: ${spring.application.name}:${server.port}
logging:
level:
ROOT: INFO
feign:
circuitbreaker:
enabled: true #开启Hystrix
其中,fallbackUri表示熔断后应该访问的地址,可以是外部地址,也可以是内部地址。
测试
1、“服务提供者”正常工作,访问http://localhost:8220/hello
2、关闭“服务提供者”,访问http://localhost:8220/hello:
控制台:
WARN 9316 --- [oundedElastic-1] o.s.c.l.core.RoundRobinLoadBalancer : No servers available for service: service-provider
限流
一般限流都在网关层实现,比如使用Nginx、Zuul、Spring Cloud Gateway、Openresty、Kong等。常见的限流算法有:计数器、漏桶、令牌桶。限流算法是通用的,而非Spring Cloud Gateway独有。
Spring Cloud Gateway内置了限流工厂RequestRateLimiterGatewayFilterFactory,它底层是使用Redis的Lua脚本实现的。在Spring Cloud Gateway上实现限流很简单,只需要编写相应的过滤器即可。
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>2.3.8.RELEASE</version>
</dependency>
需要添加Redis依赖,并配置好Redis服务器,详情参见linux下部署单机版redis。
修改启动项,配置限流的Bean
在GatewayApplication中添加:
@Bean
public KeyResolver ipKeyResolver() {
//按IP来限流。
//return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
//获取访问者的ip地址, 通过访问者ip地址进行限流, 限流使用的是Redis中的令牌桶算法
String hostName = exchange.getRequest().getRemoteAddress().getHostName();
return Mono.just(hostName);
}
};
}
这里是根据IP地址限流。‘
配置文件配置限流过滤器
server:
port: 8220
spring:
application:
name: gateway-consul
cloud:
gateway:
routes:
- id: hello
uri: lb://service-provider/hello/
predicates:
- Path=/hello
- Method=GET
filters:
- AddRequestParameter=name,songyunhui
- name: RequestRateLimiter # 限流过滤器使用gateway内置令牌算法
args:
redis-rate-limiter:
replenishRate: 1 #令牌补充的频率,每次就一个
burstCapacity: 2 #令牌桶的最大容量,允许在一秒钟内完成的最大请求数
key-resolver: "#{@ipKeyResolver}"
discovery:
locator:
enabled: true #是否与服务中心的发现组件进行整合
consul:
host: 10.1.12.22
port: 8500
discovery:
instance-id: ${spring.application.name}:${server.port}
redis:
host: redis服务器地址
port: 6379
database: 1
level:
ROOT: INFO
feign:
circuitbreaker:
enabled: true #开启Hystrix
#默认为true
management:
endpoint:
gateway:
enabled: true
endpoints:
web:
exposure:
include: gateway
这里默认使用Spring Cloud Gateway内置的令牌桶算法。
测试
使用Jmeter,起10个线程,一秒钟并发请求,结果如下:
从响应结果中可以看出限流成功:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Remaining: 0
X-RateLimit-Requested-Tokens: 1
X-RateLimit-Burst-Capacity: 2
X-RateLimit-Replenish-Rate: 1
content-length:
端点
依赖
Spring Cloud Gateway的端点被纳入Spring Boot Actuator中了,所以需要引用Actuator的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置文件开启端点支持
management:
endpoint:
gateway:
enabled: true
endpoints:
web:
exposure:
include: gateway
添加动态路由
开启端点支持后,要想动态添加路由配置,只需发送POST请求即可。比如,想添加一条这样的路由:
路由路径:http://localhost:8220/actuator/gateway/routes/hello3
路由ID:hello3
使用Postman,往http://localhost:8220/actuator/gateway/refresh发送以下POST请求:
{
"id": "hello3 ",
"predicates": [{
"name": "Path",
"args": {
"_genkey_0": "/hello3/**"
}
}],
"filters": [],
"uri": "http://www.baidu.com",
"order": 0
}
发送成功之后,访问http://localhost:8220/actuator/gateway/routes/hello3: