Giter VIP home page Giter VIP logo

marcosbarbero / spring-cloud-zuul-ratelimit Goto Github PK

View Code? Open in Web Editor NEW
1.1K 87.0 389.0 1.34 MB

Rate limit auto-configure for Spring Cloud Netflix Zuul

Home Page: https://blog.marcosbarbero.com/spring-cloud-netflix-zuul-rate-limit/

License: Apache License 2.0

Java 99.50% Shell 0.43% Lua 0.06%
netflix-zuul rate-limit spring-cloud spring-cloud-netflix open-source throttling throttle spring-cloud-netflix-zuul loader load-shedding

spring-cloud-zuul-ratelimit's Issues

failed to run zuul-ratelimit

I add the depency

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

and the yml is :

zuul:
  routes:
    mercury-service:
      path: /ark/open_api/**
      url:  http://mercury-default-upd-product.dev.xiaohongshu.com/
      stripPrefix: false
  ratelimit:
    enable: true
    behind-proxy: true
#    repository: JPA
    policies:
      mercury-service:
        limit: 2
        quota: 1
        refresh-interval: 30
        type:
          - URL
          - ORIGIN
          - USER

then I run the springboot application, but when I call the API,the policies is not used ,should I over write a filter extends RateLimitPreFilter.

Add spring-boot-configuration processor

Add the following dependency to the core module

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

dynamic config params without restart

how can I use the project with dynamic params, just as if I want to limit some special users in a certain time interval, or config some high rate for my promotion after add more services. I saw that the project must config these things in yaml, and it may restart service after change the config. So dose it has some special treatment for this issue?

ability to disable rate limiting basing on flag in request context

I would like to disable RateLimitPreFilter and RateLimitPostFilter on the fly.

It would be great to modify implementation of shouldFilter method for filters. For example it will stop liming when "rateLimitDisabled" flag in request context is present and set true.

Correction for readme.md

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

i think you need to pass RateLimitUtils also CMIIW

Validate maven central deployment

Add test projects using the latest release from maven central in order to validate the maven release:

  • create sample projects using latest version
  • clean .m2 repository
  • build the project using mvn clean package

need working sample for redis, as well as other storage methods

hi,
I could work with this project using IN_MEMORY as storage, however, when i used REDIS, I just failed many times that it failed to start with this exception,

No qualifying bean of type [org.springframework.data.redis.core.RedisTemplate] found for dependency [org.springframework.data.redis.core.RedisTemplate<?, ?>]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=rateLimiterRedisTemplate)}

could you please update a working sample for users to use this project quickly enough

Further customization problem

Further customization mentioned a bean injected to override RateLimitKeyGenerator.
I override the RateLimitKeyGenerator in Spring boot Application but got build errors.

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

            public String customkey(final HttpServletRequest request, final Route route, final Policy policy) {
                final List<Type> types = policy.getType();
                final StringJoiner joiner = new StringJoiner(":");
                joiner.add(properties.getKeyPrefix());
                if (route != null) {
                    joiner.add(route.getId());
                }
                if (!types.isEmpty()) {
                    if (types.contains(Type.URL) && route != null) {
                        // joiner.add(route.getPath());
                        // updated for full path + domain
                        joiner.add(route.getFullPath());
                    }
                    if (types.contains(Type.ORIGIN)) {
                        joiner.add(this.getRemoteAddress(request));
                    }
                    if (types.contains(Type.USER)) {
                        // joiner.add(request.getRemoteUser() != null ? request.getRemoteUser() :
                        // "ANONYMOUS_USER");
                        // updated for sid and token
                        String value = null;
                        Cookie[] cookies = request.getCookies();
                        if ((null != cookies) || (cookies.length != 0)) {
                            for (Cookie cookie : cookies) {
                                if (cookie.getName().equalsIgnoreCase(ConstantsBean.SID)) {
                                    value = cookie.getValue();
                                }
                            }
                        }
                        joiner.add(value);
                    }
                }
                return joiner.toString();
            }

            private String getRemoteAddress(final HttpServletRequest request) {
                String xForwardedFor = request.getHeader(X_FORWARDED_FOR_HEADER);
                if (properties.isBehindProxy() && xForwardedFor != null) {
                    return xForwardedFor;
                }
                return request.getRemoteAddr();
            }
        };
    }

maven install got following:

Description:

Parameter 0 of method rateLimitKeyGenerator in com.wanda.cloud.bss.apigw.ApiGatewayApplication required a bean of type 'com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties' that could not be found.


Action:

Consider defining a bean of type 'com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties' in your configuration.

2017-12-06 18:35:09.185 ERROR 8364 --- [           main] o.s.test.context.TestContextManager      : Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@2a32de6c] to prepare test instance [com.wanda.cloud.bss.apigw.ApiGatewayApplicationTests@4cc7d00d]

java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) ~[spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189) ~[spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131) ~[spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) ~[spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283) [surefire-junit4-2.18.1.jar:2.18.1]
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173) [surefire-junit4-2.18.1.jar:2.18.1]
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153) [surefire-junit4-2.18.1.jar:2.18.1]
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128) [surefire-junit4-2.18.1.jar:2.18.1]
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203) [surefire-booter-2.18.1.jar:2.18.1]
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155) [surefire-booter-2.18.1.jar:2.18.1]
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103) [surefire-booter-2.18.1.jar:2.18.1]

Any suggestions that if the injection has any problem

`policy(route, request)` called 4 times during handling one request

I was looking into filters and found that policy(route, request) is called 4 times during routing of the one request. Two times it is called in each shouldFilter and another 2 times in each run method of pre and post filters.
I think that this value could be computed on first shouldFilter and put into RequestContext.

The same applies to route(HttpServletRequest request) method.

WDYT?

Storage service downgrade

If the storage service fails, let the user decide in the configuration file whether or not to pass the check.

such as :
my repo is redis, but my redis server is done, RateLimitFilter Should it pass?
@marcosbarbero

How to use this situation

An application with @EnableZuulProxy could act as a standalone server if you set a default route ("/"), for example zuul.route.home: / would route all traffic (i.e. "/**") to the "home" service.

about ZuulRuntimeException

hi, in the code of RateLimitPreFilter,we will throw a Exception:ZuulRuntimeException to show Too Many Requests.
But as a gateway, I must ensure no exception throw to clients.
so I create a Error Filter as a adapter for the exceptions. I think if throw a custom Exception,it is easy use instanceof to distinguish.
For example, when there is a Too Many Requests Exception, I want to return client a custom string message.

Commands not supported in redis cluster

The methods multi and exec of class org.springframework.data.redis.core.RedisOperations are not supported in org.springframework.data.redis.connection.jedis.JedisClusterConnection, so it can`t work with redis cluster.

APPLICATION FAILED TO START

use version 1.3.4.RELEASE
add property zuul.ratelimit.repository
Parameter 0 of method rateLimiterPreFilter in com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.RateLimitAutoConfiguration required a bean of type 'com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimiter' that could not be found.
- Bean method 'consultRateLimiter' not loaded because @ConditionalOnProperty (zuul.ratelimit.repository=CONSUL) found different value in property 'repository'
- Bean method 'inMemoryRateLimiter' not loaded because @ConditionalOnProperty (zuul.ratelimit.repository=IN_MEMORY) found different value in property 'repository'
- Bean method 'redisRateLimiter' not loaded because @ConditionalOnProperty (zuul.ratelimit.repository=REDIS) found different value in property 'repository'
- Bean method 'springDataRateLimiter' not loaded because @ConditionalOnProperty (zuul.ratelimit.repository=JPA) found different value in property 'repository'

Rate limit by request time

we have seen cases that rate limit by request number is not enough
sometimes a single request can be long and load the gateway

adding an option to measure the request time and add another limit option by time quetta might help in such cases

@marcosbarbero do you think it's a good idea?

Multiple policy for one service

Hi another question is it possible to have multiple policy for one service tried by seems cant do it correctly
Lets say we wanted to have within 1 minute max 10 request, but within 1 hour max 100 request

about use custom redis

hi,I have tow question, if you have time, please give me some opinions, thank you.
First,i want use my redis config, so i create this class:

@Component
@Configuration
public class RedisRateLimiterConfiguration {

    @Autowired
    RedisTemplate redisTemplate;

    @Bean
    public RateLimiter redisRateLimiter(RateLimiterErrorHandler rateLimiterErrorHandler) {
        return new RedisRateLimiter(rateLimiterErrorHandler, redisTemplate);
    }
}

Because there is no wiki to know how to do, so my question is this is right or perfect way?

Second,RateLimitPreFilterand RateLimitPostFilter have hard coding filterOrder, how can i change it.

get ip security bug

com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitUtils
at 40 line
"String xForwardedFor = request.getHeader(X_FORWARDED_FOR_HEADER);"
should be "X-REAL-IP"

Failed to process import candidates for configuration class [com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.RateLimitAutoConfiguration

I tried run zuul-ratelimit, but i met some errors, i wish you can help me, thanks!

application.yml

server:
  port: 8080
spring:
  application:
    name: GETWAY

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

zuul:
  ratelimit:
    enabled: true
    behind-proxy: true
    policy-list:
      service:
        - limit: 10
          refresh-interval: 60
          type:
            - user
            - origin
            - url

pom.xml


<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/>
    </parent>
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>com.marcosbarbero.cloud</groupId>
            <artifactId>spring-cloud-zuul-ratelimit</artifactId>
            <version>1.7.2.RELEASE</version>
        </dependency>
    </dependencies>

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
2018-06-12 20:16:12.847 ERROR 4108 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.RateLimitAutoConfiguration]; nested exception is java.lang.ClassCastException: java.lang.UnsupportedClassVersionError cannot be cast to [Ljava.lang.Object;
	at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:616) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:299) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:606) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:548) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:185) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:308) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:270) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:93) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
	at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
	at com.bozhong.Application.main(Application.java:16) [classes/:na]
Caused by: java.lang.ClassCastException: java.lang.UnsupportedClassVersionError cannot be cast to [Ljava.lang.Object;
	at org.springframework.boot.context.properties.EnableConfigurationPropertiesImportSelector.selectImports(EnableConfigurationPropertiesImportSelector.java:54) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:586) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
	... 17 common frames omitted

Unable to find parent artefact 'spring-cloud-zuul-ratelimit-parent'

I am trying to add this dependency in my project.

On build, maven tries to fetch the url - https://jcenter.bintray.com/com/marcosbarbero/cloud/spring-cloud-zuul-ratelimit-parent/1.3.0.RELEASE/spring-cloud-zuul-ratelimit-parent-1.3.0.RELEASE.pom

And I get an error -
Failed to execute goal on project gateway-service: Could not resolve dependencies for project io.cimpress.abc.backbone.gateway:gateway-service:jar:1.0.0: Failed to collect dependencies at com.marcosbarbero.cloud:spring-cloud-zuul-ratelimit:jar:1.3.0.RELEASE: Failed to read artifact descriptor for com.marcosbarbero.cloud:spring-cloud-zuul-ratelimit:jar:1.3.0.RELEASE: Could not find artifact com.marcosbarbero.cloud:spring-cloud-zuul-ratelimit-parent:pom:1.3.0.RELEASE in central

On checking the file, spring-cloud-zuul-ratelimit/spring-cloud-zuul-ratelimit-core/pom.xml
I found that the parent artefact id is 'spring-cloud-zuul-ratelimit-parent' which I could not find in maven artefactory. I am not sure if this is the reason that I am not able to add dependency.

Can someone help me with this?
Thanks

Default policy configuration

Currently each service need to be configured in order to use rate limit
Since routes can be auto discovered in the gateway I think it will be a good idea to add a default policy configuration that can be overridden by each service

@marcosbarbero WDYT?

Get only origin IP instead of list from X-Forwarded-For when behind-proxy: true

In com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitUtils

    public String getRemoteAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader(X_FORWARDED_FOR_HEADER);
        if (properties.isBehindProxy() && xForwardedFor != null) {
            return xForwardedFor;
        }
        return request.getRemoteAddr();
    }

Since X-Forwarded-For is a list of IPs (X-Forwarded-For: client, proxy1, proxy2), I think it should return only the first IP (client IP) instead of all IP.

Add project on central maven

I didn't find any relative package on maven central. Can be a great addition to add it on maven central in order to easily use this starter

Policies required for every route on gateway

The method key make a request for policy.getTypes() after policy():

final Policy policy = this.policy();		
final Route route = route();
StringBuilder builder = new StringBuilder(route.getId());
if (policy.getType().contains(Policy.Type.ORIGIN)) {
...
if (policy.getType().contains(Policy.Type.USER)) {
...
private Policy policy() {
    return (route() != null) ? properties.getPolicies().get(route().getId()) : null;
}

So its implies that every route under the gateway should have a policy or it will throw a NullPointer.

InMemoryRateLimiter

  1. good job, but when i use it in my project (the version is Brixton.RELEASE) , can't find this class org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException

AbstractRateLimitFilter improvements

  1. I suppose it makes sense to extract applyPolicy to the separate class, that would contain a list of other filters, not knowing about concrete implementations. This change will give possibility to add custom policy filters.
    Something like that:
    private final List<PolicyFilter> filters;
    private final MatchersByTypeIndex matchersIndex;

    @Override
    public boolean filter(HttpServletRequest request, Route route, 
                                       RateLimitProperties.Policy policy) {
        return policy.getType().isEmpty() || allFiltersApply(request, route, policy);
    }

    private boolean allFiltersApply(HttpServletRequest request, Route route, 
                                                        RateLimitProperties.Policy policy) {
        return filters
                .stream()
                .allMatch(policyFilter -> {
                    Set<String> matchers = matchersIndex.get(policyFilter.getType());
                    return policyFilter.filter(matchers, request, route);
                });
    }
  1. Consider using Set instead of List for users and origins in userApply and originApply methods. Complexity of contains operation on set is O(1), on list is O(n). Usage of Set will not degrade app if big amount of matchers is added.
  2. getConfiguredType can be precomputed on startup and instead of list can be saved into map<Type, Set>. So for example instead of:
    private boolean urlApply(List<MatchType> types, Route route) {
        List<String> urls = getConfiguredType(types, Type.URL);

        return urls.isEmpty()
            || route == null
            || urls.stream().anyMatch(url -> route.getPath().startsWith(url));
    }

it can be done this way:

    private boolean urlApply(List<MatchType> types, Route route) {
        Set<String> urls = matchersIndex.getOrDefault(Type.URL, Collections.emptySet());

        return urls.isEmpty()
            || route == null
            || urls.stream().anyMatch(url -> route.getPath().startsWith(url));
    }

This would decrease complexity of the method.

If you are interested I would like to open PRs with described changes.

Support multiple policies

Currently only supports a policy, but in many cases, we need a variety of strategies for different current limit, so I would like to modify the code to support multiple policies, you think of this idea? I now have a fork branch that does this 23mf:feat-support-policies

Registering multiple rate limiters

My use case: I would like to do rate limiting in context of multiple keys.

For example limit number of requests to 10 req/s for key = client+tenant+user but 1000 req/s for key = client+tenant.

Is it possible to accomplish this with current implementation?

Request.getRemoteUser () is always null.

I use eureka, zuul and oauth (spring-cloud-starter-oauth2), request.getRemoteUser () is always null.
In DefaultRateLimitKeyGenerator:

if (types.contains(Type.USER)) {
    joiner.add(request.getRemoteUser() != null ? request.getRemoteUser() : ANONYMOUS_USER);
}

I miss some something?

Move filter order to configuration

I was considering using your library for rate limiting and the only thing that is bothering me is the hardcoded order of the filters. We have a bunch of custom filters in Zuul that retrieve user data and based on this data we would like to do rate limiting. That means that RateLimitPreFilter should be placed after our custom filters. What do you think about moving filterOrder to configuration?
Thanks

JPA uses MySQL reserved `KEY` keyword

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'varchar(255) not null, expiration datetime, remaining bigint, remaining_quota bi' at line 1
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_101]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_101]
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_101]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_101]

I know the reason, because of the use of the MySQL keyword key.
I revise as follows:

create table rate (key2 varchar(255) not null, expiration datetime, remaining bigint, remaining_quota bigint, reset bigint, primary key (key2))

It can run.
I use MySql version 5.7.20.
image

MySQL Keywords reference

NPE in DefaultRateLimitKeyGenerator

In the case that someone tries to access a url without a route, NPE is thrown.
This is because it tries to get the id and the path from the route

Caused by: java.lang.NullPointerException: null
	at com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.DefaultRateLimitKeyGenerator.key(DefaultRateLimitKeyGenerator.java:46)
	at com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.filters.RateLimitPreFilter.lambda$run$0(RateLimitPreFilter.java:76)
	at java.util.Optional.ifPresent(Optional.java:159)
	at com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.filters.RateLimitPreFilter.run(RateLimitPreFilter.java:75)
	at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112)
	at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193)

Is that possible to control rate limit dynamically?

In my case, service#1 and service#2 are sharing a same request pool (to access a thirdparty service). The access rate of service#2 is very unstable, usually it's free, but sometimes many connections may come in suddenly and it will become very busy

What I want to implemented is: limit service#1 to 5 qps as a basic, limit service#2 to 10 qps as a basic, when service#1 reaches its limit, I want to check if service#2 is busy or not , if service#2 is not very busy, I will let service#1 steal 1 quota from service#2 for this perticular access.

A service with different interfaces has different policies

This is my application.yml

  ratelimit:
    key-prefix:
    enabled: true
    repository: IN_MEMORY
    behind-proxy: true
    default-policy-list:
      - limit: 10
        quota: 1000
        refresh-interval: 60
        type:
          - url=/api/get/4Kb
      - limit: 20
        quota: 1000
        refresh-interval: 60
        type:
          - url=/hello/hi

Then access /api/get/256Byte ,it will report the following error,how to configure multiple interfaces different policies?

this is ErrorFilter : Duplicate key RateLimitProperties.Policy(refreshInterval=60, limit=10, quota=1000, type=[RateLimitProperties.Policy.MatchType(type=URL, matcher=/api/get/4Kb)])

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.