Auto Scaling in MERN Stack with Nginx Reverse Proxy & Service Discovery

Auto Scaling in MERN Stack with Nginx Reverse Proxy & Service Discovery

How Service Discovery and Auto Scaling Work Together for Seamless, Scalable Applications

Basic and Prerequisite Knowledge

Before diving into the world of auto-scaling, service discovery, and MERN stack development, it’s important to have a solid understanding of the following concepts:

  1. Basic Web Development: Familiarity with front-end and back-end technologies like HTML, CSS, JavaScript, React, and Node.js is essential for building web applications.

  2. MERN Stack: The MERN stack consists of MongoDB (for database), Express (for backend framework), React (for frontend framework), and Node.js (runtime environment for JavaScript). Understanding how these technologies work together is crucial.

  3. Docker: Docker allows you to containerize your application and run it in isolated environments. Knowing how to use Docker and Docker Compose helps in setting up and managing multi-container apps.

  4. Reverse Proxy: A reverse proxy like Nginx acts as an intermediary between clients and services, routing traffic efficiently.

  5. Cloud Computing & Auto Scaling: Understanding how cloud platforms enable scaling of web applications based on demand is key. Auto scaling automatically adjusts the number of resources based on traffic load.

  6. Service Discovery: Service discovery automates the process of finding and connecting services, which is essential when your app scales and you have multiple instances running.

Introduction

Imagine you own a growing bakery. When it’s quiet, you only need a few staff members to handle orders. But when the rush comes, you need more hands to keep up with the demand. Once things slow down, you reduce the number of staff. This is exactly how auto-scaling works in the world of web applications—automatically adjusting resources based on traffic.

In this guide, we’ll explore how to set up a MERN stack (MongoDB, Express, React, Node.js) application, integrate Nginx as a reverse proxy, and implement service discovery to enable smooth scaling. Let’s dive in!

Basic MERN Architecture Overview

A typical MERN stack consists of four key parts:

  • Frontend (React): What users interact with

  • Backend (Node.js/Express): Handles business logic and APIs

  • MongoDB: Stores data

  • Nginx Reverse Proxy: Routes traffic to the correct service

MERN Architecture by Enaikele omoh Kelvin

Why Use Nginx as Reverse Proxy?

Think of Nginx as a smart traffic controller for your app. Here's how it helps:

  • Directs Traffic: Routes incoming requests to the right service, whether it's your frontend or backend.

  • Handles SSL/TLS: Ensures your app is secure.

  • Caching: Improves performance by caching frequent responses.

  • Load Balancing: Distributes traffic efficiently to available services.

Here’s a basic Nginx configuration for your MERN app:

# Frontend service
upstream frontend {
    server frontend:3000;
}

# Backend service
upstream backend {
    server backend:5000;
}

server {
    listen 80;

    # Frontend requests
    location / {
        proxy_pass http://frontend;
    }

    # API requests
    location /api {
        proxy_pass http://backend;
    }
}

Docker Setup for Your MERN App

Let’s take this a step further and containerize our app using Docker. Here’s a simple docker-compose.yml file to get started:

version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    depends_on:
      - frontend
      - backend

  frontend:
    build: ./frontend
    ports:
      - "3000"

  backend:
    build: ./backend
    ports:
      - "5000"

  mongodb:
    image: mongo
    ports:
      - "27017:27017"

This configuration sets up Nginx, React (frontend), Node.js (backend), and MongoDB in separate containers. You can now easily deploy your MERN stack with just one command: docker-compose up

Auto Scaling Made Simple

Auto scaling is like adding or removing staff based on demand. In the realm of cloud computing, it enables your application to adapt automatically to increases or decreases in traffic.

Here’s how it works:

  1. Monitor your app: Track key metrics like CPU usage, memory, and requests per second.

  2. Set rules: Define thresholds for scaling. For example:

    • If CPU usage > 70%, add more instances.

    • If CPU usage < 30%, remove instances.

    • Always maintain a minimum of 2 servers and a maximum of 10 servers.

Service Discovery approach in autoscaling

As your app scales and adds more instances, it becomes crucial to keep track of all these moving parts. Service discovery automates the process of identifying and connecting services, similar to how a phone book helps you find contact information.

For example, imagine a team of staff working at a restaurant—each staff member (service) may be assigned specific tasks. If a new staff member joins (a new instance is added), the system automatically registers them, and the rest of the team can find and interact with them seamlessly. Similarly, with service discovery, new instances are added automatically, and outdated ones are removed, ensuring smooth communication between all services, especially during auto scaling.

Here’s how it works with Consul:

  1. Install Consul: Add Consul to your Docker Compose setup:
consul:
  image: consul:latest
  ports:
    - "8500:8500"
  1. Register Services: In your backend, register the service with Consul:
const consul = require('consul')();
consul.agent.service.register({
  name: 'backend',
  port: 5000
});
  1. Find Services: When a service needs to find another, use Consul’s catalog:
consul.catalog.service.nodes('backend', function(err, services) {
  // services contains a list of backend instances
});

Putting It All Together

With Nginx, Docker, and Consul, your app will be able to scale and discover new instances automatically. Here's the flow:

  1. Nginx Routes Requests:

    • Frontend requests → React app

    • /api requests → Node.js backend

  2. Auto Scaling Watches Load:

    • High traffic → More instances are added

    • Low traffic → Fewer instances are removed

  3. Service Discovery Keeps Track:

    • New instances register automatically with Consul

    • Dead instances are removed

    • Nginx is updated with the current list of instances

Simple Monitoring Setup

To monitor your app’s health, you can set up simple health checks for your backend:

// Backend health check
app.get('/health', (req, res) => {
  res.json({
    status: 'healthy',
    time: new Date()
  });
});

This ensures that Nginx can confirm whether a service is running before routing traffic to it.

Best Practices for Beginners

  • Start Small: Begin with single instances and add scaling as you grow.

  • Test Thoroughly: Ensure all components (Nginx, backend, frontend) work seamlessly together.

  • Keep It Simple: Use default configurations at first and add complexity as needed.

  • Monitor Basics: Track CPU usage, memory, and response times to ensure smooth performance.

Conclusion

Auto-scaling and service discovery are crucial components for modern web applications. By utilizing Nginx as a reverse proxy and Consul for service discovery, you can build a scalable, reliable system that efficiently handles varying traffic loads. Begin with the fundamentals, conduct thorough testing, and scale as necessary. This method ensures that your MERN stack app stays fast, secure, and prepared for future growth.To dive deeper into scaling strategies in modern deployment, check out this link.