Node.js: Implantação e Otimização

Última atualização: 2026-08-26

Depois que Charlie implantou a API no servidor de produção usando o node app.js, o processo travava com frequência devido a exceções não capturadas, causando interrupções prolongadas no serviço durante a operação autônoma. Ele implementou o PM2 para habilitar o reinício automático e o modo de cluster, combinado com a conteinerização do Docker e um proxy reverso do Nginx, o que aumentou a disponibilidade do serviço de 95% para 99,9% — e ele finalmente conseguiu dormir tranquilo.

Você aprenderá:


1. Gestão de Processos PM2

(1) Por que precisamos de um gerente de processos?

Em um ambiente de produção, os processos do Node.js podem travar devido a exceções não capturadas, vazamentos de memória ou recursos de sistema insuficientes. Se iniciado diretamente com node app.js, o processo não será reiniciado após uma falha, resultando em interrupção do serviço. O PM2 é o gerenciador de processos mais popular para o Node.js, oferecendo recursos de reinício automático, gerenciamento de logs, balanceamento de carga e monitoramento.

▶ Exemplo:(2) Instalação e comandos básicos

BASH
npm install -g pm2
BASH
pm2 start app.js --name "my-api"
pm2 restart my-api
pm2 stop my-api
pm2 remove my-api
pm2 logs my-api
pm2 monit

(3) Referência rápida aos comandos comuns do PM2

Comando Função Casos de uso comuns
pm2 start app.js Abrir o aplicativo Primeira implantação
pm2 restart <name> Reinicie o aplicativo Após atualizar o código
pm2 reload <name> Reinício sem tempo de inatividade Atualização do ambiente de produção
pm2 stop <name> Serviço suspenso Em manutenção
pm2 delete <name> Excluir processo Remover completamente
pm2 logs [name] Ver registro Solucionar problemas
pm2 monit Painel de monitoramento em tempo real Monitorar o uso de recursos
pm2 list Lista de processos Visualizar status de execução
pm2 describe <name> Detalhes do processo Diagnósticos aprofundados
pm2 save Salvar lista de processos Configuração de inicialização
pm2 startup Gerar um script de inicialização Restaurar automaticamente após a reinicialização do servidor

▶ Exemplo: Inicialização e monitoramento do PM2

BASH
pm2 start app.js --name "charlie-api" -i max
pm2 monit
pm2 save
pm2 startup
TEXT 📖 Somente leitura
┌─────┬──────────────┬─────────────┬─────────┬─────────┬──────────┐
│ id  │ name         │ mode        │ ↺       │ status  │ cpu      │
├─────┼──────────────┼─────────────┼─────────┼─────────┼──────────┤
│ 0   │ charlie-api  │ cluster     │ 15      │ online  │ 12%      │
│ 1   │ charlie-api  │ cluster     │ 2       │ online  │ 8%       │
│ 2   │ charlie-api  │ cluster     │ 0       │ online  │ 5%       │
│ 3   │ charlie-api  │ cluster     │ 1       │ online  │ 3%       │
└─────┴──────────────┴─────────────┴─────────┴─────────┴──────────┘


2. Noções básicas sobre o Docker

(1) Por que usar o Docker

O Docker empacota aplicativos e suas dependências em imagens de contêiner, garantindo a consistência entre os ambientes de desenvolvimento, teste e produção. O código do Charlie, que antes havia sido executado com sucesso em sua máquina local, apresentou erros após ser implantado no servidor devido a diferenças nas versões do Node.js, mas o Docker resolveu completamente esse problema.

▶ Exemplo:(2) Como escrever um Dockerfile

DOCKERFILE
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s \
  CMD node healthcheck.js

USER node

CMD ["node", "app.js"]

▶ Exemplo:(3) Orquestração de múltiplos serviços com o Docker Compose

YAML
version: "3.8"

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - MONGO_URI=mongodb://mongo:27017/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - mongo
      - redis
    restart: always
    healthcheck:
      test: ["CMD", "node", "healthcheck.js"]
      interval: 30s
      timeout: 3s
      retries: 3

  mongo:
    image: mongo:7
    volumes:
      - mongo-data:/data/db
    restart: always

  redis:
    image: redis:7-alpine
    restart: always

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - api
    restart: always

volumes:
  mongo-data:

(4) Comparação dos métodos de implantação

Dimensão Implantação em hardware físico Implantação no Docker Implantação em serviço em nuvem
Consistência ambiental Insuficiente Excelente Excelente
Velocidade de implantação Lenta Rápida Mais rápida
Complexidade operacional Alta Média Baixa
Utilização de recursos Alta Média Sob demanda
Flexibilidade de expansão Ruim Boa Excelente
Custo Baixo Médio Alto
Casos de uso Pequenos projetos Projetos de médio e grande porte Projetos de nível empresarial
Curva de aprendizagem Baixa Média Alta

▶ Exemplo: Compilando e executando uma imagem do Docker

BASH
docker build -t charlie-api:1.0 .
docker run -d -p 3000:3000 --env-file .env charlie-api:1.0
docker-compose up -d
docker-compose logs -f api


3. Gerenciamento de variáveis de ambiente

(1) Por que as variáveis de ambiente são necessárias?

As configurações, como endereços de bancos de dados, números de porta e senhas, variam de acordo com os diferentes ambientes (desenvolvimento, teste e produção). Codificar essas configurações diretamente no código cria riscos de segurança e dificulta a alternância entre os ambientes. As variáveis de ambiente separam a configuração do código, em conformidade com a metodologia Twelve-Factor App.

▶ Exemplo:(2) Arquivos dotenv e .env

JAVASCRIPT
const dotenv = require('dotenv');

dotenv.config({ path: `.env.${process.env.NODE_ENV || 'development'}` });

const config = {
  port: parseInt(process.env.PORT, 10) || 3000,
  mongoUri: process.env.MONGO_URI,
  jwtSecret: process.env.JWT_SECRET,
  redisUrl: process.env.REDIS_URL,
  logLevel: process.env.LOG_LEVEL || 'info',
};

module.exports = config;
▶ Experimente

▶ Exemplo:(3) Estratégia de configuração do ambiente de produção

TEXT 📖 Somente leitura
.env                # Default Configuration(Do not submit Git)
.env.development    # Development Environment
.env.test           # Test Environment
.env.production     # Production Environment(Through CI/CD Inject,Do not コミット to the code リポジトリ)

(4) Comparação entre métodos de gerenciamento de variáveis de ambiente

Método Segurança Flexibilidade Colaboração em equipe Casos de uso
.env Arquivo Médio Alto Bom Projetos gerais
Variáveis de ambiente do sistema Alto Baixo Insuficiente Fácil implantação
Segredos do Docker Alto Médio Bom Ambiente do Docker
K8s Secrets Alto Alto Excelente Kubernetes
Centro de Configuração da Plataforma em Nuvem Alta Alta Excelente Projetos nativos da nuvem

▶ Exemplo: Carregamento de configurações para vários ambientes

JAVASCRIPT
const path = require('path');
const dotenv = require('dotenv');

const env = process.env.NODE_ENV || 'development';

const envFile = path.resolve(process.cwd(), `.env.${env}`);
dotenv.config({ path: envFile });

if (env === 'development') {
  dotenv.config({ path: path.resolve(process.cwd(), '.env') });
}

const required = ['MONGO_URI', 'JWT_SECRET'];
const missing = required.filter(key => !process.env[key]);

if (missing.length) {
  throw new Error(`Missing required env vars: ${missing.join(', ')}`);
}

module.exports = {
  env,
  port: parseInt(process.env.PORT, 10) || 3000,
  mongoUri: process.env.MONGO_URI,
  jwtSecret: process.env.JWT_SECRET,
  redisUrl: process.env.REDIS_URL,
  logLevel: process.env.LOG_LEVEL || 'info',
};
▶ Experimente

4. Modo de cluster

(1) Por que precisamos de clusters?

O Node.js é monothread, o que significa que apenas uma instância pode ser executada em um único núcleo da CPU. O modo cluster utiliza o módulo cluster para criar vários processos de trabalho, aproveitando ao máximo as CPUs multicore para melhorar significativamente a taxa de transferência e a disponibilidade.

(2) Como funciona o módulo de cluster

O processo mestre é responsável por escutar na porta e distribuir as solicitações, enquanto os processos de trabalho lidam com a lógica de negócios propriamente dita. Vários processos de trabalho compartilham a mesma porta para garantir o balanceamento de carga.

▶ Exemplo:(3) Configuração manual de um cluster

JAVASCRIPT
const cluster = require('cluster');
const os = require('os');
const http = require('http');

if (cluster.isPrimary) {
  const numCPUs = os.cpus().length;
  console.log(`Master ${process.pid} is running`);
  console.log(`Forking ${numCPUs} workers...`);

  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died. Restarting...`);
    cluster.fork();
  });
} else {
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Handled by worker ${process.pid}\n`);
  }).listen(3000);

  console.log(`Worker ${process.pid} started`);
}
▶ Experimente

(4) Modo de cluster do PM2

O PM2 possui suporte integrado a clusters que pode ser ativado sem a necessidade de modificar o código:

BASH
pm2 start app.js -i max
pm2 start app.js -i 4

▶ Exemplo: Comparação de desempenho dos modos de cluster

BASH
node single.js &
ab -n 10000 -c 100 http://localhost:3000/
TEXT 📖 Somente leitura
Single process:
  Requests per second:    3254.21 [#/sec]

Cluster (4 workers):
  Requests per second:    11280.67 [#/sec]


5. Análise de desempenho

(1) Sincronização básica com console.time

A maneira mais simples de medir o desempenho, ideal para identificar rapidamente operações lentas:

JAVASCRIPT
app.get('/api/users', async (req, res) => {
  console.time('フェッチ-users');
  const users = await User.find().lean();
  console.timeEnd('フェッチ-users');
  res.json(users);
});

(2) Indicadores de desempenho: medição precisa

O módulo integrado perf_hooks no Node.js oferece medição de tempo de alta precisão:

JAVASCRIPT
const { performance, PerformanceObserver } = require('perf_hooks');

const obs = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`);
  });
});
obs.observe({ type: 'measure', buffered: true });

function measureAsync(label, fn) {
  return async (...args) => {
    performance.mark(`${label}-start`);
    const result = await fn(...args);
    performance.mark(`${label}-end`);
    performance.measure(label, `${label}-start`, `${label}-end`);
    return result;
  };
}

const fastQuery = measureAsync('db-query', async () => {
  return await User.find().lean();
});

(3) Diagnóstico profissional do Clinic.js

O Clinic.js é o conjunto oficial de ferramentas de diagnóstico de desempenho recomendado pelo Node.js:

BASH
npm install -g clinic
clinic doctor -- node app.js
clinic flame -- node app.js
clinic bubbleprof -- node app.js

(4) Comparação de estratégias de otimização de desempenho

Estratégia Ferramentas/Métodos Cenários aplicáveis Dificuldade Eficácia
Análise de tempo console.time Localização rápida Baixo Médio
Medição precisa perf_hooks Caminho crítico Médio Alto
Análise da CPU Clinic Flame Uso intensivo da CPU Médio Alto
Event Loop Clinic Doctor I/O Blocking Medium High
Vazamento de memória heapdump / memwatch Problemas de memória Alto Alto
Teste de carga autocannon / ab Planejamento de capacidade Baixa Média
Monitoramento APM New Relic / Datadog Monitoramento contínuo Médio Alto

▶ Exemplo: Uso do autocannon para testes de carga

BASH
npm install -g autocannon
autocannon -c 100 -d 10 http://localhost:3000/api/health
TEXT 📖 Somente leitura
┌─────────┬──────┬──────┬───────┬──────┬───────┬───────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg   │ Stdev │ Max   │
├─────────┼──────┼──────┼───────┼──────┼───────┼───────┼───────┤
│ Latency │ 2 ms │ 4 ms │ 12 ms │ 18ms │ 5 ms  │ 3 ms  │ 45 ms │
└─────────┴──────┴──────┴───────┴──────┴───────┴───────┴───────┘

Requests/sec: 18523.6


6. Pontos-finais de verificação de integridade

(1) Por que os exames de saúde são necessários?

Os sistemas de orquestração de contêineres (Docker, K8s) e os balanceadores de carga precisam saber se um serviço está funcionando normalmente. Os endpoints de verificação de integridade oferecem uma interface padronizada para detectar o status do serviço, permitindo a detecção automática de falhas e o redirecionamento do tráfego.

▶ Exemplo:(2) Exame básico de saúde

JAVASCRIPT
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
▶ Experimente

▶ Exemplo:(3) Avaliação detalhada do estado de saúde

JAVASCRIPT
app.get('/health', async (req, res) => {
  const checks = {
    server: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
  };

  try {
    await mongoose.connection.db.admin().ping();
    checks.dataベース = 'ok';
  } catch (err) {
    checks.dataベース = 'error';
  }

  try {
    await redisClient.ping();
    checks.redis = 'ok';
  } catch (err) {
    checks.redis = 'error';
  }

  const isHealthy = checks.dataベース === 'ok' && checks.redis === 'ok';
  res.status(isHealthy ? 200 : 503).json(checks);
});
▶ Experimente

(4) Separação entre prontidão e atividade

Em ambientes de produção, as verificações de integridade são normalmente divididas em dois tipos: verificação de atividade (se o processo está ativo) e verificação de prontidão (se ele está pronto para receber tráfego):

JAVASCRIPT
app.get('/healthz', (req, res) => {
  res.json({ status: 'alive' });
});

app.get('/readyz', async (req, res) => {
  try {
    await mongoose.connection.db.admin().ping();
    await redisClient.ping();
    res.json({ status: 'ready' });
  } catch {
    res.status(503).json({ status: 'not ready' });
  }
});

▶ Exemplo: Script de verificação de integridade do Docker

JAVASCRIPT
const http = require('http');

const options = {
  hostname: 'localhost',
  port: process.env.PORT || 3000,
  path: '/healthz',
  timeout: 2000,
};

const req = http.request(options, (res) => {
  if (res.statusCode === 200) {
    process.exit(0);
  } else {
    process.exit(1);
  }
});

req.on('error', () => process.exit(1));
req.on('timeout', () => { req.destroy(); process.exit(1); });
req.end();
▶ Experimente

7. Proxy reverso do Nginx

(1) Por que precisamos do Nginx?

O Nginx atua como um proxy reverso, oferecendo recursos como terminação de SSL, balanceamento de carga, fornecimento de recursos estáticos e limitação de solicitações. O Node.js concentra-se na lógica de negócios, enquanto o Nginx lida com a otimização da camada de rede; cada um desempenha sua função específica.

▶ Exemplo:(2) Arquitetura de implantação do Node.js em produção

100%
graph LR
    Client[Client] --> Nginx[Nginx Reverse Proxy<br/>:80/:443]
    Nginx --> PM2[PM2 Cluster Management]
    PM2 --> W1[Worker 1<br/>:3000]
    PM2 --> W2[Worker 2<br/>:3000]
    PM2 --> W3[Worker 3<br/>:3000]
    PM2 --> W4[Worker 4<br/>:3000]
    W1 --> DB[(MongoDB)]
    W2 --> DB
    W3 --> Redis[(Redis)]
    W4 --> Redis

(3) Configuração do Nginx

TEXT 📖 Somente leitura
upstream nodejs_backend {
    least_conn;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    keepalive 64;
}

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate     /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/certs/api.example.com.key;

    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;
    }

    location /health {
        proxy_pass http://nodejs_backend/health;
        access_log off;
    }

    location /static/ {
        alias /app/public/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
    limit_req zone=api burst=50 nodelay;
}

▶ Exemplo: Configuração do proxy reverso do Nginx no Docker

YAML
# docker-compose.yml Excerpt
nginx:
  image: nginx:alpine
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro
    - ./ssl:/etc/ssl/certs:ro
  depends_on:
    api:
      condition: service_healthy
  restart: always


8. Exemplo abrangente: configuração completa de implantação

Charlie consolidou todas as configurações de implantação em um único sistema, automatizando todo o processo, desde o código até a produção.

▶ Exemplo: Estrutura de diretórios do projeto

TEXT 📖 Somente leitura
charlie-api/
├── app.js
├── healthcheck.js
├── config/
│   └── index.js
├── ecosystem.config.js
├── Dockerfile
├── docker-compose.yml
├── nginx.conf
├── .env.example
├── .dockerignore
└── package.json

▶ Exemplo: PM2 ecosystem.config.js

JAVASCRIPT 📖 Somente leitura
module.exports = {
  apps: [
    {
      name: 'charlie-api',
      script: 'app.js',
      instances: 'max',
      exec_mode: 'cluster',
      autorestart: true,
      watch: false,
      max_memory_restart: '512M',
      env_development: {
        NODE_ENV: 'development',
        PORT: 3000,
      },
      env_production: {
        NODE_ENV: 'production',
        PORT: 3000,
      },
      error_file: './logs/error.log',
      out_file: './logs/out.log',
      merge_logs: true,
      log_date_format: 'YYYY-MM-DD HH:mm:ss',
      max_restarts: 10,
      restart_delay: 4000,
      kill_timeout: 5000,
      listen_timeout: 10000,
    },
  ],
  deploy: {
    production: {
      user: 'deploy',
      host: 'api.example.com',
      ref: 'origin/main',
      repo: 'git@github.com:charlie/api.git',
      path: '/var/www/charlie-api',
      'pre-deploy-local': '',
      'post-deploy':
        'npm ci && pm2 reload ecosystem.config.js --env production',
      'pre-setup': '',
    },
  },
};
42 linhas de lógica (limite de 40, somente leitura)

▶ Exemplo: Dockerfile (otimizado para compilações em várias etapas)

DOCKERFILE
FROM node:20-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build 2>/dev/null || true

FROM node:20-alpine AS production

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --from=builder /app ./

RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
USER nodejs

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD node healthcheck.js

CMD ["node", "app.js"]

▶ Exemplo: .env.example

TEXT 📖 Somente leitura
NODE_ENV=production
PORT=3000
MONGO_URI=mongodb://mongo:27017/charlie-api
REDIS_URL=redis://redis:6379
JWT_SECRET=your-secret-key-here
LOG_LEVEL=info
CORS_ORIGIN=https://example.com
RATE_LIMIT_WINDOW=60000
RATE_LIMIT_MAX=100

▶ Exemplo: healthcheck.js

JAVASCRIPT
const http = require('http');

const req = http.request(
  {
    hostname: '127.0.0.1',
    port: parseInt(process.env.PORT, 10) || 3000,
    path: '/healthz',
    timeout: 2000,
  },
  (res) => {
    process.exit(res.statusCode === 200 ? 0 : 1);
  }
);

req.on('error', () => process.exit(1));
req.on('timeout', () => { req.destroy(); process.exit(1); });
req.end();
▶ Experimente

▶ Exemplo: Endpoint de verificação de integridade no arquivo app.js

JAVASCRIPT 📖 Somente leitura
const express = require('express');
const mongoose = require('mongoose');
const config = require('./config');

const app = express();
app.use(express.json());

app.get('/healthz', (req, res) => {
  res.json({ status: 'alive', pid: process.pid });
});

app.get('/readyz', async (req, res) => {
  try {
    await mongoose.connection.db.admin().ping();
    res.json({ status: 'ready', pid: process.pid, uptime: process.uptime() });
  } catch {
    res.status(503).json({ status: 'not ready', pid: process.pid });
  }
});

app.get('/health', async (req, res) => {
  const checks = {
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    pid: process.pid,
  };

  try {
    await mongoose.connection.db.admin().ping();
    checks.database = 'ok';
  } catch {
    checks.database = 'error';
    checks.status = 'degraded';
  }

  const isHealthy = checks.database === 'ok';
  res.status(isHealthy ? 200 : 503).json(checks);
});

app.get('/api/users', async (req, res) => {
  console.time('fetch-users');
  const users = await mongoose.model('User').find().lean();
  console.timeEnd('fetch-users');
  res.json({ success: true, data: users });
});

mongoose.connect(config.mongoUri).then(() => {
  app.listen(config.port, () => {
    console.log(`Server running on port ${config.port} [${config.env}]`);
  });
});

process.on('SIGTERM', () => {
  console.log('SIGTERM received, shutting down gracefully...');
  mongoose.connection.close();
  process.exit(0);
});

process.on('SIGINT', () => {
  console.log('SIGINT received, shutting down gracefully...');
  mongoose.connection.close();
  process.exit(0);
});
55 linhas de lógica (limite de 40, somente leitura)

❓ Perguntas Frequentes

P: O Docker e o PM2 podem ser usados juntos? R: Sim, mas normalmente opta-se por um ou por outro. O Node.js é executado diretamente dentro de um contêiner do Docker, com as reinicializações gerenciadas pelo K8s ou pelo Docker Compose; o PM2 é adequado para implantações não contêinerizadas.

P: Como escolho uma plataforma de serviços em nuvem? R: Para projetos pequenos, use o Vercel ou o Railway (sem necessidade de configuração); para projetos de médio porte, use a AWS ou o GCP (flexíveis, mas complexos); para projetos na China, use o Alibaba Cloud ou o Tencent Cloud. Escolha com base no seu orçamento e na experiência da sua equipe.

P: Quais são algumas das ferramentas de CI/CD mais utilizadas? R: GitHub Actions (integra-se bem com o GitHub), GitLab CI (prático para hospedagem própria), Jenkins (de nível empresarial, com muitos plug-ins) e CircleCI (nativo da nuvem).

P: Como faço para monitorar uma aplicação Node.js em um ambiente de produção? R: Use o PM2, o New Relic, o Datadog ou uma configuração autohospedada do Prometheus + Grafana para monitorar a CPU, a memória, o tempo de resposta e as taxas de erro.

P: Como faço para realizar uma verificação de integridade após a implantação? R: Adicione o endpoint /health, que retorna { status: 'ok' }; o Docker HEALTHCHECK ou o livenessProbe do K8s acessam esse endpoint periodicamente.

P: O que devo usar, o PM2 ou o Docker? R: Os dois não são mutuamente exclusivos. O Docker resolve questões relacionadas à consistência do ambiente, enquanto o PM2 lida com o gerenciamento de processos e o clustering. Para ambientes de produção, recomendamos usar o Docker e o PM2 em conjunto, com o PM2 rodando dentro de um contêiner do Docker para gerenciar vários processos.

P: Como posso realizar uma implantação sem tempo de inatividade? R: Substitua pm2 restart por pm2 reload. O PM2 reiniciará os Workers um por um, garantindo que algumas instâncias permaneçam online para atender às solicitações o tempo todo. Em um ambiente Docker, você pode usar estratégias de implantação azul-verde ou de atualização contínua.

P: Quais são as limitações do modo cluster? R: No modo cluster, os processos não compartilham memória; as sessões devem ser compartilhadas por meio de armazenamento externo, como o Redis; os WebSockets devem ser usados em conjunto com sessões persistentes ou sincronização de mensagens Pub/Sub; e o cache do sistema de arquivos é independente para cada processo.

P: Como faço para monitorar o ambiente de produção? R: O PM2 oferece pm2 monit monitoramento em tempo real e pm2 plus um painel online; entre as soluções comerciais estão o New Relic, o Datadog e o Prometheus + Grafana; as principais métricas incluem CPU, memória, latência do loop de eventos e tempo de resposta das solicitações.

P: Como posso reduzir o tamanho de uma imagem do Docker? R: Use a imagem base node:alpine, utilize compilações em múltiplas etapas para separar as dependências de compilação, .dockerignore exclua arquivos desnecessários, npm ci --only=production instale apenas as dependências de produção e limpe o cache do npm npm cache clean --force.

P: Quais são as vantagens de usar o Nginx como proxy reverso? R: O descarregamento de SSL reduz a sobrecarga de criptografia no Node.js; os recursos estáticos são tratados diretamente pelo Nginx; o balanceamento de carga distribui as solicitações; a limitação de taxa impede ataques DDoS; a compactação gzip reduz o volume de transferência de dados; e o armazenamento em cache acelera as respostas.


📖 Resumo

(1) Pontos-chave desta aula

(2) Tarefa de casa

  1. Inicie seu projeto Express usando o PM2, configure ecosystem.config.js, ative o modo de cluster e use pm2 monit para monitorar o status de execução.
  2. Escreva um Dockerfile para o projeto, utilize compilações em várias etapas para otimizar o tamanho da imagem e use docker-compose para iniciar o Node.js e o MongoDB simultaneamente
  3. Implemente os três endpoints de verificação de integridade /health, /healthz e /readyz e configure HEALTHCHECK no Docker.
  4. Use autocannon para realizar testes de carga na sua API, comparando as diferenças de taxa de transferência entre os modos de processo único e de cluster.
  5. Escreva a configuração do proxy reverso do Nginx para implementar a terminação SSL e o balanceamento de carga, e use ab ou curl para verificar se o encaminhamento do proxy está funcionando corretamente.

📝 Exercícios

  1. Conclua todos os exemplos de código desta lição e certifique-se de que cada um deles seja executado corretamente.
  2. Modifique o exemplo completo e adicione suas próprias extensões
  3. Analise a documentação oficial, identifique 1 ou 2 APIs que não foram abordadas nesta aula e escreva um código de teste para elas.
  4. Reflexão: Como você aplicaria o que aprendeu nesta aula a um projeto do mundo real?
  5. Tente combinar o que você aprendeu nesta aula com o conteúdo das aulas anteriores para criar um pequeno projeto.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%