Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Sunshine And March Vibes (2025 Wallpapers Edition)

      May 16, 2025

      The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

      May 16, 2025

      How To Fix Largest Contentful Paint Issues With Subpart Analysis

      May 16, 2025

      How To Prevent WordPress SQL Injection Attacks

      May 16, 2025

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025

      Minecraft licensing robbed us of this controversial NFL schedule release video

      May 16, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      The power of generators

      May 16, 2025
      Recent

      The power of generators

      May 16, 2025

      Simplify Factory Associations with Laravel’s UseFactory Attribute

      May 16, 2025

      This Week in Laravel: React Native, PhpStorm Junie, and more

      May 16, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025
      Recent

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»How to Build a Distributed Rate Limiting System Using Redis and Lua Scripts

    How to Build a Distributed Rate Limiting System Using Redis and Lua Scripts

    November 19, 2024

    In this comprehensive guide, you’ll build a distributed rate limiter using Redis and Lua scripting to control user requests in a high-traffic environment.

    Rate limiting is crucial in any system to prevent abuse, manage traffic, and protect your resources. By leveraging Redis and Lua, you’ll build an efficient, scalable rate limiting system that can handle a large number of requests while keeping your backend services safe.

    We will also include an interactive demo where users can simulate traffic, observe rate limits being enforced, and view logs of blocked requests.

    What You Will Learn

    • How to build a rate limiting system using Redis.

    • How to use Lua scripts with Redis to achieve atomic operations.

    • Understanding Redis data structures for efficient request tracking.

    • Techniques for handling high traffic in a distributed system.

    • Using Docker to simulate and scale a distributed rate limiter.

    Prerequisites

    Before starting, ensure you have the following installed:

    • Node.js (v14 or higher)

    • Redis

    • Docker (for simulating a distributed environment)

    • Basic understanding of Node.js, Redis, and Lua scripting.

    Table of Contents

    • What You Will Learn

    • Prerequisites

    • Project Overview

    • Step 1: How to Set Up the Project

    • Step 2: How to Set Up Redis

    • Step 3: How to Implement the Rate Limiter with Redis and Lua

    • Step 4: How to Create the Node.js API Server

    • Step 5: How to Test the Rate Limiter

    • Step 6: How to Visualize Rate Limiting Metrics

    • Step 7: How to Deploy with Docker

    • Conclusion: What You’ve Learned

    Project Overview

    In this tutorial, you will:

    1. Build a rate limiter using Redis and Lua to enforce request quotas.

    2. Use Lua scripts to ensure atomic operations, avoiding race conditions.

    3. Implement a token bucket algorithm for rate limiting.

    4. Create an interactive demo to simulate high traffic and visualize rate limiting in action.

    System Architecture

    You’ll build the system with the following components:

    1. API Server: Handles incoming user requests.

    2. Redis: Stores request data and enforces rate limits.

    3. Lua Scripts: Ensures atomic updates to Redis for rate limiting.

    4. Docker: Simulates a distributed environment with multiple instances.

    Step 1: How to Set Up the Project

    Let’s start by setting up our Node.js project:

    mkdir distributed-rate-limiter
    cd distributed-rate-limiter
    npm init -y
    

    Next, install the required dependencies:

    npm install express redis dotenv
    
    • express: A lightweight web server framework.

    • redis: For interacting with Redis.

    • dotenv: For managing environment variables.

    Create a .env file with the following content:

    REDIS_HOST=localhost
    REDIS_PORT=6379
    PORT=3000
    RATE_LIMIT=5
    TIME_WINDOW=60
    

    These variables define the Redis host, port, rate limit (number of allowed requests), and the time window (in seconds).

    Step 2: How to Set Up Redis

    Before we dive into the code, ensure that Redis is installed and running on your system. If you don’t have Redis installed, you can use Docker to quickly set it up:

    docker run -p 6379:6379 --name redis-rate-limiter -d redis
    

    Step 3: How to Implement the Rate Limiter with Redis and Lua

    To efficiently handle rate limiting, we’ll use a token bucket algorithm. In this algorithm:

    1. Each user has a “bucket” of tokens.

    2. Each request consumes a token.

    3. Tokens refill periodically at a set rate.

    To ensure atomicity and avoid race conditions, we’ll use Lua scripting with Redis. Lua scripts in Redis execute atomically, which means they can’t be interrupted by other operations while running.

    How to Create a Lua Script for Rate Limiting

    Create a file called rate_limiter.lua:

    local key = KEYS[1]
    local limit = tonumber(ARGV[1])
    local window = tonumber(ARGV[2])
    local current = redis.call("get", key)
    
    if current and tonumber(current) >= limit then
        return 0
    else
        if current then
            redis.call("incr", key)
        else
            redis.call("set", key, 1, "EX", window)
        end
        return 1
    end
    
    1. Inputs:

      • KEYS[1]: The Redis key representing the user’s request count.

      • ARGV[1]: The rate limit (maximum number of allowed requests).

      • ARGV[2]: The time window (in seconds) for the rate limit.

    2. Logic:

      • If the user has reached the rate limit, return 0 (request blocked).

      • If the user is within the limit, increment their request count or set a new count with an expiration if it’s the first request.

      • Return 1 (request allowed).

    Step 4: How to Create the Node.js API Server

    Create a file called server.js:

    require('dotenv').config();
    const express = require('express');
    const redis = require('redis');
    const fs = require('fs');
    const path = require('path');
    
    const app = express();
    const client = redis.createClient({
      host: process.env.REDIS_HOST,
      port: process.env.REDIS_PORT
    });
    
    const rateLimitScript = fs.readFileSync(path.join(__dirname, 'rate_limiter.lua'), 'utf8');
    
    const RATE_LIMIT = parseInt(process.env.RATE_LIMIT);
    const TIME_WINDOW = parseInt(process.env.TIME_WINDOW);
    
    // Middleware for rate limiting
    async function rateLimiter(req, res, next) {
      const ip = req.ip;
      try {
        const allowed = await client.eval(rateLimitScript, 1, ip, RATE_LIMIT, TIME_WINDOW);
        if (allowed === 1) {
          next();
        } else {
          res.status(429).json({ message: 'Too many requests. Please try again later.' });
        }
      } catch (err) {
        console.error('Error in rate limiter:', err);
        res.status(500).json({ message: 'Internal server error' });
      }
    }
    
    app.use(rateLimiter);
    
    app.get('/', (req, res) => {
      res.send('Welcome to the Rate Limited API!');
    });
    
    const PORT = process.env.PORT;
    app.listen(PORT, () => {
      console.log(`Server running on port ${PORT}`);
    });
    
    1. Rate Limiter Middleware:

      • Retrieves the client’s IP address and checks if they are within the rate limit using the Lua script.

      • If the user exceeds the limit, a 429 response is sent.

    2. API Endpoint:

      • The root endpoint is rate-limited, so users can only access it a limited number of times within the specified window.

    Step 5: How to Test the Rate Limiter

    1. Start Redis:

       docker start redis-rate-limiter
      
    2. Run the Node.js Server:

       node server.js
      
    3. Simulate Requests:

      • Use curl or Postman to test the rate limiter:

          curl http://localhost:3000
        
      • Send multiple requests rapidly to see rate limiting in action.

    Step 6: How to Visualize Rate Limiting Metrics

    To monitor rate limiting metrics like cache hits and blocked requests, we’ll add logging to the middleware in server.js:

    async function rateLimiter(req, res, next) {
      const ip = req.ip;
      try {
        const allowed = await client.eval(rateLimitScript, 1, ip, RATE_LIMIT, TIME_WINDOW);
        if (allowed === 1) {
          console.log(`Allowed request from ${ip}`);
          next();
        } else {
          console.log(`Blocked request from ${ip}`);
          res.status(429).json({ message: 'Too many requests. Please try again later.' });
        }
      } catch (err) {
        console.error('Error in rate limiter:', err);
        res.status(500).json({ message: 'Internal server error' });
      }
    }
    

    Step 7: How to Deploy with Docker

    Let’s containerize the application to run it in a distributed environment.

    Create a Dockerfile:

    FROM node:14
    WORKDIR /app
    COPY . .
    RUN npm install
    EXPOSE 3000
    CMD ["node", "server.js"]
    

    Build and Run the Docker Container:

    docker build -t rate-limiter .
    docker run -p 3000:3000 rate-limiter
    

    Now you can scale the rate limiter by running multiple instances.

    Conclusion: What You’ve Learned

    Congratulations! You’ve successfully built a distributed rate limiter using Redis and Lua scripts. Throughout this tutorial, you’ve learned how to:

    1. Implement rate limiting to control user requests in a distributed system.

    2. Use Lua scripts in Redis to perform atomic operations.

    3. Apply a token bucket algorithm to manage request quotas.

    4. Monitor rate limiting metrics to optimize performance.

    5. Use Docker to simulate a scalable distributed environment.

    Next Steps:

    1. Add Rate Limiting by User ID: Extend the system to support rate limits per user.

    2. Integrate with Nginx: Use Nginx as a reverse proxy with Redis-backed rate limiting.

    3. Deploy with Kubernetes: Scale your rate limiter using Kubernetes for high availability.

    Happy coding!

    Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleHow to Build a Scalable URL Shortener with Distributed Caching Using Redis
    Next Article How to Create a Meme Generator Using HTML Canvas

    Related Posts

    Security

    Nmap 7.96 Launches with Lightning-Fast DNS and 612 Scripts

    May 17, 2025
    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-40906 – MongoDB BSON Serialization BSON::XS Multiple Vulnerabilities

    May 17, 2025
    Leave A Reply Cancel Reply

    Continue Reading

    IBM’s Think 2024 News That Should Help Skills & Productivity Issues in Australia

    Development

    Apple Patches Actively Exploited iOS Zero-Day CVE-2025-24200 in Emergency Update

    Development

    A Guide to “apt autoremove” – Clean Up Your System

    Development

    “That was really frustrating for us on the dev side.” Halo dev explains how one of the Xbox series’ biggest controversies came to be

    News & Updates

    Highlights

    Development

    Laravel Herd v1.7 is out with updates to the dump UI

    June 12, 2024

    Laravel Herd v1.7 is now out and includes a few new features to the dump…

    How to Deploy Apache Airflow on Vultr Using Anaconda

    May 15, 2024

    CVE-2025-4090 – “Mozilla Firefox Android and Thunderbird Information Disclosure”

    April 29, 2025

    Build a Memory Game in React

    February 13, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.