Multi dimensional current limiting of gateway

github https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit

Spring cloud zuul ratelimit description

Spring cloud zuul ratelimit is an extension of distributed current limiting strategy integrated with zuul

  • Restrict the flow of the requested target URL (for example, how many times a URL can be called per minute)
  • Restrict the access IP of the client (for example, how many requests are allowed per minute for an IP)
  • Restrict the flow of certain users or user groups (for example, non VIP users can only call an API 100 times per minute, etc.)
  • Multi dimensional mixed current limiting. At this point, we need to implement some flow restriction rules arrangement mechanism. Relationship with, or, not etc.

Current limiting granularity supported

  • Service granularity (default configuration, current limiting control of the current service module)
  • User granularity
    Implementation of user flow restriction: if your project integrates Shiro or Spring Security security framework, the user principle of the request domain will be maintained automatically. If it is your own framework, please log in successfully and maintain the user principle of the request domain before using user granularity flow restriction. The default value of not logged in is anonymous
  • Origin granularity (the origin of user request is used as granularity control)
    The current restriction of an IP client does not affect other clients, that is, the API gateway is independent of each client
  • URL interface granularity (address of request interface as granularity control)
  • The above granularity can be freely combined to support multiple situations.
  • If not, customize the RateLimitKeyGenerator implementation

Support data storage

  • InMemoryRateLimiter - use ConcurrentHashMap as data store
  • ConsulRateLimiter - use Consul as data store
  • RedisRateLimiter - use Redis as data store
  • JpaRateLimiter - use database as data store
  • Bucket4j JCache and other cache storage

pom dependency

        <dependency>
            <groupId>com.marcosbarbero.cloud</groupId>
            <artifactId>spring-cloud-zuul-ratelimit</artifactId>
            <version>1.7.1.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

Current limiting configuration

  • limit the number of accesses allowed per unit time
  • Total time allowed to access in unit time of quota (the total time of all requests in unit time window cannot exceed this time limit)
  • Refresh interval unit time setting
  • Type current limiting type
    1. url type flow restriction is distinguished by request path
    2. origin is distinguished by client IP address
    3. Users are distinguished by login user names, including anonymous users
  • Default policy optional - policy configured for all routes, unless policy list is specifically configured
  • policies restrict the flow of a specific service id
    • shortcoming
      • Multiple URLs can be configured, but these URLs all use a flow restriction configuration, and there is no way to specify the flow restriction configuration of each url
  • Policy list restricts the flow of a specific service id
    • advantage
      • You can specify different current limiting configurations for each url of a service id

policies configure multiple URLs to share a current limit number

zuul.routes.hello-feign.path=/hello-feign/**
zuul.routes.hello-feign.serviceId=feign-service-1

#*********************************************************
#  Specific routes
#
# The test client allows 10 accesses in 30 seconds, and the total request time is required to be less than 20 seconds
#
#*********************************************************
zuul.ratelimit.policies.hello-feign.limit=10
zuul.ratelimit.policies.hello-feign.quota=20
zuul.ratelimit.policies.hello-feign.refreshInterval=30

zuul.ratelimit.policies.hello-feign.type[0].type=url
zuul.ratelimit.policies.hello-feign.type[0].matcher=/custom/zuul/test

zuul.ratelimit.policies.hello-feign.type[1].type=url
zuul.ratelimit.policies.hello-feign.type[1].matcher=/custom/zuul/timeout

Policy list configures the current limit times of each url

zuul.routes.hello-feign.path=/hello-feign/**
zuul.routes.hello-feign.serviceId=feign-service-1

zuul.ratelimit.policy-list.hello-feign.[0].limit=10
zuul.ratelimit.policy-list.hello-feign.[0].quota=4
zuul.ratelimit.policy-list.hello-feign.[0].refreshInterval=10
zuul.ratelimit.policy-list.hello-feign.[0].type[0].type=url
zuul.ratelimit.policy-list.hello-feign.[0].type[0].matcher=/custom/zuul/test

zuul.ratelimit.policy-list.hello-feign.[1].limit=2
zuul.ratelimit.policy-list.hello-feign.[1].quota=4
zuul.ratelimit.policy-list.hello-feign.[1].refreshInterval=10
zuul.ratelimit.policy-list.hello-feign.[1].type[0].type=url
zuul.ratelimit.policy-list.hello-feign.[1].type[0].matcher=/request-body

Extend the key generated by the policy, because the default policy key will overwrite the policy corresponding to the current url during the configuration of the policy list.

@Configuration
public class CustomPolicy extends DefaultRateLimitKeyGenerator {

    private final RateLimitProperties properties;
    private final RateLimitUtils rateLimitUtils;


    public CustomPolicy(RateLimitProperties properties, RateLimitUtils rateLimitUtils) {
        super(properties, rateLimitUtils);
        this.properties = properties;
        this.rateLimitUtils = rateLimitUtils;
    }

    @Override
    public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) {
        // Get the index of the current policy
        int indexOf = properties.getPolicies(route.getId()).indexOf(policy);

        final List<RateLimitProperties.Policy.Type> types = policy.getType().stream().map(RateLimitProperties.Policy.MatchType::getType).collect(Collectors.toList());
        final StringJoiner joiner = new StringJoiner(":");
        joiner.add(properties.getKeyPrefix());
        if (route != null) {
            joiner.add(route.getId());
        }
        if (!types.isEmpty()) {
            if (types.contains(RateLimitProperties.Policy.Type.URL) && route != null) {
                joiner.add(route.getPath());
            }
            if (types.contains(RateLimitProperties.Policy.Type.ORIGIN)) {
                joiner.add(rateLimitUtils.getRemoteAddress(request));
            }
            if (types.contains(RateLimitProperties.Policy.Type.USER)) {
                joiner.add(rateLimitUtils.getUser(request));
            }
        }
        
        // Add index
        joiner.add(String.valueOf(indexOf));

        return joiner.toString();

    }
}

Other current limiting configuration items

# redis
spring.redis.port=6379
spring.redis.host=127.0.0.1
spring.redis.timeout=2000

# Open current limiting
zuul.ratelimit.enabled=true
# Prefix corresponding to the key used to identify the request
zuul.ratelimit.key-prefix=hello-feign
zuul.ratelimit.repository=redis
# After agent
zuul.ratelimit.behind-proxy=true

Tags: Spring Redis github Shiro

Posted on Thu, 14 May 2020 01:25:46 -0700 by visonardo