Rate limiting is a technique for controlling the rate at which requests are sent or received. This is useful for preventing abuse, managing resources, and improving service quality. In a Go application, you can implement rate limiting using various techniques such as token bucket or leaky bucket algorithms, or by leveraging a third-party package like ‘golang.org/x/time/rate‘.
Here, I’ll describe the token bucket rate-limiting algorithm using ‘golang.org/x/time/rate‘ package.
1. Install the ‘golang.org/x/time‘ package:
go get -u golang.org/x/time/rate
2. Import the ‘rate‘ package:
import (
"context"
"fmt"
"net/http"
"time"
"golang.org/x/time/rate"
)
3. Create a rate limiter middleware:
func rateLimiterMiddleware(next http.Handler, limiter *rate.Limiter) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// If the limiter allows a request at this time
if limiter.Allow() {
next.ServeHTTP(w, r)
return
}
// If not allowed, return a 429 Too Many Requests error
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
})
}
4. Define the rate and burst parameters:
Here are examples of how to use different rate and burst parameters to limit requests:
rate.NewLimiter(rate.Every(3 * time.Second), 1): Allow one request every 3 seconds.rate.NewLimiter(rate.Every(time.Minute), 60): Allow 60 requests per minute, evenly distributed over the minute.rate.NewLimiter(rate.Every(time.Minute / 10), 10): Allow 10 requests per minute, with up to 10 bursts allowed.
5. Apply the middleware to your HTTP handlers:
func main() {
// Define a rate limiter with the desired rate and burst limits
limiter := rate.NewLimiter(rate.Every(time.Minute / 10), 10)
// Apply the rate limiter middleware for a handler
http.Handle("/limited", rateLimiterMiddleware(myHandler(), limiter))
http.ListenAndServe(":8080", nil)
}
func myHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello! You are rate-limited.n")
})
}
In this example, a rate limiter is applied to the ‘/limited‘ route, allowing up to 10 requests per minute in bursts of 10.
Remember that using this method, you have to set a distinct rate limiter for each user you want to limit separately. Otherwise, it would limit the combined access rate for all users. You can do this by maintaining a map of user-IDs to rate limiters or by using an external storage like Redis.
That’s it! You’ve implemented rate limiting in a Go application using the token bucket algorithm and the ‘golang.org/x/time/rate‘ package.