Skip to content

Go Rate Limiting

Rate limiting is an important mechanism for controlling resource utilization and maintaining quality of service. Go supports rate limiting with goroutines, channels, and tickers.

1. Basic Rate Limiting

The simplest way to implement rate limiting is using a time.Ticker. This example limits requests to once every 200 milliseconds.

package main

import (
    "fmt"
    "time"
)

func main() {
    requests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        requests <- i
    }
    close(requests)

    // This limiter will send a value every 200ms
    limiter := time.Tick(200 * time.Millisecond)

    for req := range requests {
        <-limiter // Block until ticker sends a pulse
        fmt.Println("request", req, time.Now())
    }
}

2. Bursty Rate Limiting

Sometimes you want to allow a short "burst" of requests but still limit the overall rate. We can achieve this by using a buffered channel as our limiter.

// Allow up to 3 requests at once, but only refill 1 slot every 200ms
burstyLimiter := make(chan time.Time, 3)

for i := 0; i < 3; i++ {
    burstyLimiter <- time.Now()
}

go func() {
    for t := range time.Tick(200 * time.Millisecond) {
        burstyLimiter <- t
    }
}()

// Now handle more requests
burstyRequests := make(chan int, 5)
for i := 1; i <= 5; i++ {
    burstyRequests <- i
}
close(burstyRequests)

for req := range burstyRequests {
    <-burstyLimiter
    fmt.Println("request", req, time.Now())
}

Why use Rate Limiting?

  1. Prevent Abuse: Stop users from overwhelming your API with thousands of requests per second.
  2. Resource Management: Ensure your database or external dependencies aren't overloaded.
  3. Cost Control: If you pay for third-party APIs by the request, rate limiting keeps costs predictable.

Best Practices

  • Client Side: If you are calling an external API, implement rate limiting on your side to stay within their limits and avoid getting banned.
  • Context: Use context.Context to allow cancellation of waiting requests.
  • Packages: For complex production use cases, consider the golang.org/x/time/rate package, which implements a "Token Bucket" algorithm.