Spring Cloud Zuul RateLimit

Spring Cloud Netflix Zuul 的费率限制策略。「Rate limit strategy for Spring Cloud Netflix Zuul」

Github星跟蹤圖

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'

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

Usage

Latest version: Maven
Central

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:

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

Deny Request properties

Policy properties:

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
marcos.hgb@gmail.com.

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.

主要指標

概覽
名稱與所有者marcosbarbero/spring-cloud-zuul-ratelimit
主編程語言Java
編程語言Java (語言數: 3)
平台
許可證Apache License 2.0
所有者活动
創建於2016-04-14 17:49:19
推送於2025-06-10 02:12:42
最后一次提交2022-03-16 13:16:58
發布數48
最新版本名稱v2.4.3.RELEASE (發布於 )
第一版名稱v1.0.0.RELEASE (發布於 )
用户参与
星數1.1k
關注者數86
派生數387
提交數528
已啟用問題?
問題數178
打開的問題數0
拉請求數265
打開的拉請求數1
關閉的拉請求數220
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?