当前位置:主页 > java教程 > Spring Cloud Netflix Zuul中的速率限制

Spring Cloud Netflix Zuul中的速率限制详解

发布:2019-06-10 15:28:30 202


本站收集了一篇相关的编程文章,网友赖明俊根据主题投稿了本篇教程内容,涉及到Spring、Cloud、Netflix、Zuul速率限制、Spring、Cloud、Netflix、Zuul、Spring Cloud Netflix Zuul中的速率限制相关内容,已被332网友关注,相关难点技巧可以阅读下方的电子资料。

Spring Cloud Netflix Zuul中的速率限制

Spring Cloud Netflix Zuul是一个包含Netflix Zuul的 开源网关。它为Spring Boot应用程序添加了一些特定功能。不幸的是,开箱即用不提供速率限制。

除了Spring Cloud Netflix Zuul依赖项之外,我们还需要将Spring Cloud Zuul RateLimit 添加到我们的应用程序的pom.xml中:

<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
 <groupId>com.marcosbarbero.cloud</groupId>
 <artifactId>spring-cloud-zuul-ratelimit</artifactId>
 <version>2.2.0.RELEASE</version>
</dependency>

首先,让我们创建几个REST端点,我们将在其上应用速率限制。

下面是一个简单的Spring Controller类,有两个端点:

@Controller
@RequestMapping("/greeting")
public class GreetingController {
 
 @GetMapping("/simple")
 public ResponseEntity<String> getSimple() {
  return ResponseEntity.ok("Hi!");
 }
 
 @GetMapping("/advanced")
 public ResponseEntity<String> getAdvanced() {
  return ResponseEntity.ok("Hello, how you doing?");
 }
}

让我们在application.yml文件中添加以下Zuul属性  :

zuul:
 routes:
 serviceSimple:
  path: /greeting/simple
  url: forward:/
 serviceAdvanced:
  path: /greeting/advanced
  url: forward:/
 ratelimit:
 enabled: true
 repository: JPA
 policy-list:
  serviceSimple:
  - limit: 5
   refresh-interval: 60
   type:
   - origin
  serviceAdvanced:
  - limit: 1
   refresh-interval: 2
   type:
   - origin
 strip-prefix: true

在zuul.routes下,我们提供端点详细信息。在zuul.ratelimit.policy-list下,我们为端点提供速率限制配置。该限属性指定的时间端点可以在内部被称为数字刷新间隔。

我们可以看到,我们为serviceSimple  端点添加了每60秒5个请求的速率限制。相比之下,  serviceAdvanced的速率限制为每2秒1个请求。

该类型配置指定其速率限制的方法,以下是可能的值:

  • origin - 基于用户原始请求的速率限制
  • url - 基于下游服务的请求路径的速率限制
  • user - 基于经过身份验证的用户名或“匿名”的速率限制
  • No value - 充当每项服务的全局配置。要使用这种方法,请不要设置参数'type'

接下来,让我们测试一下速率限制:

@Test
public void whenRequestNotExceedingCapacity_thenReturnOkResponse() {
 ResponseEntity<String> response = restTemplate.getForEntity(SIMPLE_GREETING, String.class);
 assertEquals(OK, response.getStatusCode());
 
 HttpHeaders headers = response.getHeaders();
 String key = "rate-limit-application_serviceSimple_127.0.0.1";
 
 assertEquals("5", headers.getFirst(HEADER_LIMIT + key));
 assertEquals("4", headers.getFirst(HEADER_REMAINING + key));
 assertEquals("60000", headers.getFirst(HEADER_RESET + key)); 
}

在这里,我们只对一个端点/ greeting / simple进行一次调用。请求成功,因为它在速率限制内。

另一个关键点是,对于每个响应,我们返回标头Header,为我们提供有关速率限制的更多信息。对于上述请求,我们将获得以下标头:

X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1: 5

X-RateLimit-Remaining-rate-limit-application_serviceSimple_127.0.0.1: 4

X-RateLimit-Reset-rate-limit-application_serviceSimple_127.0.0.1: 60000

解释:

  • X-RateLimit-Limit- [key]:为端点配置 的限制
  • X-RateLimit-Remaining- [key]:  调用端点的剩余尝试次数
  • X-RateLimit-Reset- [key]:为端点配置 的刷新间隔的剩余毫秒数

另外,如果我们再次立即触发相同的端点,我们可以得到:

X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1: 5

X-RateLimit-Remaining-rate-limit-application_serviceSimple_127.0.0.1: 3

X-RateLimit-Reset-rate-limit-application_serviceSimple_127.0.0.1: 57031

请注意减少的剩余尝试次数和剩余的毫秒数。

让我们看看当我们超过速率限制时会发生什么:

@Test
public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException {
 ResponseEntity<String> response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
 assertEquals(OK, response.getStatusCode());
  
 for (int i = 0; i < 2; i++) {
  response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
 }
 
 assertEquals(TOO_MANY_REQUESTS, response.getStatusCode());
 
 HttpHeaders headers = response.getHeaders();
 String key = "rate-limit-application_serviceAdvanced_127.0.0.1";
 
 assertEquals("1", headers.getFirst(HEADER_LIMIT + key));
 assertEquals("0", headers.getFirst(HEADER_REMAINING + key));
 assertNotEquals("2000", headers.getFirst(HEADER_RESET + key));
 
 TimeUnit.SECONDS.sleep(2);
 
 response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
 assertEquals(OK, response.getStatusCode());
}

在这里,我们快速连续两次调用,由于我们已将速率限制配置为每2秒一个请求,因此第二个调用将失败。结果,错误代码429(Too Many Requests)返回给客户端。以下是达到速率限制时返回的标头:

X-RateLimit-Limit-rate-limit-application_serviceAdvanced_127.0.0.1: 1

X-RateLimit-Remaining-rate-limit-application_serviceAdvanced_127.0.0.1: 0

X-RateLimit-Reset-rate-limit-application_serviceAdvanced_127.0.0.1: 268

之后,我们休息了2秒钟。这是为端点配置的刷新间隔。最后,我们再次触发端点并获得成功的响应。

自定义密钥生成器

我们可以使用自定义密钥生成器自定义响应头中发送的密钥。这很有用,因为应用程序可能需要控制除type属性提供的选项之外的密钥策略。

例如,这可以通过创建自定义的RateLimitKeyGenerator实现类来完成。我们可以添加更多的限定符或完全不同的东西:

@Bean
public RateLimitKeyGenerator rateLimitKeyGenerator(RateLimitProperties properties,
 RateLimitUtils rateLimitUtils) {
 return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) {
  @Override
  public String key(HttpServletRequest request, Route route,
   RateLimitProperties.Policy policy) {
   return super.key(request, route, policy) + "_" + request.getMethod();
  }
 };
}

上面的代码将REST方法名称附加到键。例如:

X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1_GET: 5

另一个关键点是  RateLimitKeyGenerator bean将由spring-cloud-zuul-ratelimit自动配置。

自定义错误处理

该框架支持速率限制数据存储的各种实现。例如,提供了Spring Data JPA和Redis。默认情况下,使用DefaultRateLimiterErrorHandler  类将故障记录为错误。

当我们需要以不同方式处理错误时,我们可以定义一个自定义的RateLimiterErrorHandler bean:

@Bean
public RateLimiterErrorHandler rateLimitErrorHandler() {
 return new DefaultRateLimiterErrorHandler() {
  @Override
  public void handleSaveError(String key, Exception e) {
   <i>// implementation</i>
  }
 
  @Override
  public void handleFetchError(String key, Exception e) {
   <i>// implementation</i>
  }
 
  @Override
  public void handleError(String msg, Exception e) {
   <i>// implementation</i>
  }
 };
}

与RateLimitKeyGenerator bean 类似  ,也将自动配置RateLimiterErrorHandler bean。

在GitHub上 找到本文的完整代码


参考资料

相关文章

  • Springboot整合策略模式详解

    发布:2023-04-26

    这篇文章主要介绍了Springboot整合策略模式详解的相关资料,需要的朋友可以参考下


  • Springboot Vue可配置调度任务实现示例详解

    发布:2023-03-01

    这篇文章主要为大家介绍了Springboot Vue可配置调度任务实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • springboot如何开启一个监听线程执行任务

    发布:2023-03-22

    这篇文章主要介绍了springboot如何开启一个监听线程执行任务问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教


  • SpringBoot使用统一异常处理实例讲解

    发布:2019-08-11

    这篇文章主要为大家详细介绍了SpringBoot使用统一异常处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • SpringMVC HttpMessageConverter报文信息转换器

    发布:2023-03-09

    ​​HttpMessageConverter​​​,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文。​​​HttpMessageConverter​​​提供了两个注解和两个类型:​​@RequestBody,@ResponseBody​​​,​​RequestEntity,ResponseEntity​​


  • SpringBoot在Controller层接收参数的n种姿势(超详细)

    发布:2023-03-11

    这篇文章主要介绍了SpringBoot在Controller层接收参数的常用方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下


  • 如何使用Spring integration在Springboot中集成Mqtt详解

    发布:2023-03-25

    MQTT是多个客户端通过一个中央服务器传递信息的多对多协议,能高效地将信息分发给一个或多个订阅者,下面这篇文章主要给大家介绍了关于如何使用Spring integration在Springboot中集成Mqtt的相关资料,需要的朋友可以参考下


  • spring kafka框架中@KafkaListener 注解解读和使用案例

    发布:2023-03-29

    Kafka 目前主要作为一个分布式的发布订阅式的消息系统使用,也是目前最流行的消息队列系统之一,这篇文章主要介绍了kafka @KafkaListener 注解解读,需要的朋友可以参考下


网友讨论