Rate-Limit an API (spring MVC) - spring

I'm looking the best more efficient way to implement (or use an already setup) rate limiter that would protect all my rest api url. the protection I'm looking at is a "call per second per user limiter"
I had a look on the net and what comes out was the use of either "Redis" or Guava RateLimiter.
To be honest I have never used Redis and I'am really not familiar with it. But by looking on its docs it seems that it has a quite robust rate limiter system.
I have also had a look at Guava's RateLimiter. And it looks a bit easier to use (don't need a redis installation etc...)
So I would like some suggestion of what would be "in my case" the best solution? Is using Redis "too much"?
Have any of you already tried RateLimter? Is this a good solution? Is it scaleable?
PS: I am also open to other solutions than the 2 I aforementioned if you think there are better choices.
Thank you!

If you are trying to limit access to your Spring-based REST api you should use token-bucket algorithm.
There is bucket4j-spring-boot-starter project which uses bucket4j library to rate-limit access to the REST api. You can configure it via application properties file. There is an option to limit the access based on IP address or username.
If you are using Netflix Zuul you could use Spring Cloud Zuul RateLimit which uses different storage options: Consul, Redis, Spring Data and Bucket4j.

Guava’s RateLimiter blocks the current thread so if there’s a burst of asynchronous calls against the throttled service lots of threads will be blocked and might result exhaust of free threads.
Perhaps Spring-based library Kite meets your needs. Kite's "rate-limiting throttle" rejects requests after the principal reaches a configurable limit on the number of requests in some time period. The rate limiter uses Spring Security to determine the principal involved.
But Kite is still a single-JVM approach. If you do need a cluster-aware approach Redis is a way to go.

there is no hard rule, it totally depends on your specific situation. provided that "I have never used Redis", I would recommend guava RateLimiter. compare to redis, a completely new nosql system for you, guava RateLimiter is much easier to get started with. by adding a few lines of code, you are enable to distribute permits at a configurable rate. what left to do is to adapt it to fit your need, like providing rate limit on a per user basis.

Related

How to scale one specific Rest API without microservice?

I am developing web application backend with Spring where client and server talk through Restful APIs. There is a specific API where I assume the hit will be much. Is there any way to scale this specific API?( Like, assigning more threads)
In this application everything is interdependent. So, microservice wont be best approach I guess.
There are two possible ways, i can think of
Use Load Balancer, this will help you to add multiple application instances of Rest API. This is classical approach in such cases.
This depends upon existing implementation, API can be refactor to just receive the message and decouple the processing thread.
The your suggested way of increasing thread has limitation and more fine tuning require. If the use case is just to support limited user, following configure can be use. tomcat thread pool.
Just have multiple instances of the same service. REST has a statelessness constraint, so it is easy to do it.

rate limiting and throttling in java

I need to implement ratelimiter/throttling in one of my microservice.
For example I have one User microservice that handles login and get user data based on role like Admin or normal user that is implemented using
JWT token and annotation #Secured, So, My ask is to throttle based on these what api is being called.And, I should be able to modify the throttle limit at runtime too.
I don't want to re-invent the wheel, so, any ideas please?
technology stack:- java, spring boot
Answer to this surely depends on what you relate throttling to.
If you are thinking to throttle data returned by api based on role for some time, you could achieve this simply by using spring-boot cache. You can control cache evict time in springboot-app (Even if you want to externalize configuration).
Please have a look at https://spring.io/guides/gs/caching/. Also, have a look at https://www.youtube.com/watch?v=nfZxXGjXVfc demonstration if required.
I am not putting details of how caching is done as it's very well explained in springboot docs. So, might have to tune it according to your need but this is first answer to your controlled throttling.
If you are thinking to throttle the api endpoint itself or throttle the amount of data it could serve i.e. control no. of requests it could serve in a seconds etc. Then you could use RateLimiter from Guava.
Also, I managed to find another one probably more relevant if you are using springboot. It's weddini/spring-boot-throttling
Seems like 2nd approach fits more into what you need.
Hope it helps!
I have implemented a rate limiter base on token-bucket.Other releated technology is spring-boot,spring-data-redis and lua.
Hope it can be helpful.
https://github.com/AllstarVirgo/rateLimit

why rate limiting logic should be placed with application code rather then web server

I am exploring to put rate limiting functionality on rest API which are developed using spring boot.
After going through many articles, I came to know that the best way to put rate limiting functionality is with application code, rather then putting it on web servers.
My question is how do you decide that which functionality should go where. Since, its monitoring your incoming calls and nothing to do with business logic, the ideal place should be a web server.
My question is how do you decide that which functionality should go
where. Since, its monitoring your incoming calls and nothing to do
with business logic, the ideal place should be a web server.
Technically the web server could do the job but in the facts, a web server doesn't have necessarily all needed information, it is not specialized for API consuming and it may also make the testability of this feature much harder.
Some practical reasons why the webserver side could be a bad choice :
the developers don't have necessarily the configuration of the HTTP web server in local.
you want to write unit and integration test to check that the rate limitations are applied as specified. Creating a configuration for automated testing is much simpler in the scope of your Java application than with a configuration file defined on a web server.
web servers reasons in terms of HTTP request-response, not in terms of service.
Rate limitations may be applied according to the IP but not only, the username, the user roles, the type of service may influence the limitations. Not sure that you could get all of these easily from an HTTP server.
For example roles are stored on the server side or in a database.
A better option is setting these mechanisms by adding specific and specialized classes or configuration files, which simplifies their reading, their maintenance and their testability.
As you mention Spring Boot in your tags, that and that should interest you.
I recommend spring-cloud-gateway's rate limiter
you could separate this functionality from your business logic by using Filters.
https://www.baeldung.com/spring-boot-add-filter

Using org.springframework.cache.support.SimpleCacheManager in the cloud

I noticed that Spring reference application (Sagan) uses the SimpleCacheManager implementation. See here for source code of Sagan.
I was surprised by this choice because I thought that all but small applications running on a single node would use something like a Redis cache manager and not the simple cache manager.
How can a large application like Sagan -which I assume runs on cloudfoundry- use this simple implementation?
Any comment welcome.
Well, the SimpleCacheManager choice has been made because it was the simplest solution that could possibly work. Note that Sagan is, at least for now, not storing a lot of data in that cache and merely using it to respect various APIs rate-limiting and get better performance on some parts of the application.
Yes, Sagan is running on CloudFoundry (see this presentation) and is using CF marketplace services.
Even if cache consistency between instances is not a constraint for now, we could definitely add another marketplace service, here a Redis Cloud instance, and use this as a central cache repository.
Now that we're considering using that cache for more features, it even makes sense to at least consider that use case, since it could lower our monthly bill (pay a small fee for a redis service and use less memory for our CF instances).
In any case, thanks a lot balteo for this insightful question, we've created a Github issue for that.

the geo coder to fetch more requests

I am working with geocoder gem and like to process more number of requests from an IP. By default Google API provides only 2500 requests per day.
Please share your thoughts on how I can do more requests than the limit?
As stated before: Using only Google API the only way around the limitation is to pay for it. Or in a more shady way make the requests form more than one IP/API-Key which i would not recommend.
But to stay on the save side i would suggest mixing the services up since there a few more Geocoding APIs out there - for free.
With the right gem mixing them is also not a big issue:
http://www.rubygeocoder.com/
Supports a couple of them with a nice interface. You would pretty much only have to add some rate-limiting counters making sure you stay within the limits of each provider.
Or go the heavy way of implementing your own geocoding. With for example your own running Openstreetmaps database. The Database can be downloaded here: http://wiki.openstreetmap.org/wiki/Planet.osm#Worldwide_data
Which is the best way depends on what your actual requirements are and what ressources you have available.

Resources