#Best way to add a ratelimit net/http server (by IP)
16 messages · Page 1 of 1 (latest)
Types: 4
Functions: 2
Package rate provides a rate limiter.
why do you need redis
Depends, if you want to run multiple instances of your server in a form of horizontal scaling then no, redis will be the best option. However if you plan on running only one instance, then keeping them all in a map is both faster and easier
The way I did it was making a struct called visitor:
type visitor struct {
*sync.RWMutex
lastAccess time.Time
requests int
}
Which I then made a map of, where the IP was linked to a pointer to a visitor like this, as well as a mutex to make it goroutine safe:
var visitors = make(map[string]*visitor)
var mtx sync.Mutex
Then, I was simply receiving the ip, locking the mtx mutex, incrementing the counter, and if the request was exceeding the max number of requests, i would return a 429
Do you need the map to be shared across multiple instances of the webserver? If so, something like redis makes sense otherwise, just setup a map with a RW lock on it.
okay reading helps, basically what others said above.
The real question, is can you rate limit on something that's not the IP address
If it's an unauthenticated end point, you're going to struggle with any rate limiting.
Simplest algo is to use a sliding window. Keep two numbers per each actor: THIS second and PREV second. The rate for the actor is then THIS + the prorated part of PREV. So for example, if you're at second 1.3, the rate is THIS + 0.7 * PREV. You need to shift THIS to PREV when the second changes. You can of course use a different time window.
I would say you most likely don't need a centralized store such as Redis because you are trying to protect each individual server from overload anyways. So just keep a local map and restrict to M/N where M is the global limit and N is the number of servers. If your server count changes, it might be ok to allow more traffic. Depends on your use case.
Redis also introduces a network call so each and every request will be delayed by a roundtrip to Redis. And, Redis is basically just a single-threaded map so you're creating a bottleneck with contention issues.
Agreed. If you rate by IP address, you might block legit traffic from say an enterprise or ISP that channels all their traffic via a limited set of proxies.
If your goal is to protect the server from overload, consider a single global counter rather than or in addition to on a per-IP basis.
https://pkg.go.dev/golang.org/x/time/rate is a token bucket. This algo has drawbacks.
@torpid grove : I cooked this up for you. Enjoy. https://github.com/microbus-io/throttle