Spring Cloud Zuul RateLimit 简介

spring-cloud-zuul-ratelimit 是一个用于在基于 Spring Cloud Zuul 构建的微服务网关中实现速率限制(限流)的组件。它能够控制进入微服务系统的流量,防止系统因过多的请求而崩溃或性能下降。在分布式系统中,尤其是在面对高并发场景时,限流是保障系统稳定性和可用性的重要手段。

spring-cloud-zuul-ratelimit 用于在基于 Spring Cloud Zuul 构建的微服务网关中实现速率限制(限流)的组件。它能够控制进入微服务系统的流量,防止系统因过多的请求而崩溃或性能下降。在分布式系统中,尤其是在面对高并发场景时,限流是保障系统稳定性和可用性的重要手段。

spring-cloud-zuul-ratelimit 中有五种内置的速率限制方法:

  • USER:使用经过身份验证的用户名或“anonymous”。

  • ORIGIN:使用用户源请求。

  • URL:使用下游服务的请求路径。

  • URL_PATTERN:使用请求的 Ant 路径模式到下游服务。

  • ROLE:使用经过身份验证的用户角色。

  • HTTP_METHOD:使用 HTTP 请求方法。

  • HTTP_HEADER:使用 HTTP 请求头。

  • 每个服务的全局配置:

    • 此配置不验证请求来源、已认证用户或统一资源标识符(URI)。

    • 要使用这种方法,只需不设置参数“type”。

注意:可以将已认证用户、请求来源、统一资源定位符(URL)、角色(ROLE)和请求方法结合起来,只需向列表中添加多个值即可。

用法

最后版本:2.4.3.RELEASE

如果您使用的是 Spring Boot 1.5.x 版本,则必须使用 Spring Cloud Zuul RateLimit 1.7.x 版本。

在 pom.xml 中添加依赖项:

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

根据所选的数据存储相应地添加以下依赖项:

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>

此实现还需要一个数据库表,下面你可以找到一个示例脚本:

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 (依赖于 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 (依赖于 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 (依赖于 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>

示例 YAML 配置:

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

简单 Properties 配置:

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

“quota”(配额)和“refresh-interval”(刷新间隔)都可以用 Spring Boot 的时长格式表示:

    • 常规的长格式表示(默认以秒为单位)

    • Java 的 java.time.Duration 所使用的标准 ISO-8601 格式(例如 PT30M 表示 30 分钟)。

    • 一种更易读的格式,其中值和单位结合在一起(例如,10s 表示 10 秒)。

可用实现方式

提供了八种实现方式:

实现

数据存储

ConsulRateLimiter

Consul

RedisRateLimiter

Redis

SpringDataRateLimiter

Spring Data

Bucket4jJCacheRateLimiter

Bucket4j

Bucket4jHazelcastRateLimiter

Bucket4jIgniteRateLimiter

Bucket4jInfinispanRateLimiter

Bucket4j 实现需要使用 @Qualifier("RateLimit") 的相关 Bean:

  • JCache - javax.cache.Cache

  • Hazelcast - com.hazelcast.map.IMap

  • Ignite - org.apache.ignite.IgniteCache

  • Infinispan - org.infinispan.functional.ReadWriteMap

通用应用属性

属性命名空间:zuul.ratelimit

属性名

默认值

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

拒绝请求属性:

属性名

默认值

origins

被拒绝访问的来源列表表

-

response-status-code

被拒绝请求时要返回的 HTTP 状态码码

403 (FORBIDDEN)

策略属性:

属性名

默认值

limit

请求数量

-

quota

请求时间

-

refresh-interval

秒数

60

type

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

[]

breakOnMatch

true/false

false

更多定制

本节将详细介绍如何添加自定义实现

Key 生成器

如果应用程序需要在 type 属性提供的选项之外控制密钥策略,那么只需创建一个自定义的 RateLimitKeyGenerator bean 实现,添加更多限定符或其他完全不同的东西即可:

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

错误处理

本框架使用第三方应用程序控制速率限制访问,这些库不受本框架控制。如果其中一个第三方应用程序出现故障,框架将在 DefaultRateLimiterErrorHandler 类中处理该故障,并在故障发生时记录错误日志。

如果需要以不同方式处理错误,可以通过定义自定义的 RateLimiterErrorHandler Bean 来实现,例如:

@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
        }
    }
}

事件处理

如果应用程序需要在超过速率限制访问时收到通知,则可以通过监听 RateLimitExceededEvent 事件来实现:

@EventListener
public void observe(RateLimitExceededEvent event) {
    // custom code
}

👉官网地址:GitHub - marcosbarbero/spring-cloud-zuul-ratelimit: Rate limit auto-configure for Spring Cloud Netflix Zuul

 

锲而舍之,朽木不折;锲而不舍,金石可镂。——《荀子·劝学》
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号