IP throttling, also known as rate limiting, is a technique used to control the rate of requests from a client to a server. It helps prevent abuse, ensure fair usage of resources, and protect against denial-of-service attacks. In this article, we’ll explore how to implement IP throttling in Go using the net/http
package and the golang.org/x/time/rate
package, which provides a rate limiter implementation.
Prerequisites
Before we proceed, make sure you have Go installed on your system. You can download and install it from the official Go website.
Setting up the Project
First, create a new directory for your project and initialize it as a Go module:
mkdir ip-throttling-example
cd ip-throttling-example
go mod init ip-throttling-example
Next, install the golang.org/x/time/rate
package:
go get golang.org/x/time/rate
Implementing IP Throttling
Now, let’s create a Go program main.go
that implements IP throttling using the net/http
and golang.org/x/time/rate
packages.
Example Code:
package main
import (
"fmt"
"net"
"net/http"
"sync"
"golang.org/x/time/rate"
)
// IPRateLimiter represents an IP rate limiter.
type IPRateLimiter struct {
ips map[string]*rate.Limiter
mu *sync.RWMutex
limiter *rate.Limiter
}
// NewIPRateLimiter creates a new instance of IPRateLimiter with the given rate limit.
func NewIPRateLimiter(r rate.Limit, burst int) *IPRateLimiter {
return &IPRateLimiter{
ips: make(map[string]*rate.Limiter),
mu: &sync.RWMutex{},
limiter: rate.NewLimiter(r, burst),
}
}
// Allow checks if the request from the given IP is allowed.
func (lim *IPRateLimiter) Allow(ip string) bool {
lim.mu.RLock()
rl, exists := lim.ips[ip]
lim.mu.RUnlock()
if !exists {
lim.mu.Lock()
rl, exists = lim.ips[ip]
if !exists {
rl = rate.NewLimiter(lim.limiter.Limit(), lim.limiter.Burst())
lim.ips[ip] = rl
}
lim.mu.Unlock()
}
return rl.Allow()
}
func main() {
// Create a new IP rate limiter with a rate limit of 1 request per second and a burst limit of 3 requests.
limiter := NewIPRateLimiter(1, 3)
// Create an HTTP handler function that applies IP rate limiting.
handler := func(w http.ResponseWriter, r *http.Request) {
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
if !limiter.Allow(ip) {
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
return
}
fmt.Fprintf(w, "Hello, your request from IP %s is allowed.\n", ip)
}
// Register the handler function with the / endpoint.
http.HandleFunc("/", handler)
// Start the HTTP server on port 8080.
fmt.Println("Server listening on :8080")
http.ListenAndServe(":8080", nil)
}
In this example:
- We define an
IPRateLimiter
struct that represents an IP rate limiter. It contains a map of IP addresses to rate limiters (ips
), a mutex (mu
) to synchronize access to the map, and a default rate limiter (limiter
) for IPs that are not in the map. - The
NewIPRateLimiter
function creates a new instance ofIPRateLimiter
with the given rate limit and burst limit. - The
Allow
method checks if the request from the given IP address is allowed based on the rate limiter associated with that IP. If the IP is not in the map, a new rate limiter is created and added to the map. - In the
main
function, we create a new instance ofIPRateLimiter
with a rate limit of 1 request per second and a burst limit of 3 requests. - We define an HTTP handler function that applies IP rate limiting. It extracts the IP address from the request, checks if the request is allowed using the rate limiter, and responds accordingly.
- Finally, we register the handler function with the
/
endpoint and start an HTTP server listening on port 8080.
Testing the Implementation
To test the implementation, start the Go server by running the following command:
go run .
Open your web browser and navigate to http://localhost:8080. You should see a message indicating that your request is allowed. If you refresh the page multiple times within a second, you’ll eventually receive a 429 Too Many Requests
response, indicating that you’ve exceeded the rate limit.
Conclusion
In this article, we explored how to implement IP throttling, also known as rate limiting, in Go using the net/http
package and the golang.org/x/time/rate
package. We created a custom IP rate limiter that tracks requests from different IP addresses and applies rate limiting based on the specified rate limit and burst limit. By implementing IP throttling, you can control the rate of requests from clients, prevent abuse, and ensure fair usage of resources in your Go applications.
The best way to Fix a problem is to fix it before it’s a problem.
Happy coding! 🚀