项目作者: tangaiyun

项目描述 :
great Rate-limiter for Zuul
高级语言: Java
项目地址: git://github.com/tangaiyun/zuul-redislimiter-spring-boot.git
创建时间: 2018-12-13T11:54:12Z
项目社区:https://github.com/tangaiyun/zuul-redislimiter-spring-boot

开源协议:Apache License 2.0

下载


English | 中文

zuul-redislimiter-spring-boot

rate limiter for zuul

Quickstart

Clone, build and install

  1. git clone https://github.com/tangaiyun/zuul-redislimiter-spring-boot.git
  2. cd zuulredislimiter/zuul-redislimiter-spring-boot-starter
  3. mvn clean install

Add to your POM

Then create a zuul proxy project refer to sample project “zuulredislimiter/zuulapp”,and you need to add dependency in pom.xml

  1. package com.tay.zuulapp;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
  5. @SpringBootApplication
  6. @EnableZuulProxy
  7. public class ZuulappApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(ZuulappApplication.class, args);
  10. }
  11. }
  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.cloud</groupId>
  8. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-test</artifactId>
  13. <scope>test</scope>
  14. </dependency>
  15. <dependency>
  16. <groupId>com.tay</groupId>
  17. <artifactId>zuul-redislimiter-spring-boot-starter</artifactId>
  18. <version>0.0.1-SNAPSHOT</version>
  19. </dependency>
  20. </dependencies>

Configuration

For resources/application.yml you need to add the following lines.

  1. server:
  2. port: 8000
  3. spring:
  4. application:
  5. name: service-zuul
  6. zuul:
  7. routes:
  8. service1: /s1/**
  9. service2: /s2/**
  10. redis-limiter:
  11. redis-host: 127.0.0.1 #Redis server host
  12. policy-map:
  13. api-a: #limiting policy with serviceId api-a
  14. order: -1 #n policies matched, which with lower order value has high priority
  15. baseExp: Headers['userid'] #base on HTTP header with key "userid"
  16. pathRegExp: /s1/.* #URI pattern
  17. timeUnit: MINUTES #timeUnit, supports SECONDS,MINUTES,HOURS,DAYS
  18. permits: 2 #Number of visits allowed per a timeUnit
  19. api-a1:
  20. order: 0
  21. baseExp: Cookies['userid']
  22. pathRegExp: /s1.*
  23. timeUnit: MINUTES
  24. permits: 3
  25. api-b:
  26. order: 2
  27. baseExp: Headers['userid']
  28. pathRegExp: /s2/.*
  29. timeUnit: MINUTES
  30. permits: 5
  31. eureka:
  32. client:
  33. serviceUrl:
  34. defaultZone: http://localhost:8761/eureka/
  35. instance:
  36. prefer-ip-address: true

Create a sample microservice refer to zuulredislimiter/service1

  1. package com.tay.service1;
  2. import org.springframework.web.bind.annotation.GetMapping;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RestController;
  5. @RestController
  6. @RequestMapping("/demo1")
  7. public class Controller1 {
  8. @GetMapping("/test11")
  9. public String test1() {
  10. return "test11!";
  11. }
  12. @GetMapping("/test12")
  13. public String test2() {
  14. return "test12!";
  15. }
  16. }
  1. server:
  2. port: 8001
  3. spring:
  4. application:
  5. name: service1
  6. eureka:
  7. client:
  8. serviceUrl:
  9. defaultZone: http://localhost:8761/eureka/
  10. instance:
  11. prefer-ip-address: true

Create another sample microservice like zuulredislimiter/service2

  1. package com.tay.service2;
  2. import org.springframework.web.bind.annotation.GetMapping;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RestController;
  5. @RestController
  6. @RequestMapping("/demo2")
  7. public class Controller2 {
  8. @GetMapping("/test21")
  9. public String test1() {
  10. return "test21!";
  11. }
  12. @GetMapping("/test22")
  13. public String test2() {
  14. return "test22!";
  15. }
  16. }
  1. server:
  2. port: 8002
  3. spring:
  4. application:
  5. name: service2
  6. eureka:
  7. client:
  8. serviceUrl:
  9. defaultZone: http://localhost:8761/eureka/
  10. instance:
  11. prefer-ip-address: true

Create an Eureka server project like zuulredislimiter/eurekaserver

  1. package com.tay.eurekaserver;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
  5. @EnableEurekaServer
  6. @SpringBootApplication
  7. public class EurekaserverApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(EurekaserverApplication.class, args);
  10. }
  11. }
  1. server:
  2. port: 8761
  3. eureka:
  4. client:
  5. register-with-eureka: false
  6. fetch-registry: false

Start Redis server

Start Redis server on a local machine or with Docker.

  1. sudo docker run -d -p 6379:6379 redis

start eurekaserver project

start zuulapp project

start service1 project

start service2 project

Testing

You can use a HTTP client tool such as Postman, restd or curl, and get the URL http://localhost:8000/s2/demo2/test21. Don’t forget to add a pair value userid=tom in your HTTP request header. You will be able to find the user with userid “tom” can visit this url five times successfully at most in one minute.

Advanced Guide

Complete Configuration Items

  1. spring:
  2. redis-limiter:
  3. redis-host: 127.0.0.1 # redis server IP default:127.0.0.1
  4. redis-port: 6379 # redis service port default:6379
  5. redis-password: test # redis password default:null
  6. redis-connection-timeout: 2000 # redis connection timeout default:2000
  7. redis-pool-max-idle: 50 # redis pool max idle default: 50
  8. redis-pool-min-idle: 10 # redis pool mim idle default:10
  9. redis-pool-max-wait-millis -1 # max wait time for get connection default:-1
  10. redis-pool-max-total: 200 # max total connection default:200
  11. redis-key-prefix: #RL # key prefix for visit footprint default: #RL
  12. check-action-timeout: 100 # check action execution timeout default: 100
  13. channel #RLConfigChannel # conf change event pub/sub channel default: #RLConfigChannel
  14. policy-map: # rate limiting policies
  15. api-a: # unique service id
  16. order: -1 # order
  17. baseExp: Headers['userid'] # value to base on, Spel expression without "#", supports Headers['xxx'] or Cookies['xxx']
  18. pathRegExp: /s1/.* # URI path pattern, a Regular expression
  19. timeUnit: MINUTES # timeUnit supports SECONDS, MINUTES, HOURS,DAYS
  20. permits: 2 # Number of visits allowed per a timeUnit
  21. api-a1:
  22. order: 0
  23. baseExp: Headers['userid']
  24. pathRegExp: /s1.*
  25. timeUnit: MINUTES
  26. permits: 3
  27. ...

Dynamic configuration

We can change the limiting policy by internal RESTful API.

  1. @RequestMapping("/zuullimiterpolicy")
  2. public class LimitingPolicyResource {
  3. ...
  4. @PostMapping
  5. public void add(@RequestBody LimitingPolicy limitingPolicy, HttpServletResponse response) throws IOException{
  6. ...
  7. }
  8. @PutMapping
  9. public void update(@RequestBody LimitingPolicy limitingPolicy, HttpServletResponse response) throws IOException {
  10. ...
  11. }
  12. @GetMapping("/{serviceId}")
  13. public LimitingPolicy get(@PathVariable("serviceId") String serviceId) {
  14. ...
  15. }
  16. @DeleteMapping("/{serviceId}")
  17. public void delete(@PathVariable("serviceId") String serviceId) {
  18. ...
  19. }

Currently, this framework support four actions (add, update, query, delete).

For example (as in the zuulapp project)

The result will of GET http://localhost:8000/zuullimiterpolicy/api-a

  1. {
  2. "serviceId": "api-a",
  3. "order": -1,
  4. "baseExp": "Headers['userid']",
  5. "pathRegExp": "/s1/.*",
  6. "timeUnit": "MINUTES",
  7. "permits": 2,
  8. "delete": false
  9. }

If we want to update configuration, assign Content-Type as application/json, then excute PUT http://localhost:8000/zuullimiterpolicy, the request body as below:

  1. {
  2. "serviceId": "api-a",
  3. "order": -1,
  4. "baseExp": "Headers['userid']",
  5. "pathRegExp": "/s1/.*",
  6. "timeUnit": "MINUTES",
  7. "permits": 10,
  8. "delete": false
  9. }

then the limiting policy for service with serviceId “api-a” changed.

If we want to delete a limiting policy with serviceId “api-b”, execute DELETE http://localhost:8000/zuullimiterpolicy/api-b, the limiting policy with serviceId “api-b” will be deleted.

add a new limiting policy, assign Content-Type as application/json, then excute POST http://localhost:8000/zuullimiterpolicy, the request body as below:

  1. {
  2. "serviceId": "api-d",
  3. "order": -1,
  4. "baseExp": "Headers['userid']",
  5. "pathRegExp": "/s3/.*",
  6. "timeUnit": "MINUTES",
  7. "permits": 10,
  8. "delete": false
  9. }

please be careful, the serviceId and pathRegExp should not be conflict with existed limiting policy.