Gateway Rate Limiting

In modern microservice architectures, the API gateway serves as the primary ingress point for all incoming traffic, undertaking essential responsibilities such as routing, authentication, monitoring, and traffic control. As business scales expand, sudden traffic spikes, malicious attacks, or downstream service degradation can impose catastrophic blows on the entire infrastructure. To safeguard system stability and high availability, Gateway Rate Limiting has emerged as an indispensable technological countermeasure.

This article explores the core concepts and prevalent algorithms of rate limiting, and walks through a practical implementation using Spring Cloud Gateway integrated with Redis for distributed rate limiting.

Rate limiting refers to the practice of restricting the number of requests processed within a specified time window when a system faces high concurrency. It rejects requests exceeding the system's processing capacity or routes them to fallback or queuing mechanisms, thereby protecting backend services from being overwhelmed.

Offloading rate-limiting logic to the API Gateway layer yields several distinct advantages:

  • Unified Interception: Intercepting traffic before it penetrates the internal network saves internal bandwidth and microservice computing resources.
  • Business Decoupling: Business code remains agnostic of rate-limiting logic, which substantially enhances development efficiency.
  • Global Governance: Centralized traffic control can be enforced across multiple dimensions, including IP addresses, user identities, API paths, and authorization tokens.
    Selecting an appropriate algorithm is paramount when designing a rate-limiting mechanism. Several mainstream algorithms are commonly deployed:
  1. Fixed Window Counter

    • Mechanism: Divides time into fixed-size windows (such as one second), aggregates request counts within each window, and rejects requests once the threshold is breached.
    • Drawback: Vulnerable to "boundary burst" traffic. For instance, if a surge of requests occurs during the last 50 milliseconds of one window and the first 50 milliseconds of the next, the system might absorb twice the threshold volume in a very short span, potentially causing failures.
  2. Sliding Window Log

    • Mechanism: Records the timestamp of every incoming request and calculates the total request count within a rolling sliding window dynamically.
    • Advantage: Smooths out traffic fluctuations and eliminates the boundary vulnerabilities associated with fixed windows.
    • Drawback: High memory consumption due to the necessity of storing individual request timestamps.
  3. Leaky Bucket

    • Mechanism: Incoming requests enter a bucket and leak out at a constant, fixed rate. If the arrival rate exceeds the leak rate, overflow requests are discarded.
    • Advantage: Smooths output velocity effectively and strictly caps the system's maximum processing ceiling.
    • Drawback: Inability to accommodate sudden traffic bursts, even if the backend possesses spare capacity.
  4. Token Bucket

    • Mechanism: The system deposits tokens into a bucket at a constant rate. Every incoming request must acquire a token from the bucket before it can be processed; if the bucket is empty, the request is rejected.
    • Advantage: Controls average processing speeds while permitting controlled bursts of traffic, making it the most widely adopted algorithm in production.

Implementing Distributed Rate Limiting with Spring Cloud Gateway and Redis

In distributed systems, single-node rate limiters often fall short of requirements. A token bucket algorithm powered by Redis and Lua scripts represents the industry standard for distributed rate limiting. Spring Cloud Gateway features a built-in RequestRateLimiter filter factory with native Redis support.

1. Add Dependencies

Include the Spring Cloud Gateway and Redis Reactive dependencies in the project's pom.xml:

<dependencies>
    <!-- Gateway Dependency -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- Redis Reactive Dependency -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
</dependencies>

2. Configure Routes and Rate-Limiting Rules

Define the Redis connection properties and Gateway rate-limiting rules within application.yml. A KeyResolver bean must be configured to determine the dimension by which traffic is throttled.

server:
  port: 8080

spring:
  application:
    name: api-gateway
  redis:
    host: localhost
    port: 6379
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/users/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10   # Average number of tokens added to the bucket per second
                redis-rate-limiter.burstCapacity: 20   # Maximum bucket capacity (maximum allowable burst traffic)
                redis-rate-limiter.requestedTokens: 1  # Number of tokens consumed per request
                key-resolver: "#{@ipKeyResolver}"

3. Implement the KeyResolver Component

Create a component to generate the unique keys for rate limiting. For instance, rate limiting based on the client's IP address can be implemented as follows:

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

@Configuration
public class RateLimiterConfig {

    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest()
                    .getRemoteAddress()
                    .getAddress()
                    .getHostAddress()
        );
    }
}

To throttle traffic based on user IDs instead, simply modify the KeyResolver logic to extract the user identifier from request headers or query parameters.

Conclusion

Gateway rate limiting serves as the ultimate line of defense for maintaining stability in microservice architectures. By judiciously selecting rate-limiting algorithms like the token bucket and coupling them with distributed caching via Redis, systems can easily absorb high-concurrency traffic shocks. In production environments, core parameters such as replenishRate (smooth throughput) and burstCapacity (burst capacity) must be continuously tuned based on stress-testing results to strike an optimal balance between business throughput and system resilience.