• Stars
    star
    1,138
  • Rank 40,938 (Top 0.9 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created over 8 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Rate limit auto-configure for Spring Cloud Netflix Zuul

Spring Cloud Zuul RateLimit Build Status Coverage Status Maven Central

Overview

Module to enable rate limit per service in Netflix Zuul.

There are five 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

  • URL Pattern

    • Uses the request Ant path pattern to the downstream service

  • ROLE

    • Uses the authenticated user roles

  • Request method

    • Uses the HTTP request method

  • Request header

    • Uses the HTTP request header

  • 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, URL, ROLE and Request Method just adding multiple values to the list

Usage

Note

Latest version: Maven Central

Note

If you are using Spring Boot version 1.5.x you MUST use Spring Cloud Zuul RateLimit version 1.7.x. Please take a look at the Maven Central and pick the latest artifact in this version line.

Add the dependency on pom.xml

<dependency>
    <groupId>com.marcosbarbero.cloud</groupId>
    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
    <version>${latest-version}</version>
</dependency>

Add the following dependency accordingly to the chosen data storage:

  • Redis

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • Consul

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-consul</artifactId>
</dependency>
  • Spring Data JPA

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

This implementation also requires a database table, bellow here you can find a sample script:

CREATE TABLE rate (
  rate_key VARCHAR(255) NOT NULL,
  remaining BIGINT,
  remaining_quota BIGINT,
  reset BIGINT,
  expiration TIMESTAMP,
  PRIMARY KEY(rate_key)
);
  • Bucket4j JCache

<dependency>
     <groupId>com.github.vladimir-bukhtoyarov</groupId>
     <artifactId>bucket4j-core</artifactId>
</dependency>
<dependency>
     <groupId>com.github.vladimir-bukhtoyarov</groupId>
     <artifactId>bucket4j-jcache</artifactId>
</dependency>
<dependency>
     <groupId>javax.cache</groupId>
     <artifactId>cache-api</artifactId>
</dependency>
  • Bucket4j Hazelcast (depends on Bucket4j JCache)

<dependency>
     <groupId>com.github.vladimir-bukhtoyarov</groupId>
     <artifactId>bucket4j-hazelcast</artifactId>
</dependency>
<dependency>
     <groupId>com.hazelcast</groupId>
     <artifactId>hazelcast</artifactId>
</dependency>
  • Bucket4j Infinispan (depends on Bucket4j JCache)

<dependency>
     <groupId>com.github.vladimir-bukhtoyarov</groupId>
     <artifactId>bucket4j-infinispan</artifactId>
</dependency>
<dependency>
     <groupId>org.infinispan</groupId>
     <artifactId>infinispan-core</artifactId>
</dependency>
  • Bucket4j Ignite (depends on Bucket4j JCache)

<dependency>
     <groupId>com.github.vladimir-bukhtoyarov</groupId>
     <artifactId>bucket4j-ignite</artifactId>
</dependency>
<dependency>
     <groupId>org.apache.ignite</groupId>
     <artifactId>ignite-core</artifactId>
</dependency>

Sample YAML configuration

zuul:
  ratelimit:
    key-prefix: your-prefix
    enabled: true
    repository: REDIS
    behind-proxy: true
    add-response-headers: true
    deny-request:
      response-status-code: 404 #default value is 403 (FORBIDDEN)
      origins:
        - 200.187.10.25
        - somedomain.com
    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
          - http_method
    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
        - type: #optional value for each type
            - user=anonymous
            - origin=somemachine.com
            - url=/api #url prefix
            - role=user
            - http_method=get #case insensitive
            - http_header=customHeader
        - type:
            - url_pattern=/api/*/payment

Sample Properties configuration

zuul.ratelimit.enabled=true
zuul.ratelimit.key-prefix=your-prefix
zuul.ratelimit.repository=REDIS
zuul.ratelimit.behind-proxy=true
zuul.ratelimit.add-response-headers=true

zuul.ratelimit.deny-request.response-status-code=404
zuul.ratelimit.deny-request.origins[0]=200.187.10.25
zuul.ratelimit.deny-request.origins[1]=somedomain.com

zuul.ratelimit.default-policy-list[0].limit=10
zuul.ratelimit.default-policy-list[0].quota=1000
zuul.ratelimit.default-policy-list[0].refresh-interval=60

# Adding multiple rate limit type
zuul.ratelimit.default-policy-list[0].type[0]=user
zuul.ratelimit.default-policy-list[0].type[1]=origin
zuul.ratelimit.default-policy-list[0].type[2]=url
zuul.ratelimit.default-policy-list[0].type[3]=http_method

# Adding the first rate limit policy to "myServiceId"
zuul.ratelimit.policy-list.myServiceId[0].limit=10
zuul.ratelimit.policy-list.myServiceId[0].quota=1000
zuul.ratelimit.policy-list.myServiceId[0].refresh-interval=60
zuul.ratelimit.policy-list.myServiceId[0].type[0]=user
zuul.ratelimit.policy-list.myServiceId[0].type[1]=origin
zuul.ratelimit.policy-list.myServiceId[0].type[2]=url

# Adding the second rate limit policy to "myServiceId"
zuul.ratelimit.policy-list.myServiceId[1].type[0]=user=anonymous
zuul.ratelimit.policy-list.myServiceId[1].type[1]=origin=somemachine.com
zuul.ratelimit.policy-list.myServiceId[1].type[2]=url_pattern=/api/*/payment
zuul.ratelimit.policy-list.myServiceId[1].type[3]=role=user
zuul.ratelimit.policy-list.myServiceId[1].type[4]=http_method=get
zuul.ratelimit.policy-list.myServiceId[1].type[5]=http_header=customHeader

Both 'quota' and 'refresh-interval', can be expressed with Spring Bootโ€™s duration formats:

  • A regular long representation (using seconds as the default unit)

  • The standard ISO-8601 format used by java.time.Duration (e.g. PT30M means 30 minutes)

  • A more readable format where the value and the unit are coupled (e.g. 10s means 10 seconds)

Available implementations

There are eight implementations provided:

Implementation Data Storage

ConsulRateLimiter

Consul

RedisRateLimiter

Redis

SpringDataRateLimiter

Spring Data

Bucket4jJCacheRateLimiter

Bucket4j

Bucket4jHazelcastRateLimiter

Bucket4jIgniteRateLimiter

Bucket4jInfinispanRateLimiter

Bucket4j implementations require the relevant bean with @Qualifier("RateLimit"):

  • JCache - javax.cache.Cache

  • Hazelcast - com.hazelcast.map.IMap

  • Ignite - org.apache.ignite.IgniteCache

  • Infinispan - org.infinispan.functional.ReadWriteMap

Common application properties

Property namespace: zuul.ratelimit

Property name Values Default Value

enabled

true/false

false

behind-proxy

true/false

false

response-headers

NONE, STANDARD, VERBOSE

VERBOSE

key-prefix

String

${spring.application.name:rate-limit-application}

repository

CONSUL, REDIS, JPA, BUCKET4J_JCACHE, BUCKET4J_HAZELCAST, BUCKET4J_INFINISPAN, BUCKET4J_IGNITE

-

deny-request

DenyRequest

-

default-policy-list

List of Policy

-

policy-list

Map of Lists of Policy

-

postFilterOrder

int

FilterConstants.SEND_RESPONSE_FILTER_ORDER - 10

preFilterOrder

int

FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER

Deny Request properties

Property name Values Default Value

origins

list of origins to have the access denied

-

response-status-code

the http status code to be returned on a denied request

403 (FORBIDDEN)

Policy properties:

Property name Values Default Value

limit

number of requests

-

quota

time of requests

-

refresh-interval

seconds

60

type

[ORIGIN, USER, URL, URL_PATTERN, ROLE, HTTP_METHOD, HTTP_HEADER]

[]

breakOnMatch

true/false

false

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 bean[1] implementation adding further qualifiers or something entirely different:

  @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();
          }
      };
  }

Error Handling

This framework uses 3rd party applications to control the rate limit access and these libraries are out of control of this framework. If one of the 3rd party applications fails, the framework will handle this failure in the DefaultRateLimiterErrorHandler class which will log the error upon failure.

If there is a need to handle the errors differently, it can be achieved by defining a custom RateLimiterErrorHandler bean[2], 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
        }
    }
  }

Event Handling

If the application needs to be notified when a rate limit access was exceeded then it can be done by listening to RateLimitExceededEvent event:

    @EventListener
    public void observe(RateLimitExceededEvent event) {
        // 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.

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 [email protected].

Acknowledgement

Jetbrains

Footnote

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


1. By declaring a new RateLimitKeyGenerator, you replace the DefaultRateLimitKeyGenerator.
2. By declaring a new RateLimitErrorHandler, you replace the DefaultRateLimitErrorHandler.

More Repositories

1

spring-boot2-oauth2-jwt

Read more http://blog.marcosbarbero.com/centralized-authorization-jwt-spring-boot2/
Java
155
star
2

spring-cloud-config-client-oauth2

OAuth2 - Spring Cloud Config Client
Java
14
star
3

spring-boot-starter-purge-accesslog

AccessLog purge strategy for spring boot applications
Java
11
star
4

spring-boot2-oauth2-opaque-token

Read more http://blog.marcosbarbero.com/oauth2-centralized-authorization-opaque-jdbc-spring-boot2
Java
11
star
5

airline-booking

Java
9
star
6

spring-cloud-starter-zuul-transformation

Transformation starter for Spring Cloud Netflix Zuul
Java
6
star
7

spring-boot-n-cloud-playground

There's no place like https://start.spring.io/
Java
5
star
8

spring-security-authserver-sample

Auth Server sample using spring-security-oauth2
Java
5
star
9

trade-bot

Simple bot implementation to perform some trading operations.
Java
4
star
10

devcommerce2016-microservices-power-patterns-pains

Devcommerce 2016 - The power patterns and the pains of microservice architecture
Java
3
star
11

coding-dojo-spring-boot

Java
3
star
12

spring-boot-auth0-sample

Demo Spring Boot project to connect to Auth0
Java
2
star
13

spring-security-starter-ldap

Ldap autoconfiguration
Java
2
star
14

netshoes-bootiful-microservices

Repository to keep sample projects for Netshoes tech talk
Java
2
star
15

spring-boot-per-request-datasource

Java
2
star
16

so-questions

Placeholder to tryout SO questions
Java
1
star
17

spring-boot-jooq-sample

Spring-Boot + JOOQ
Java
1
star
18

code-challenge

Java
1
star
19

cross-solar-java

Java
1
star
20

netshoes-bootiful-config-repo

Configuration properties repository
1
star
21

say-it-in-dutch

Repository to place notes from my Dutch lessons
1
star
22

bootiful-microservices

Bootiful microservices - Spring Cloud Netflix
Java
1
star
23

algorithm-challenge

Repository to store any algorithm challenge that I've found out there.
Java
1
star
24

ifood

Java
1
star
25

spring-boot-moip-integration

Moip Integration for spring-boot applications
Java
1
star