DEV Community

Full Stack from Full-Stack
Full Stack from Full-Stack

Posted on

Top 10 Java interview questions about Rate Limiters

1. What is rate limiting and why is it important?

Rate limiting controls the number of requests a user can send to a system in a given time frame, ensuring system stability and fair usage.

2. How would you implement a basic rate limiter using Java?

One can use a token bucket or a sliding log approach.

public class RateLimiter {
    private final long maxRequests;
    private long lastRequestTime = System.currentTimeMillis();
    private long currentRequests = 0;

    public RateLimiter(long maxRequestsPerSecond) {
        this.maxRequests = maxRequestsPerSecond;
    }

    public synchronized boolean allowRequest() {
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastRequestTime > 1000) {
            lastRequestTime = currentTime;
            currentRequests = 0;
        }
        if (currentRequests < maxRequests) {
            currentRequests++;
            return true;
        }
        return false;
    }
}
Enter fullscreen mode Exit fullscreen mode

3. How does the token bucket algorithm work for rate limiting?

Tokens are added to a bucket at a fixed rate. A token is required for a request. If no token is available, the request is denied.

token bucket algorithm work for rate limiting

token bucket algorithm work for rate limiting

4. How can Redis be used in rate limiting?

Redis, with its atomic operations and expiring keys, can track request counts or tokens efficiently across distributed systems.

Redis can be used in rate limiting

Redis can be used in rate limiting

5. How would you handle distributed rate limiting?

Use a centralized store like Redis or a distributed configuration system like ZooKeeper to coordinate rate limits across multiple instances.

Redis can handle distributed rate limiting

Redis can handle distributed rate limiting

ZooKeeper can handle distributed rate limiting

ZooKeeper can handle distributed rate limiting

6. What is the difference between a stateful and stateless rate limiter?

A stateful rate limiter maintains state (like request counts), while a stateless one makes decisions based on immediate data without retaining past information.

A stateless rate limiter doesn’t maintain any state between requests, which means it doesn’t remember past requests. Instead, it makes decisions based solely on the current request’s information. One common approach for a stateless rate limiter is to use a JWT (JSON Web Token) or a similar token that contains the necessary information.

Here’s a simple example using JWTs:

  1. A client requests access and receives a JWT that has an expiration time and a maximum number of requests allowed.
  2. For each request, the client sends the JWT.
  3. The server verifies the JWT, and checks the expiration time, and the number of requests made.
  4. If the client exceeds the number of requests in the time frame, the server denies the request.

Here’s a basic implementation:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;

public class StatelessRateLimiter {
    private static final String SECRET_KEY = "mySecretKey";
    private static final int MAX_REQUESTS = 10;
    private static final int ONE_HOUR = 3600000;

    public String generateToken() {
        long expirationTime = System.currentTimeMillis() + ONE_HOUR;
        return Jwts.builder()
                    .setSubject("rateLimitToken")
                    .claim("requests", 0)
                    .setExpiration(new Date(expirationTime))
                    .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                    .compact();
    }

    public boolean allowRequest(String token) {
        try {
            Claims claims = Jwts.parser()
                                .setSigningKey(SECRET_KEY)
                                .parseClaimsJws(token)
                                .getBody();
            int requests = claims.get("requests", Integer.class);
            if (requests < MAX_REQUESTS) {
                claims.put("requests", requests + 1);
                return true;
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

This is a simplified example. In a real-world scenario, you’d need to handle token renewal, ensure secure token storage, and manage other security aspects. The JWT library used here is jjwt.

7. How can you implement a sliding window rate limiter in Java?

Track timestamps of incoming requests in a list or deque. Ensure the number of requests in any given time window doesn’t exceed the limit.

import java.util.Deque;
import java.util.LinkedList;

public class SlidingWindowRateLimiter {
    private final Deque<Long> timestamps;
    private final int maxRequests;
    private final long windowSizeInMillis;

    public SlidingWindowRateLimiter(int maxRequests, long windowSizeInMillis) {
        this.timestamps = new LinkedList<>();
        this.maxRequests = maxRequests;
        this.windowSizeInMillis = windowSizeInMillis;
    }

    public synchronized boolean allowRequest() {
        long currentTime = System.currentTimeMillis();

        // Remove timestamps outside of the current window
        while (!timestamps.isEmpty() && timestamps.peekFirst() < currentTime - windowSizeInMillis) {
            timestamps.pollFirst();
        }

        // Check if adding a new request would exceed the max limit
        if (timestamps.size() < maxRequests) {
            timestamps.addLast(currentTime);
            return true;
        }

        return false;
    }

    public static void main(String[] args) {
        SlidingWindowRateLimiter limiter = new SlidingWindowRateLimiter(5, 1000); // 5 requests per 1 second

        for (int i = 0; i < 10; i++) {
            System.out.println(limiter.allowRequest()); // First 5 will be true, next 5 will be false
            try {
                Thread.sleep(200); // Sleep for 200ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the SlidingWindowRateLimiter allows up to a specified number of requests (maxRequests) within a given time window (windowSizeInMillis). The Deque is used to store timestamps of requests. When checking if a new request is allowed, timestamps outside the current window are removed, and then the size of the Deque is checked against the maximum allowed requests.

8. How do you handle rate limiting in a microservices architecture?

Implement rate limiters at the API gateway level or use a distributed rate limiting approach using a centralized store.

9. What are the challenges of rate limiting in real-time systems?

Ensuring minimal latency, handling large request volumes, and maintaining system performance while tracking and enforcing limits.

10. How can you inform a user or service about their rate limit status?

Use HTTP headers like X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset to convey rate limit details.

In the vast landscape of backend engineering, rate limiting stands as a sentinel, ensuring system stability and fair resource allocation. As we’ve explored, Java offers a myriad of tools and techniques to implement effective rate-limiting strategies. Whether you’re preparing for an interview or looking to fortify your backend systems, understanding the nuances of rate limiting is paramount. Dive deep, experiment, and remember: a robust backend is as much about managing incoming traffic as it is about processing it. Until next time, happy coding!

🗨️💡 Join the Conversation! Share Your Thoughts Below.

🗣️ Your opinion matters! We're eager to hear your take on this topic. What are your thoughts, experiences, or questions related to what you've just read? Don't hold back—let's dive into a lively discussion!

Enjoyed this Article?

💖 React: Click the heart icon to show your appreciation and help others discover this content too!

🔔 Follow: Stay updated with the latest insights, tips, and trends by subscribing to our profile. Don't miss out on future articles!

🚀 Share: Spread the knowledge! Share this article with your network and help us reach a wider audience.

Your engagement is what keeps our community thriving. Thank you for being a part of it!

Top comments (1)

Collapse
 
erikpischel profile image
Erik Pischel

Currently, I use failsafe.dev implementation