irpas技术客

SpringCloud之Gateway网关熔断、限流_yzm4399_gateway 熔断

网络投稿 3710

1、重试

spring: cloud: gateway: discovery: locator: enabled: true lowerCaseServiceId: true routes: - id: gate_hi uri: lb://gateway-hi predicates: - Path=/retry/* filters: - StripPrefix=1 - name: Retry args: retries: 3 series: SERVER_ERROR methods: GET,POST

retries:重试次数 series: SERVER_ERROR,下游服务报5XX系列的错误触发重试机制 methods:重试的HTTP方法

hi服务hello接口

@GetMapping("hello") public String hello(@RequestParam String name) { int i = 1 / 0; return "hi," + name + " ! " + "访问端口号:" + port; }

启动eureka、hi、limit服务

2、熔断Hystrix

添加 hystrix 依赖

<!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>

熔断配置

server: port: 8026 eureka: client: serviceUrl: defaultZone: http://localhost:8088/eureka/ spring: application: name: gateway-limit cloud: gateway: discovery: locator: enabled: true lowerCaseServiceId: true routes: - id: gateway_hi uri: lb://gateway-hi predicates: - Path=/hi/* filters: - StripPrefix=1 #熔断 - name: Hystrix args: name: localfallback fallbackUri: forward:/fallback

回调方法在网关服务

@RestController public class IndexController { @RequestMapping("/fallback") public String fallback() { System.out.println("fallback"); return "local fallback"; } }

启动服务 eureka、hi、gateway-limit 正常访问: http://localhost:8026/hi/hello?name=yzm

关闭hi服务,再次访问 服务hi不可达,网关回调fallback()方法

修改: 将回调方法部署到ha服务上

@RequestMapping("/fallback") public String fallback() { System.out.println("fallback"); return "ha fallback"; }

注释gateway服务上的fallback()方法

@RestController public class IndexController { // @RequestMapping("/fallback") public String fallback() { System.out.println("fallback"); return "local fallback"; } } spring: application: name: gateway-limit cloud: gateway: discovery: locator: enabled: true lowerCaseServiceId: true routes: - id: gateway_hi uri: lb://gateway-hi predicates: - Path=/hi/* filters: - StripPrefix=1 #熔断 - name: Hystrix args: name: remotefallback fallbackUri: forward:/fallback - id: gateway_ha uri: lb://gateway-ha predicates: - Path=/fallback

启动服务 eureka、ha、gateway-limit,不用启动hi 访问 http://localhost:8026/hi/hello?name=yzm

3、Redis实现限流

添加依赖 redis-reactive

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>

限流配置

spring: application: name: gateway-limit cloud: gateway: discovery: locator: enabled: true lowerCaseServiceId: true routes: - id: gateway_hi uri: lb://gateway-hi predicates: - Path=/hi/limit/* filters: - StripPrefix=2 #限流 - name: RequestRateLimiter args: key-resolver: '#{@remoteAddrKeyResolver}' redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率 redis-rate-limiter.burstCapacity: 3 #令牌桶容量 # redis连接配置 redis: host: 192.168.8.128 port: 6379 password: 1234 database: 0

key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。

键解析器

/** * 用于限流的键的解析器的 Bean 对象名字。 * 它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。 * 默认情况下,使用PrincipalNameKeyResolver,以请求认证的java.security.Principal作为限流键。 */ @Component public class RemoteAddrKeyResolver implements KeyResolver { @Override public Mono<String> resolve(ServerWebExchange exchange) { // 根据IP地址限流 String hostAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress(); System.out.println("hostAddress = " + hostAddress); // 根据请求地址限流 String uriPath = exchange.getRequest().getURI().getPath(); System.out.println("uriPath = " + uriPath); // 根据用户ID //String userId = exchange.getRequest().getQueryParams().getFirst("userId"); return Mono.just(hostAddress); } }

正常访问 快速刷新

4、使用过滤器实现令牌桶限流

引入依赖

<!-- 令牌桶 --> <dependency> <groupId>com.github.vladimir-bukhtoyarov</groupId> <artifactId>bucket4j-core</artifactId> <version>4.0.0</version> </dependency>

定义过滤器

/** * 根据IP Address限流 */ @Data @Slf4j @NoArgsConstructor @AllArgsConstructor public class RateLimitByIpGatewayFilter implements GatewayFilter, Ordered { //桶的最大容量,即能装载 Token 的最大数量 int capacity; //每次 Token 补充量 int refillTokens; //补充 Token 的时间间隔 Duration refillDuration; private static final Map<String, Bucket> CACHE = new ConcurrentHashMap<>(); private Bucket createNewBucket() { Refill refill = Refill.of(refillTokens, refillDuration); Bandwidth limit = Bandwidth.classic(capacity, refill); return Bucket4j.builder().addLimit(limit).build(); } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress(); Bucket bucket = CACHE.computeIfAbsent(ip, b -> createNewBucket()); log.info("IP: " + ip + ",TokenBucket Available Tokens: " + bucket.getAvailableTokens()); if (bucket.tryConsume(1)) { return chain.filter(exchange); } else { exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS); return exchange.getResponse().setComplete(); } } @Override public int getOrder() { return -1000; } }

配置路由

package com.yzm.gatewaylimit.config; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.Duration; @Configuration public class RouteConfig { @Bean public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) { return builder.routes() // 根据令牌限流 .route(p -> p .path("/ip/**") .filters(f -> f .stripPrefix(1) .filter(new RateLimitByIpGatewayFilter(3,1, Duration.ofSeconds(1)))) .uri("http://httpbin.org:80")) .build(); } }

桶最大容量3个,每秒产出1个token

快速刷新

相关链接

首页 上一篇:Gateway过滤器


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #gateway #熔断 #Gateway熔断限流