本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3
本文基于前两篇文章eureka-server、eureka-client、eureka-ribbon、eureka-feign和spring-gataway的实现。
参考
在高并发应用中,缓存、限流、降级,是我们保护系统应用的三大利器。在开发一些api接口的时候,通常也会在网关层做限流控制,一方面是为了防止大量的请求是服务器过载,导致服务器不可用,另一方面也是防止其他人的恶习网络攻击。
常见的限流方式,如Hystrix的使用线程池隔离,超过线程池的负载走熔断的逻辑;也有通过滑动的时间窗口来控制流量。
常用的限流算法有,计数器算法、漏桶算法、令牌桶算法,这里就不对相关算法进行描述。
Spring Cloud Gateway的熔断可以基于Hystrix实现。可以参考 spring cloud 2.x版本 Hystrix Dashboard断路器教程 。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
server: port: 8100 spring: redis: host: localhost port: 6379 application: name: spring-gateway cloud: gateway: discovery: locator: enabled: true # 开启通过服务中心的自动根据 serviceId 创建路由的功能 default-filters: - My=true routes: - id: ribbon-route uri: lb://EUREKA-RIBBON order: 0 predicates: - Path=/ribbon/** filters: - name: Hystrix args: name: fallback fallbackUri: forward:/fallback - StripPrefix=1 #去掉前缀,具体实现参考StripPrefixGatewayFilterFactory - AddResponseHeader=X-Response-Default-Foo, Default-Bar - id: feign-route uri: lb://EUREKA-FEIGN order: 0 predicates: - Path=/feign/** filters: - StripPrefix=1 - AddResponseHeader=X-Response-Default-Foo, Default-Bar eureka: instance: hostname: eureka1.server.com lease-renewal-interval-in-seconds: 5 lease-expiration-duration-in-seconds: 10 client: service-url: defaultZone: http://eureka1.server.com:8701/eureka/,http://eureka2.server.com:8702/eureka/,http://eureka3.server.com:8703/eureka/
只设置ribbon的路由熔断,feign设置和ribbon相同。
package spring.cloud.demo.spring.gateway.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class FallBackController { @GetMapping("/fallback") public String fallback() { return "Error:fallback"; } }
启动eureka-server、eureka-client、eureka-ribbon、spring-gateway相关服务,访问 http://localhost :8100/ribbon/sayHello地址,页面显示结果如下:
然后我们将eureka-ribbon服务停掉,刷新页面,返回结果如下:
至此:熔断的简单配置实现就完成了,如需自定义熔断策略可以参考HystrixGatewayFilter的内容。
Spring Cloud Gateway官方提供了RequestRateLimiterGatewayFilterFactory类,使用redis和lua脚本来实现令牌桶的方式。我们也可以基于Google Guava中的RateLimiter、Bucket4j、RateLimitJ来实现。本文将采用官方提供的方式来实现。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>
server: port: 8100 spring: redis: host: localhost port: 6379 application: name: spring-gateway cloud: gateway: discovery: locator: enabled: true # 开启通过服务中心的自动根据 serviceId 创建路由的功能 default-filters: - My=true routes: - id: ribbon-route uri: lb://EUREKA-RIBBON order: 0 predicates: - Path=/ribbon/** filters: - name: RequestRateLimiter args: key-resolver: '#{@ipKeyResolver}' redis-rate-limiter.replenishRate: 200 redis-rate-limiter.burstCapacity: 400 - name: Hystrix args: name: fallback fallbackUri: forward:/fallback - StripPrefix=1 #去掉前缀,具体实现参考StripPrefixGatewayFilterFactory - AddResponseHeader=X-Response-Default-Foo, Default-Bar - id: feign-route uri: lb://EUREKA-FEIGN order: 0 predicates: - Path=/feign/** filters: - StripPrefix=1 - AddResponseHeader=X-Response-Default-Foo, Default-Bar eureka: instance: hostname: eureka1.server.com lease-renewal-interval-in-seconds: 5 lease-expiration-duration-in-seconds: 10 client: service-url: defaultZone: http://eureka1.server.com:8701/eureka/,http://eureka2.server.com:8702/eureka/,http://eureka3.server.com:8703/eureka/
说明:
package spring.cloud.demo.spring.gateway.config; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; @Configuration public class BeanConfig { @Bean public KeyResolver ipKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); } }
这里设置的是ip的限流。
首先启动redis服务,然后顺序启动eureka-server、eureka-client、eureka-ribbon、spring-gateway相关服务,访问 http://localhost :8100/ribbon/sayHello。为了演示方便可以将redis-rate-limiter.replenishRate和redis-rate-limiter.burstCapacity参数设置成1和3,然后疯狂刷新页面可以看到有请求失败的情况(最好使用压测工具来演示)。同时我们还要打开redis的监控(monitor命令),可以看到redis的监控,如下:
说明:redis中会有2个key,request_rate_limiter.{xxx}.timestamp和request_rate_limiter.{xxx}.tokens
本文简单的实现了Gateway的熔断和限流。总体来说Spring Cloud Gateway提供的路由网关、过滤器、熔断、限流还是都比较简单,也非常灵活,可以根据自己的需求来自定义。
gitHub地址
<center><font color=red>《Srping Cloud 2.X小白教程》目录</font></center>