Poupe até 53% em Servidores VPS, escolha agora. Oferta limitada.

Guia para escalar aplicações Node.js quando o tráfego explodir

15 min de leitura  ·  Guia técnico

Escalar aplicações Node.js significa aumentar a capacidade de processamento para suportar mais usuários simultâneos sem degradar a performance. Para escalar Node.js quando o tráfego explodir, siga estes passos:

  1. Configure clustering com PM2 para usar todos os cores da CPU
  2. Implemente cache Redis para reduzir consultas ao banco
  3. Configure load balancer Nginx para distribuir requisições
  4. Otimize queries do banco de dados e conexões
  5. Configure monitoramento de performance em tempo real
  6. Implemente auto-scaling horizontal com múltiplos servidores

Pré-requisitos

  • Servidor VPS ou dedicado com Ubuntu 22.04 LTS
  • Node.js 18+ e npm instalados
  • Aplicação Node.js funcionando em produção
  • Acesso root via SSH ao servidor
  • Redis Server para cache (opcional mas recomendado)
  • Nginx para load balancing

Configurando clustering com PM2 para máxima performance

O clustering permite que aplicações Node.js utilizem todos os cores disponíveis da CPU, multiplicando a capacidade de processamento. O PM2 é a ferramenta mais robusta para gerenciar clusters Node.js em produção.

Primeiro, instale o PM2 globalmente:

npm install -g pm2

Crie um arquivo de configuração ecosystem.config.js na raiz do projeto:

module.exports = {
  apps: [{
    name: 'minha-app',
    script: './app.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    max_memory_restart: '1G',
    error_file: './logs/err.log',
    out_file: './logs/out.log',
    log_file: './logs/combined.log'
  }]
}

Inicie a aplicação em modo cluster:

pm2 start ecosystem.config.js

Output esperado:

┌─────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id  │ name     │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0   │ minha-app│ default     │ 1.0.0   │ cluster │ 12345    │ 0s     │ 0    │ online    │ 0%       │ 25.2mb   │ root     │ disabled │
│ 1   │ minha-app│ default     │ 1.0.0   │ cluster │ 12346    │ 0s     │ 0    │ online    │ 0%       │ 25.1mb   │ root     │ disabled │
└─────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

Verifique o status das instâncias:

pm2 status
pm2 monit

Implementando cache Redis para reduzir latência

O cache Redis elimina consultas repetitivas ao banco de dados, reduzindo drasticamente o tempo de resposta. Instale e configure o Redis no servidor:

sudo apt update
sudo apt install redis-server -y
sudo systemctl enable redis-server
sudo systemctl start redis-server

Instale o cliente Redis na aplicação Node.js:

npm install redis

Configure o cliente Redis na aplicação:

const redis = require('redis');
const client = redis.createClient({
  host: 'localhost',
  port: 6379,
  retry_strategy: (options) => {
    if (options.error && options.error.code === 'ECONNREFUSED') {
      return new Error('Redis server recusou conexão');
    }
    if (options.total_retry_time > 1000 * 60 * 60) {
      return new Error('Tempo limite de retry excedido');
    }
    return Math.min(options.attempt * 100, 3000);
  }
});

// Middleware de cache
const cacheMiddleware = (duration) => {
  return async (req, res, next) => {
    const key = req.originalUrl;
    try {
      const cached = await client.get(key);
      if (cached) {
        return res.json(JSON.parse(cached));
      }
      res.sendResponse = res.json;
      res.json = (body) => {
        client.setex(key, duration, JSON.stringify(body));
        res.sendResponse(body);
      };
      next();
    } catch (error) {
      next();
    }
  };
};

Aplique cache em rotas específicas:

app.get('/api/produtos', cacheMiddleware(300), async (req, res) => {
  const produtos = await db.query('SELECT * FROM produtos');
  res.json(produtos);
});

Configurando load balancer Nginx para distribuição de carga

O Nginx atua como proxy reverso, distribuindo requisições entre múltiplas instâncias da aplicação. Instale o Nginx:

sudo apt install nginx -y
sudo systemctl enable nginx

Crie a configuração do load balancer em /etc/nginx/sites-available/minha-app:

upstream nodejs_backend {
    least_conn;
    server 127.0.0.1:3000 weight=1 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 weight=1 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3002 weight=1 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3003 weight=1 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    server_name meudominio.com;
    
    location / {
        proxy_pass http://nodejs_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_connect_timeout 5s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    location /static/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        alias /var/www/minha-app/static/;
    }
}

Ative a configuração:

sudo ln -s /etc/nginx/sites-available/minha-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Configure o PM2 para usar portas diferentes:

module.exports = {
  apps: [{
    name: 'app-3000',
    script: './app.js',
    env: { PORT: 3000 }
  }, {
    name: 'app-3001', 
    script: './app.js',
    env: { PORT: 3001 }
  }, {
    name: 'app-3002',
    script: './app.js', 
    env: { PORT: 3002 }
  }, {
    name: 'app-3003',
    script: './app.js',
    env: { PORT: 3003 }
  }]
}

Otimizando conexões de banco de dados

Pool de conexões evita overhead de criar/destruir conexões constantemente. Configure pools adequados para sua aplicação:

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'app_user',
  password: 'senha_segura',
  database: 'minha_app',
  connectionLimit: 20,
  queueLimit: 0,
  acquireTimeout: 60000,
  timeout: 60000,
  reconnect: true
});

// Middleware para queries otimizadas
const executeQuery = async (sql, params = []) => {
  const connection = await pool.getConnection();
  try {
    const [results] = await connection.execute(sql, params);
    return results;
  } finally {
    connection.release();
  }
};

Atenção: Monitore o número de conexões ativas para evitar esgotar o pool durante picos de tráfego.

Implemente índices adequados nas tabelas mais consultadas:

-- Exemplo de índices para otimização
CREATE INDEX idx_usuario_email ON usuarios(email);
CREATE INDEX idx_produto_categoria ON produtos(categoria_id);
CREATE INDEX idx_pedido_data ON pedidos(data_criacao);

Implementando monitoramento de performance

Configure monitoramento completo para detectar gargalos antes que afetem usuários. Instale ferramentas de monitoramento:

npm install express-status-monitor
npm install newrelic

Configure o monitor de status na aplicação:

const monitor = require('express-status-monitor');

app.use(monitor({
  title: 'Minha App Status',
  path: '/status',
  spans: [{
    interval: 1,
    retention: 60
  }, {
    interval: 5, 
    retention: 60
  }],
  chartVisibility: {
    cpu: true,
    mem: true,
    load: true,
    responseTime: true,
    rps: true,
    statusCodes: true
  },
  healthChecks: [{
    protocol: 'http',
    host: 'localhost',
    path: '/health',
    port: '3000'
  }]
}));

Configure alertas no PM2:

pm2 install pm2-server-monit
pm2 set pm2-server-monit:refresh 2000
pm2 set pm2-server-monit:cpu_threshold 80
pm2 set pm2-server-monit:mem_threshold 80

Crie endpoint de health check:

app.get('/health', async (req, res) => {
  try {
    // Verifica conexão com banco
    await pool.execute('SELECT 1');
    
    // Verifica Redis
    await client.ping();
    
    res.status(200).json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      memory: process.memoryUsage()
    });
  } catch (error) {
    res.status(503).json({
      status: 'unhealthy',
      error: error.message
    });
  }
});

Configurando auto-scaling horizontal

Para tráfego extremo, configure múltiplos servidores com auto-scaling. Use Docker para facilitar deployment:

# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["pm2-runtime", "start", "ecosystem.config.js"]

Configure docker-compose para múltiplas instâncias:

# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    deploy:
      replicas: 4
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M
    environment:
      - NODE_ENV=production
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
      - db
  
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app
  
  redis:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru

Para auto-scaling baseado em métricas, configure scripts de monitoramento:

#!/bin/bash
# auto-scale.sh
CPU_THRESHOLD=80
CURRENT_CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)

if (( $(echo "$CURRENT_CPU > $CPU_THRESHOLD" | bc -l) )); then
    echo "CPU alto detectado: $CURRENT_CPU%. Escalando..."
    docker-compose up --scale app=6 -d
else
    echo "CPU normal: $CURRENT_CPU%"
fi

Problemas comuns e como resolver

Aplicação trava durante picos de tráfego

Causa: Event loop bloqueado por operações síncronas ou CPU intensivas.
Solução: Identifique operações bloqueantes com clinic.js e mova processamento pesado para workers separados usando worker_threads ou filas como Bull Queue.

Memória aumenta constantemente até crash

Causa: Memory leaks em closures, event listeners não removidos ou cache sem expiração.
Solução: Use --inspect para debugging, configure max_memory_restart no PM2 e implemente limpeza adequada de recursos com process.on('SIGTERM').

Conexões de banco esgotam rapidamente

Causa: Pool de conexões mal dimensionado ou conexões não liberadas adequadamente.
Solução: Aumente connectionLimit gradualmente, sempre use finally para liberar conexões e monitore conexões ativas com SHOW PROCESSLIST.

Load balancer retorna 502 Bad Gateway

Causa: Instâncias Node.js não respondem ou portas incorretas no upstream.
Solução: Verifique se todas as instâncias estão rodando com pm2 status, confirme portas no arquivo de configuração do Nginx e teste conectividade com curl localhost:3000.

Cache Redis não funciona corretamente

Causa: Configuração incorreta do cliente ou chaves de cache mal estruturadas.
Solução: Verifique conexão com redis-cli ping, implemente tratamento de erro adequado e use TTL apropriado para evitar dados obsoletos.

Perguntas frequentes sobre escalar aplicações Node.js

Como o PM2 ajuda a escalar aplicações Node.js?

O PM2 permite executar múltiplas instâncias da aplicação Node.js em modo cluster, distribuindo a carga entre os cores da CPU. Ele também oferece restart automático, monitoramento de recursos e balanceamento de carga nativo.

Qual a diferença entre clustering e load balancing para Node.js?

Clustering executa múltiplas instâncias da aplicação no mesmo servidor, aproveitando todos os cores da CPU. Load balancing distribui requisições entre diferentes servidores ou instâncias, podendo usar clustering internamente em cada servidor.

Quando devo usar cache Redis em aplicações Node.js?

Use Redis quando sua aplicação faz consultas frequentes ao banco de dados, precisa armazenar sessões de usuário ou dados temporários. O Redis reduz drasticamente o tempo de resposta e alivia a carga do banco principal.

Como monitorar performance de aplicações Node.js em produção?

Use ferramentas como PM2 Monit, New Relic ou DataDog para acompanhar CPU, memória, tempo de resposta e erros. Configure alertas para picos de uso e monitore logs de erro em tempo real.

É possível escalar Node.js verticalmente sem clustering?

Sim, mas é limitado. Escalabilidade vertical aumenta recursos do servidor (CPU, RAM), mas Node.js por padrão usa apenas um core. Clustering é essencial para aproveitar múltiplos cores e maximizar performance.

Conclusão

  • Configure PM2 em modo cluster para aproveitar todos os cores da CPU disponíveis
  • Implemente cache Redis estratégico para reduzir latência e carga no banco de dados
  • Use Nginx como load balancer para distribuir tráfego entre múltiplas instâncias da aplicação

Leia também

Precisa de ajuda para escalar sua aplicação Node.js?

Nossa equipe especializada pode configurar a infraestrutura ideal para suportar qualquer volume de tráfego. Oferecemos servidores VPS otimizados com recursos dedicados para aplicações Node.js de alta performance.

Conheça nossos planos de VPS para Node.js

  • 0 Os usuários acharam isso útil
  • nodejs, pm2, clustering, load-balancer, nginx, performance, escalabilidade, avirahost
Esta resposta foi útil?

Artigos Relacionados

Instalando painel de gerenciamento de hospedagem VirtualMin.

O virtualmin é um painel de gerenciamento de hospedagem de sites gratuito, que é suportado por...

Como usar a ferramenta oficial de acesso remoto do Windows no PC e celular

1. Pelo menu Iniciar, acesse os “Acessórios do Windows” e abra o “Conexão de Área de Trabalho...

Como acessar o painel de gerenciamento dos meus Serviços.

Para acessar o painel de gerenciamento do seu serviço basta seguir o passo á passo abaixo.   1....

Compreendendo o Servidor VPS: O que é e Como Funciona!

Um servidor VPS (Virtual Private Server) é uma solução de hospedagem na qual um servidor físico é...

Como trocar a senha do usuário root do servidor VPS ou Dedicado.

Para trocar a senha do usuário root em um servidor VPS da AviraHost, você pode seguir os...