marcosbarbero / spring-cloud-zuul-ratelimit

Rate limit auto-configure for Spring Cloud Netflix Zuul
https://blog.marcosbarbero.com/spring-cloud-netflix-zuul-rate-limit/
Apache License 2.0
1.14k stars 389 forks source link

Rate limitting depending on the number of calls for the user? #119

Closed Paxon96 closed 6 years ago

Paxon96 commented 6 years ago

Hi. I have already written at http://blog.marcosbarbero.com/spring-cloud-netflix-zuul-rate-limit/. And as I sad, I need to rate limitting be depending on the number of calls for the user and not for the entire service. As I understand, type: - user should work, but it does not really work. Any ideas or suggestions? Or maybe I misunderstood this property :c

My property:

zuul:
  #ignoredServices: '*'
  debug:
    request: true
  prefix: /some/endpoint
  ratelimit:
    enabled: true
    repository: CONSUL
    behind-proxy: true
    default-policy-list:
    - limit: 10 #optional - request number limit per refresh interval window
      quota: 60 #optional - request time limit per refresh interval window (in seconds)
      refresh-interval: 30 #default value 60 (in seconds)
    policy-list:
      MyServiceID:
      - limit: 10 #optional - request number limit per refresh interval window
        quota: 60 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 30 #default value (in seconds)
        type: #optional
        - user
        - origin
        - url=/endpoint1
      - limit: 10 #optional - request number limit per refresh interval window
        quota: 60 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 30 #default value (in seconds)
        type: #optional
        - user
        - origin
        - url=/endpoint2
marcosbarbero commented 6 years ago

Hi @Paxon96 how did you test it? Do you need globally per user doesn't matter the service?

Paxon96 commented 6 years ago

Hi @marcosbarbero I was overloading on one host and tried to access the resource on another.

I need per user but regardless of the service.

marcosbarbero commented 6 years ago

so you need to change your config a little bit. In your current config, you have the policy-list set for a service named MyServiceID you should move your default/user config under default-policy-list

lchayoun commented 6 years ago

Just to clarify things, rate limit is not shared between services.

If you want to limit just by the user just remove the 'origin' and the 'url' from the type list.

That being said, putting a limit of 10 on the user in the default list will enforce 10 requests in the refresh interval per service.

Paxon96 commented 6 years ago

U mean, like this?

ratelimit:
    enabled: true
    repository: CONSUL
    behind-proxy: true
    default-policy-list:
      - limit: 10 #optional - request number limit per refresh interval window
        quota: 60 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 30 #default value 60 (in seconds)
        type: #optional
            - user

Or like this?

ratelimit:
    enabled: true
    repository: CONSUL
    behind-proxy: true
    default-policy-list:
      - limit: 10 #optional - request number limit per refresh interval window
        quota: 60 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 30 #default value 60 (in seconds)
        type: #optional
            - user 
   policy-list:
     MyServiceID:
        - limit: 10 #optional - request number limit per refresh interval window
          quota: 60 #optional - request time limit per refresh interval window (in seconds)
          refresh-interval: 30 #default value (in seconds)
          type: #optional
          - url=/endpoint1
        - limit: 10 #optional - request number limit per refresh interval window
          quota: 60 #optional - request time limit per refresh interval window (in seconds)
          refresh-interval: 30 #default value (in seconds)
          type: #optional
          - url=/endpoint2
lchayoun commented 6 years ago

The first option will be enough in order to limit the user

marcosbarbero commented 6 years ago

Yeah, maybe I bad worded myself sorry for that. Anyway, my idea was the first option as well

Paxon96 commented 6 years ago

Nope, unfortunately the first option does not work.

To clarify, I need something like this: user1 -> sending requests and overload the service only for him use2 -> even when user1 has locked access to services, user2 can send request to them (services) and work with them

So far, when user1 overloaded the services, user2 couldn't reach them.

marcosbarbero commented 6 years ago

I think you have a malformed config in the type, looks like it has some extra spaces. This should fix it

zuul.ratelimit:
    enabled: true
    repository: CONSUL
    behind-proxy: true
    default-policy-list:
      - limit: 10 #optional - request number limit per refresh interval window
        quota: 60 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 30 #default value 60 (in seconds)
        type: #optional
          - user
Paxon96 commented 6 years ago

Still the same situation :( If one user overload the service, the service is locked for all users.

If it matters, it is returned " There was an unexpected error (type=Too Many Requests, status=429)" status.

lchayoun commented 6 years ago

If you are trying to limit only user one you can put - user=user 1in the type list. Otherwise all users have the specified limit

marcosbarbero commented 6 years ago

If the user is not specified shouldn't it pick the current username and user as the key @lchayoun ?

lchayoun commented 6 years ago

It should and I believe it is picking it up. It seems that @Paxon96 is expecting that user2 will not be limited at all.

marcosbarbero commented 6 years ago

Well, maybe I got it wrong but as far as I understood he wants to limit per user doesn't matter the resource and username, e.g.

limit = 10
type = user

So 11 requests using user1 would reach its limit but wouldn't affect user2 or any other user.

That's how I got it, maybe I'm wrong, anyway, it should be working though

Paxon96 commented 6 years ago

@marcosbarbero Exactly, I want to limit per user doesn't matter the resource and username. However, how can I set it?

This solution don't work, unfortunately.

ratelimit:
    enabled: true
    repository: CONSUL
    behind-proxy: true
    default-policy-list:
      - limit: 10 #optional - request number limit per refresh interval window
        quota: 60 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 30 #default value 60 (in seconds)
        type: #optional
          - user=user

Is it even possible, without knowing the user name?

marcosbarbero commented 6 years ago

Well, it should work with the following config.

zuul.ratelimit:
  enabled: true
  repository: CONSUL
  behind-proxy: true
  default-policy-list:
    - limit: 10
      quota: 60
      refresh-interval: 30
      type:
        - user
Paxon96 commented 6 years ago

Well, unfortunately this configuration doesn't work. I just copy-paste it into my application.yml file without any additional configuration. When I overload an endpoint at one host, it's block at another as well.

Any ideas ?

marcosbarbero commented 6 years ago

I'll write a sample project to try out, will let you know afterward.

Paxon96 commented 6 years ago

Ok, waiting.

marcosbarbero commented 6 years ago

@Paxon96 I've added a sample application in which you can use as a reference, you can find it here.

In short, this sample configures two users, admin and user and I've configured the rate limit of the endpoint /serviceA to be 10 requests every 60 seconds per user, doesn't matter which one.

If you run the app it will be available in the port 8080 so you can log in reaching http://localhost:8080/login and after logging in you can reach http://localhost:8080/serviceA once you perform 10 requests to this user you'll receive a status code 429, if you use another browser and log with the second user then you'll still be able to reach the same endpoint.