写在前面的话
当前选择的方案在是 Spring Cloud Gateway层使用 redis作为分布式的协作中心,默认底层使用令牌桶方式实现,一定要清楚,当前在这个位置:
如果再细分一下,当前位于gateway的内部的这个位置:
实现(这个省略了gateway的搭建和配置等):
1、在gateway网关服务进入redis的pom
org.springframework.boot
spring-boot-starter-data-redis-reactive
2.3.2.RELEASE
2、yml配置
spring:
application:
name: kevin-gateway
redis:
host: 82.156.54.7
port: 6379
password: 123456
cloud:
nacos:
discovery:
server-addr: 82.156.54.7:8848
gateway:
globalcors:
cors-configurations:
'[/**]':
allowCredentials: true
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
add-to-simple-url-handler-mapping: true
# 默认过滤器(对所有route均生效)
default-filters:
# 请求限速配置
- name: RequestRateLimiter
args:
# 如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问
deny-empty-key: false
# 令牌桶算法每秒补充的token数量(每秒的请求数量)spring-boot-starter-data-redis-reactive
redis-rate-limiter.replenishRate: 10
# 令牌桶算法token最大数量(每秒的最大请求数量)
redis-rate-limiter.burstCapacity: 15
# 单次请求消费的token数量
redis-rate-limiter.requestedTokens: 10
# 自定义的KeyResolver(从请求exchange解析id,用于区分限流的独立单元,如用户ID、remoteAddr、sessionId等)
key-resolver: "#{@ipKeyResolver}"
routes:
- id: mosty-base
uri: lb://mosty-base
predicates:
- Path=/mosty-base/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 10
key-resolver: "#{@ipKeyResolver}"
- id: mosty-search
uri: lb://MOSTY-SEARCH
predicates:
- Path=/mosty-search/**
filters:
- StripPrefix=2
如上,首先需要进入redis的配置
其次配置限流的Filter配置信息,允许配置全局过滤器对所有的route生效,也可以根据需求对每个route进行单独配置
配置参数说明:
name必须写 RequestRateLimiter
args参数:
yml中配置 keyResolver:"#{@ipKeyResolver}"
@Bean(name = "ipKeyResolver")
public KeyResolver ipKeyResolver() {
return new KeyResolver() {
@Override
public Mono resolve(ServerWebExchange exchange) {
String hostName = Objects.requireNonNull(exchange.getRequest()
.getRemoteAddress()).getHostName();
System.out.println("hostName:" + hostName);
return Mono.just(hostName);
}
};
}
基于限流策略,正常访问的效果,以及被限流的效果(返回标准的Http 429编码,Too Many Request)
yml中配置 keyResolver:"#{@userKeyResolver}"
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("userId")));
}
在下面的微服务的接口中一定要有该参数,即需要能在请求参数中获取到该值
@GetMapping("/getUserNameByUserId")
public String userInfo(@RequestParam("userId") String userId) {
// 查询数据库获取
return "user name of" + userId;
}
yml中配置 keyResolver:"#{@requestPathKeyResolver}"
@Bean("requestPathKeyResolver")
public KeyResolver requestPathKeyResolver() {
return exchange -> Mono.just(Objects.requireNonNull(
exchange.getRequest().getURI().()));
}
基于上面的引入pom:spring-boot-starter-data-redis-reactive外,还需要引入
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
将Hystrix配置为全局的过滤器(对所有的 route生效),如下
说明:
name执行过滤器的类型,指向了 Hystrix过滤器
args:default-filters的Hystrix将会使用HystrixCommand打包剩余的过滤器,并命名为fallbackcmd,我们还配置了可选的参数fallbackUri,降级逻辑被调用,请求将会被转发到URI为/fallbackcontroller的控制器处理
spring:
cloud:
gateway:
# 默认过滤器(对所有route均生效)
default-filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/fallbackcontroller
添加 Hystrix的fallback的控制器接口方法
此时需要添加一个fallback的接口,并且返回想要的数据结构
@ResponseBody
@RequestMapping(value = "/fallbackcontroller")
public ResponseResult
生效还需要配置hystrix的超时时间(yml配置如下):hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds
并且记得在启动类上添加Hystrix的启动项
@EnableHystrix
为了实现效果此时将待访问的接口直接进行sleep 5s,测试效果
@Slf4j
@RestController
public class TestController {
@RequestMapping("/test/fallback")
public Object fallacak() throws InterruptedException {
Thread.sleep(5000);
log.info("熔断处理!!!");
return "Service Error!!!";
}
}