来源:SpringForAll社区

1.引言

Spring Cloud Netflix Zuul 是一个包含Netflix Zuul的开源网关。它为Spring Boot应用增加了一些特别的特性。不幸的是,开箱即用不提供速率限制。

在这篇教程中,我们将探索增加了速率限制请求的Spring Cloud Zuul RateLimit。

2.Maven配置

除了Spring Cloud Netflix Zuul的依赖,我们需要增加Spring Cloud Zuul RateLimit到我们应用的pom.xml。

  1. <dependency>

  2.    <groupId>org.springframework.cloud</groupId>

  3.    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>

  4. </dependency>

  5. <dependency>

  6.    <groupId>com.marcosbarbero.cloud</groupId>

  7.    <artifactId>spring-cloud-zuul-ratelimit</artifactId>

  8.    <version>2.2.0.RELEASE</version>

  9. </dependency>

3.Controller例子

首先,我们在将要应用速率限制的地方创建一些REST端点。 下面是一个简单的有两个端点的Spring Controller类。

  1. @Controller

  2. @RequestMapping("/greeting")

  3. public class GreetingController {

  4.    @GetMapping("/simple")

  5.    public ResponseEntity<String> getSimple() {

  6.        return ResponseEntity.ok("Hi!");

  7.    }

  8.    @GetMapping("/advanced")

  9.    public ResponseEntity<String> getAdvanced() {

  10.        return ResponseEntity.ok("Hello, how you doing?");

  11.    }

  12. }

就像我们看到的,在速率限制的端点上没有特别的代码。这是因为我们将要配置这些速率限制在我们的Zuul 配置文件application.yml上。因此,保持我们的代码解耦。

4.Zuul配置

第二步,我们增加如下Zuul 配置到我们的application.yml文件上。

  1. zuul:

  2.  routes:

  3.    serviceSimple:

  4.      path: /greeting/simple

  5.      url: forward:/

  6.    serviceAdvanced:

  7.      path: /greeting/advanced

  8.      url: forward:/

  9.  ratelimit:

  10.    enabled: true

  11.    repository: JPA

  12.    policy-list:

  13.      serviceSimple:

  14.        - limit: 5

  15.          refresh-interval: 60

  16.          type:

  17.            - origin

  18.      serviceAdvanced:

  19.        - limit: 1

  20.          refresh-interval: 2

  21.          type:

  22.            - origin

  23.  strip-prefix: true

在zuul.routes下,我们提供了端点详情。在zuul.ratelimit.policy-list下,我们为端点提供了速率限制配置。limit属性指定了端点在refresh-interval区间能被调用的次数。

就像我们看到的,我们为serviceSimple 端点增加了每60秒5次请求的速率限制。相反的,serviceAdvanced增加了每2秒1次请求的速率限制。

type配置制定了我们想要的速率限制方法。下面是一些可能的值:

  • origin-基于用户原始请求的速率限制

  • url-基于下游服务的请求路径的速率限制

  • user-基于认证用户名或匿名用户的速率限制

  • 空值-每一个服务使用一个全局配置,要使用这个方式只需要不设置参数‘type’

5.测试速率限制

5.1.请求在限额内

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

  1. @Test

  2. public void whenRequestNotExceedingCapacity_thenReturnOkResponse() {

  3.    ResponseEntity<String> response = restTemplate.getForEntity(SIMPLE_GREETING, String.class);

  4.    assertEquals(OK, response.getStatusCode());

  5.    HttpHeaders headers = response.getHeaders();

  6.    String key = "rate-limit-application_serviceSimple_127.0.0.1";

  7.    assertEquals("5", headers.getFirst(HEADER_LIMIT + key));

  8.    assertEquals("4", headers.getFirst(HEADER_REMAINING + key));

  9.    assertEquals("60000", headers.getFirst(HEADER_RESET + key));    

  10. }

这里我们创建一个到端点/greeting/simple的请求。这个请求在速率限制内是成功的。

另一个关键点是我们获得的每一个响应的响应头能提供我们更多的速率限制的信息。 对上面的请求,我们将得到如下的响应头。

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

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

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

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

另外,如果我们立即再次调用同样的端点,我们将得到

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

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

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

注意剩余调用次数和剩余调用毫秒时间已经减少。

5.2.请求在限额外

让我们看下超过限制速率将发生什么:

  1. @Test

  2. public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException {

  3.    ResponseEntity<String> response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);

  4.    assertEquals(OK, response.getStatusCode());

  5.    for (int i = 0; i < 2; i++) {

  6.        response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);

  7.    }

  8.    assertEquals(TOO_MANY_REQUESTS, response.getStatusCode());

  9.    HttpHeaders headers = response.getHeaders();

  10.    String key = "rate-limit-application_serviceAdvanced_127.0.0.1";

  11.    assertEquals("1", headers.getFirst(HEADER_LIMIT + key));

  12.    assertEquals("0", headers.getFirst(HEADER_REMAINING + key));

  13.    assertNotEquals("2000", headers.getFirst(HEADER_RESET + key));

  14.    TimeUnit.SECONDS.sleep(2);

  15.    response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);

  16.    assertEquals(OK, response.getStatusCode());

  17. }

这里我们快速连续调用/greeting/advanced 端点两次。因为我们配置了2秒只能1次请求的速率限制,第二次调用将会失败。错误码429(请求频繁)将作为结果返回给客户端。

下面是速率限制达到的时候返回的响应头:

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

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

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

之后,我们休眠2秒,这是为端点刷新区间配置。最后,我们再次调用端点并能获得成功的响应。

6.定制秘钥生成器

我们能使用一个秘钥生成器来在响应头中定制秘钥发送。这是很有用的,因为应用可能需要除了可选的type属性之外的控制秘钥策略。

举例说明,通过创建一个定制的RateLimitKeyGenerator 实现。我们能添加更多的限定符或一些完全不一样的事情:

  1. @Bean

  2. public RateLimitKeyGenerator rateLimitKeyGenerator(RateLimitProperties properties,

  3.  RateLimitUtils rateLimitUtils) {

  4.    return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) {

  5.        @Override

  6.        public String key(HttpServletRequest request, Route route,

  7.          RateLimitProperties.Policy policy) {

  8.            return super.key(request, route, policy) + "_" + request.getMethod();

  9.        }

  10.    };

  11. }

上面的代码为秘钥追加了REST方法名。举例:

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

另一个关键点是RateLimitKeyGenerator对象将被spring-cloud-zuul-ratelimit自动配置.

7.个性化错误处理

框架支持针对速率限制数据存储的各种各样的实现。举例来说:Spring Data JPA 和 Redis 都有提供。默认的,失败将通过DefaultRateLimiterErrorHandler类作为错误记录下来

当我们需要对错误进行不同处理时,我们能自定义RateLimiterErrorHandler 对象。

  1. @Bean

  2. public RateLimiterErrorHandler rateLimitErrorHandler() {

  3.    return new DefaultRateLimiterErrorHandler() {

  4.        @Override

  5.        public void handleSaveError(String key, Exception e) {

  6.            // implementation

  7.        }

  8.        @Override

  9.        public void handleFetchError(String key, Exception e) {

  10.            // implementation

  11.        }

  12.        @Override

  13.        public void handleError(String msg, Exception e) {

  14.            // implementation

  15.        }

  16.    };

  17. }

与RateLimitKeyGenerator 对象类似,RateLimiterErrorHandler 也会被自动配置。

8.总结

在这篇文章中,我们看到了怎样在Spring Cloud Netflix Zuul和Spring Cloud Zuul RateLimit中使用速率限制API。 一如既往,这篇文章的完整代码能在GitHub上找到。

原文链接:https://www.baeldung.com/spring-cloud-zuul-rate-limit

作者:Ganesh Pagade

译者:shirehappy

-END-

 近期热文:

  • 从内部自用到对外服务,配置管理的演进和设计优化实践

  • Spring Cloud Data Flow 中的 ETL

  • 如何判断一个元素在亿级数据中是否存在?

  • Minor GC、Major GC和Full GC之间的区别

  • 15个Spring的核心注释示例

  • Log4j2的性能为什么这么好?

  • 微服务架构如何保障双11狂欢下的99.99%高可用?

  • Spring Cloud Stream如何消费自己生产的消息?

关注我

点击“阅读原文”,看本号其他精彩内容

Spring Cloud Netflix Zuul中的速率限制相关推荐

  1. Spring Cloud Netflix Zuul 1.0 简化说明

    为什么80%的码农都做不了架构师?>>>    绿色部分表示 Spring 提供的组件.蓝色部分表示由 netflix 提供.橘色部分由用户自己提供. 转载于:https://my. ...

  2. SpringCloud - Spring Cloud Netflix 之 Zuul网关;路由(十一)

    阅读本文前可先参考 SpringCloud - Spring Cloud根/父项目,开发准备(二)_MinggeQingchun的博客-CSDN博客 一.API网关 引自百度百科 API网关,软件术语 ...

  3. Spring Cloud Netflix五大组件简介

    微服务与微服务架构 微服务的优缺点 优点 缺点 Dubbo与Spring Cloud Spring Cloud Netflix Eureka Eureka的自我保护机制 Eureka和ZooKeepe ...

  4. Spring Cloud Dalston.RELEASE中文文档

    Spring Cloud Dalston.RELEASE中文文档 Spring Cloud 目录 特性 云原生应用程序 Spring Cloud上下文:应用程序上下文服务 引导应用程序上下文 应用程序 ...

  5. spring cloud Netflix全套面试,这一篇就够了,3万字整理

    *spring cloud Netflix* 面试:springcloud https://blog.csdn.net/weixin_46577306/article/details/10690608 ...

  6. Spring Cloud Netflix项目进入维护模式之我见

    这两天看到一则新闻:https://spring.io/blog/2018/12/12/spring-cloud-greenwich-rc1-available-now#spring-cloud-ne ...

  7. SpringCloud学习笔记(1)- Spring Cloud Netflix

    文章目录 SpringCloud学习笔记(1)- Spring Cloud Netflix 单体应用存在的问题 Spring Cloud Eureka Eureka Server代码实现 Eureka ...

  8. Spring Cloud Netflix之Eureka上篇

    前言:Spring Cloud NetFlix这个项目对NetFlix中一些久经考验靠谱的服务发现,熔断,网关,智能路由,以及负载均衡等做了封装,并通过注解的或简单配置的方式提供给Spring Clo ...

  9. Spring Cloud Netflix中文文档翻译笔记

    原文地址:http://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/1.2.2.RELEASE/ Spring Cloud Net ...

最新文章

  1. 如何将 winston log 库记录的日志写入 mongo DB 数据库
  2. Storm 1.0.1发布 .NET 适配也已到来
  3. *p++,(*p)++,*++p,++*p有什么不同
  4. AjaxControlToolkit的使用
  5. boost升压电路原理
  6. 根据城市的三字代码查询经纬度_中国国内机场三字码及经纬度
  7. b站前端大佬_B站有哪些高质量的UP主值得推荐?
  8. 【VOIP】yate sip客户端直接呼叫
  9. python 写入excel 打开时暂停_Python 解决中文写入Excel时抛异常的问题
  10. 日本京瓷株式会社会长-稻盛和夫寄语汇总
  11. 驱动器阵列和容错方法(不同RAID的区别)
  12. mysql期中考试题及答案_MySQL数据库考试试题及答案 -
  13. skynet mysql 携程_有哪些小型后台服务端开源项目?
  14. 现行各主流语言的特点
  15. Shorten the command line via JAR manifest or via a classpath file and rerun.
  16. 证明:无理数的无理数次方是否还是无理数
  17. Lacking counting POJ.NO 2386
  18. Office2016 Visio2016 Project2016零售版转换VL版
  19. pythonQQ机器人系列:使用requests实现QQ机器人聊天(1-0)
  20. 恩布企业IM 1.9 版本,免费企业即时通讯软件

热门文章

  1. 区块链 简单实现介绍
  2. python yield 详解
  3. Linux国内源介绍
  4. linux下访问windows的共享
  5. sscanf,sscanf_s及其相关用法
  6. Linux2.6--进程抢占和上下文切换
  7. java设计模式---合成模式2
  8. Android--表格布局
  9. 大数据教父Micheal Stonebraker告诉你大数据的秘密
  10. 利用 libvirt 和 Linux 审计子系统跟踪 KVM 客户机