
服务限流
服务网关的一个重要功能即服务限流。在Zuul中虽然可以通过前置类型过滤器对有效请求和无效请求(参数有效性,合法性)进行校验,将无效请求隔离在服务网关之外(返回错误提示信息、异常信息)。但有的时候某一个时间点内突发有效请求量很大,超过了系统可承受的范围,此时可以依靠服务限流算法,限制该时间点内通过的请求数,保证系统可用,避免出现服务雪崩效应。
此时可以通过Spring Cloud提供的Resilience4j限速器(RateLimiter)进行限速,也可以使用spring-cloud-zuul-ratelimit包。
项目依赖
<!--Resilience4j依赖--><dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot2</artifactId><version>0.13.2</version></dependency><!--spring-cloud-zuul-ratelimit依赖--><dependency><groupId>com.marcosbarbero.cloud</groupId><artifactId>spring-cloud-zuul-ratelimit</artifactId><version>2.2.2.RELEASE</version></dependency>
使用Resilience4j限流
限流配置
#resilience4j限流配置resilience4j.ratelimiter.limiters.user-service.limit-for-period=3resilience4j.ratelimiter.limiters.user-service.limit-refresh-period-in-millis=5000resilience4j.ratelimiter.limiters.user-service.timeout-in-millis=10
上述配置中,resilience4j.ratelimiter.limiters.user-service.limit-for-period配置时间戳内的请求数(默认为50),limit-refresh-period-in-millis配置时间戳(单位毫秒,默认500),timeout-in-millis配置超时时间。user-service可以替换为其他有意义的名称。
限流过滤器
@Componentpublic class Resilience4jRateLimiterFilter extends ZuulFilter {//Resilience4j限速器注册机@Autowiredprivate RateLimiterRegistry rateLimiterRegistry;/*** 返回过滤器类型* @return 前置类型过滤器*/@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}/*** 返回过滤器执行顺序* @return*/@Overridepublic int filterOrder() {return FilterConstants.PRE_DECORATION_FILTER_ORDER+5;}/*** 返回过滤器是否执行拦截操作* @return 请求路径是否为/user/开头*/@Overridepublic boolean shouldFilter() {RequestContext requestContext=RequestContext.getCurrentContext();String uri=requestContext.getRequest().getRequestURI();return uri.startsWith("/user/");}/*** 过滤器具体执行业务逻辑* @return* @throws ZuulException*/@Overridepublic Object run() throws ZuulException {//获取Resilience4j限速器(key与配置文件的Key名称一致)RateLimiter rateLimiter=rateLimiterRegistry.rateLimiter("user-service");//限速器执行逻辑Callable<ResultMessage> callResult=()->new ResultMessage(true,"执行成功");//绑定限速器Callable<ResultMessage> callResult2=RateLimiter.decorateCallable(rateLimiter,callResult);//尝试获取执行结果Try<ResultMessage> resultMessageTry=Try.of(()->callResult2.call()).recover(ex->new ResultMessage(false,"超出限定流量,执行降级操作"));ResultMessage resultMessage=resultMessageTry.get();//执行结果返回true,说明在限流范围内,限流操作成功,继续执行后续的自定义过滤器if(resultMessage.isSuccess()){return null;}//超过限流范围处理RequestContext requestContext=RequestContext.getCurrentContext();requestContext.setSendZuulResponse(false);//不在路由到下一个执行顺序的过滤器,直接返回失败requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());//设置响应状态码(值为429)requestContext.getResponse().setContentType(MediaType.APPLICATION_JSON_VALUE);//设置响应类型(APPLICATION_JSON_UTF8_VALUE已废弃)ObjectMapper responseMapper=new ObjectMapper();String responseBody=null;try {responseBody=responseMapper.writeValueAsString(resultMessage);//将执行结果转换为字符串并输出}catch (Exception e){e.printStackTrace();}requestContext.setResponseBody(responseBody);return null;}}
在开发Zuul过滤器的过程中,需要熟悉Zuul过滤器类型及Zuul内置过滤器执行顺序。本例中,限流过滤器应该在过滤有效请求(请求参数有效)后执行,故过滤器执行顺序为前置(pre)过滤器PreDecorationFilter后路由(route)过滤器前(PreDecorationFilter用于处理请求上下文,SimpleHostRoutingFilter用于具体的URL请求转发)。

我们将Resilience4jRateLimiterFilter(Resilience4j限速过滤器)声明为组件(@Component),在入口程序中被扫描发现并装配;注入限速注册机(RateLimiterRegistry),通过限速注册机获取具体的Resilience4j限速器实例(rateLimiterRegistry.rateLimiter(key));通过RateLimiter.decorateCallable方法(参数为Resilience4j实例,限速器业务逻辑);在尝试获取执行结果的过程中发生异常(限流操作超出限制范围),通过recover方法实现服务降级相关操作(返回缓存结果、服务降级信息、异常),提供更好的用户体验;未超过服务限流范围执行后续的过滤器操作,超过服务限流范围则设置响应信息给服务调用方展现。
Spring-cloud-zuul-ratelimit限流
为了防止微服务系统中的服务调用接口被恶意频繁请求调用,需要在服务网关层进行服务限流对服务调用接口安全性进行保护。使用spring-cloud-zuul-ratelimit可以在Zuul的基础上实现服务网关限流相关功能。
限流方式
| 限流方式 | 限流描述 |
| Authenticated User(认证用户) | 使用已经认证的用户名或'anonymous' |
| Request Origin(原始请求) | 使用用户的原始请求 |
| URL | 使用上游请求的地址 |
| Global configuration per service(全局配置) | 针对每个服务的全局配置,无需指定限流方式 |
配置详解
#spring-cloud-zuul-ratelimit配置(全局配置)#是否开启限速配置(boolean,默认false)zuul.ratelimit.enabled=true#使用Redis缓存对应的度量数据zuul.ratelimit.repository=redis#是否开启代理服务(boolean,默认false)zuul.ratelimit.behind-proxy=true#是否添加响应报头(boolean,默认false)zuul.ratelimit.add-response-header=true#每个刷新时间窗口对应的请求数量限制zuul.ratelimit.default-policy.limit=10#每个刷新时间窗口对应的请求时间限制zuul.ratelimit.default-policy.quota=1000#刷新时间窗口时间(默认60,单位秒)zuul.ratelimit.default-policy.refresh-interval=60#全局限流方式(可选,user,origin,url)zuul.ratelimit.default-policy.type=user#spring-cloud-zuul-ratelimit配置(服务实例配置)#限制用户微服务实例(user-service)刷新时间窗口对应的请求数量限制zuul.ratelimit.user-service.limit=5#限制用户微服务实例(user-service)刷新时间窗口对应的请求时间限制zuul.ratelimit.user-service.quota=100#限制用户微服务实例(user-service)限流方式zuul.ratelimit.user-service.type=origin




