/spring-cloud-zuul-ratelimit

Rate limit strategy for Spring Cloud Netflix Zuul

Primary LanguageJavaApache License 2.0Apache-2.0

Spring Cloud Zuul RateLimit Build Status Coverage Status Join the chat at https://gitter.im/spring-cloud-zuul-ratelimit/Lobby

Module to enable rate limit per service in Netflix Zuul.
There are four built-in rate limit approaches:

  • Authenticated User
    • Uses the authenticated username or 'anonymous'
  • Request Origin
    • Uses the user origin request
  • URL
    • Uses the request path of the downstream service
  • Global configuration per service:
    • This one does not validate the request Origin, Authenticated User or URI
    • To use this approach just don't set param 'type'

Note: It is possible to combine Authenticated User, Request Origin and URL just adding multiple values to the list

Usage

This project is available on maven central

Add the dependency on pom.xml

<dependency>
    <groupId>com.marcosbarbero.cloud</groupId>
    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
    <version>1.5.0.RELEASE</version>
</dependency>

Add the following dependency accordingly to the chosen data storage:

  1. Redis
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
  1. Consul
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-consul</artifactId>
</dependency>
  1. Spring Data JPA
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
  1. InMemory
    For InMemory implementation there's no need to add any extra dependency other than com.marcosbarbero.cloud:spring-cloud-zuul-ratelimit

Sample configuration

zuul:
  ratelimit:
    key-prefix: your-prefix 
    enabled: true 
    repository: REDIS 
    behind-proxy: true
    default-policy: #deprecated - please use "default-policy-list"
      limit: 10 #optional - request number limit per refresh interval window
      quota: 1000 #optional - request time limit per refresh interval window (in seconds)
      refresh-interval: 60 #default value (in seconds)
      type: #optional
        - user
        - origin
        - url
    default-policy-list: #optional - will apply unless specific policy exists
      - limit: 10 #optional - request number limit per refresh interval window
        quota: 1000 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 60 #default value (in seconds)
        type: #optional
          - user
          - origin
          - url
    policies: #deprecated - please use "policy-list"
      myServiceId:
        limit: 10 #optional - request number limit per refresh interval window
        quota: 1000 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 60 #default value (in seconds)
        type: #optional
          - user
          - origin
          - url
    policy-list:
      myServiceId:
        - limit: 10 #optional - request number limit per refresh interval window
          quota: 1000 #optional - request time limit per refresh interval window (in seconds)
          refresh-interval: 60 #default value (in seconds)
          type: #optional
            - user
            - origin
            - url

Available implementations

There are four implementations provided:

  • InMemoryRateLimiter - uses ConcurrentHashMap as data storage
  • ConsulRateLimiter - uses Consul as data storage
  • RedisRateLimiter - uses Redis as data storage
  • SpringDataRateLimiter - uses Spring Data as data storage

Common application properties

Property namespace: zuul.ratelimit

Property name Values Default Value
enabled true/false false
behind-proxy true/false false
key-prefix String ${spring.application.name:rate-limit-application}
repository CONSUL, REDIS, JPA, IN_MEMORY IN_MEMORY
default-policy Policy -
policies Map of Policy -
default-policy-list List of Policy -
policy-list Map of Lists of Policy -

Policy properties:

Property name Values Default Value
limit number of calls -
quota time of calls -
refresh-interval seconds 60
type [ORIGIN, USER, URL] []

Further Customization

This section details how to add custom implementations

Key Generator

If the application needs to control the key strategy beyond the options offered by the type property then it can be done just by creating a custom RateLimitKeyGenerator implementation adding further qualifiers or something entirely different:

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

Error Handling

This framework uses some 3rd party applications to store and control the rate limit access, as it does not has control over those applications and they can fail once a while the framework itself handles the failure in the class DefaultRateLimiterErrorHandler just by adding some error logs.

If there is a need to handle the errors differently, it can be achieved just by defining a custom RateLimiterErrorHandler bean, e.g:

  @Bean
  public RateLimiterErrorHandler rateLimitErrorHandler() {
    return new DefaultRateLimiterErrorHandler() {
        @Override
        public void handleSaveError(String key, Exception e) {
            // custom code
        }
        
        @Override
        public void handleFetchError(String key, Exception e) {
            // custom code
        }
        
        @Override
        public void handleError(String msg, Exception e) {
            // custom code
        }
    }
  }

Contributing

Spring Cloud Zuul Rate Limit is released under the non-restrictive Apache 2.0 license, and follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below.

Adding Project Lombok Agent

This project uses Project Lombok to generate getters and setters etc. Compiling from the command line this shouldn't cause any problems, but in an IDE you need to add an agent to the JVM. Full instructions can be found in the Lombok website. The sign that you need to do this is a lot of compiler errors to do with missing methods and fields.

Code of Conduct

This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to marcos.hgb@gmail.com.

Acknowledgement

Footnote

Any doubt open an issue.
Any fix send me a Pull Request.