Golang / GoLang Production Patterns and Web Standards Interview Questions
How do you implement rate limiting in a Go HTTP server?
Rate limiting protects services from overload. Go provides the token bucket algorithm via golang.org/x/time/rate. Production implementations typically rate-limit per client IP or API key, not globally.
import "golang.org/x/time/rate" // Global limiter (simple, not per-client) var globalLimiter = rate.NewLimiter(rate.Limit(100), 10) // 100 requests/second with burst of 10 func globalRateLimitMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !globalLimiter.Allow() { http.Error(w, "too many requests", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) } // Per-client rate limiter (production pattern) type IPRateLimiter struct { mu sync.Mutex limiters map[string]*rate.Limiter r rate.Limit b int } func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter { return &IPRateLimiter{limiters: make(map[string]*rate.Limiter), r: r, b: b} } func (l *IPRateLimiter) getLimiter(ip string) *rate.Limiter { l.mu.Lock() defer l.mu.Unlock() if lim, ok := l.limiters[ip]; ok { return lim } lim := rate.NewLimiter(l.r, l.b) l.limiters[ip] = lim return lim } func (l *IPRateLimiter) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ip, _, _ := net.SplitHostPort(r.RemoteAddr) if !l.getLimiter(ip).Allow() { w.Header().Set("Retry-After", "1") http.Error(w, "rate limit exceeded", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) } // Blocking wait: hold request until token available (or ctx expires) if err := limiter.Wait(ctx); err != nil { http.Error(w, "request cancelled", http.StatusServiceUnavailable) }
More Related questions...