← Назад к вопросам

Какие знаешь инструменты масштабирования кроме worker threads?

3.0 Senior🔥 161 комментариев
#Node.js и JavaScript#Архитектура и паттерны#Кэширование и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Инструменты масштабирования Node.js (кроме Worker Threads)

Masштабирование — это критично для production приложений. Есть много подходов помимо worker threads, которые я регулярно использую в своих проектах.

1. Cluster Module

Встроенный инструмент для распределения нагрузки между процессами:

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

if (cluster.isMaster) {
  const numWorkers = os.cpus().length;
  console.log(`Master процесс запущен (PID: ${process.pid})`);
  
  // Создание рабочих процессов
  for (let i = 0; i < numWorkers; i++) {
    cluster.fork();
  }
  
  // Перезагрузка при падении
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} умер (${signal || code})`);
    cluster.fork(); // Запуск нового рабочего
  });
  
  // Graceful shutdown
  process.on('SIGTERM', () => {
    console.log('Завершение всех workers...');
    for (const worker of Object.values(cluster.workers)) {
      worker.kill();
    }
    process.exit(0);
  });
} else {
  // Рабочий процесс
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Processed by worker ${process.pid}\n`);
  }).listen(3000);
  
  console.log(`Worker процесс запущен (PID: ${process.pid})`);
}

Преимущества:

  • Встроен в Node.js (не нужно устанавливать)
  • Один порт слушают все worker процессы
  • Автоматическая балансировка нагрузки

2. PM2 (Production Process Manager)

Индустриальный стандарт для управления Node.js процессами:

// ecosystem.config.js
module.exports = {
  apps: [
    {
      name: 'api-server',
      script: './server.js',
      instances: 'max', // Или количество CPU ядер
      exec_mode: 'cluster',
      max_memory_restart: '500M',
      
      // Graceful shutdown
      kill_timeout: 5000,
      wait_ready: true,
      listen_timeout: 3000,
      
      // Окружение
      env: {
        NODE_ENV: 'production',
        PORT: 3000
      }
    }
  ],
  
  // Скрипты
  deploy: {
    production: {
      user: 'deploy',
      host: 'example.com',
      ref: 'origin/main',
      repo: 'git@github.com:user/repo.git'
    }
  }
};

Запуск:

pm2 start ecosystem.config.js
pm2 logs
pm2 monit
pm2 gracefulReload all

3. Docker + Kubernetes (контейнеризация)

Масштабирование на уровне инфраструктуры:

# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
HEALTHCHECK --interval=10s --timeout=3s CMD node healthcheck.js
CMD ["node", "server.js"]
# kubernetes.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: myapp:latest
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: "production"
        
        # Health checks
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 5

4. Load Balancing (балансировка нагрузки)

Nginx в качестве reverse proxy:

upstream nodejs_cluster {
  least_conn;
  server localhost:3000;
  server localhost:3001;
  server localhost:3002;
  server localhost:3003;
}

server {
  listen 80;
  server_name example.com;
  
  location / {
    proxy_pass http://nodejs_cluster;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    
    # Таймауты
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
  }
}

5. Caching Layers (кэширование)

Redis для кэширования:

const redis = require('redis');
const client = redis.createClient();

app.get('/api/users/:id', async (req, res) => {
  const cacheKey = `user:${req.params.id}`;
  
  try {
    // Проверка кэша
    const cached = await client.get(cacheKey);
    if (cached) {
      return res.json(JSON.parse(cached));
    }
    
    // Загрузка из БД
    const user = await db.users.findById(req.params.id);
    
    // Сохранение в кэш на 1 час
    await client.setex(cacheKey, 3600, JSON.stringify(user));
    
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

6. Database Replication (репликация БД)

PostgreSQL Master-Slave:

// Читаем с реплик, пишем в master
const masterPool = new Pool({
  host: 'master.db.local',
  database: 'myapp'
});

const replicaPool = new Pool({
  host: 'replica.db.local',
  database: 'myapp'
});

// Запись — только в master
async function createUser(userData) {
  const result = await masterPool.query(
    'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
    [userData.name, userData.email]
  );
  // Инвалидируем кэш
  await cache.del('users:*');
  return result.rows[0];
}

// Чтение — с любой реплики
async function getUser(id) {
  const result = await replicaPool.query(
    'SELECT * FROM users WHERE id = $1',
    [id]
  );
  return result.rows[0];
}

7. CDN для статики

CloudFlare, AWS CloudFront:

app.use(express.static('public', {
  maxAge: '1d',
  etag: false // Let CDN handle it
}));

app.get('/api/data', (req, res) => {
  res.set('Cache-Control', 'public, max-age=3600'); // 1 час
  res.json({ data: 'cached' });
});

8. Microservices Architecture

Разделение на независимые сервисы:

// api-gateway
const express = require('express');
const httpProxy = require('express-http-proxy');

const app = express();

app.use('/auth', httpProxy('http://auth-service:3001'));
app.use('/users', httpProxy('http://user-service:3002'));
app.use('/orders', httpProxy('http://order-service:3003'));

app.listen(3000, () => console.log('API Gateway on 3000'));

9. Message Queue (асинхронная обработка)

RabbitMQ или Kafka для задач:

// Producer
await publisher.publish('orders', { orderId: 123 });

// Consumer (может быть в отдельном процессе)
await subscriber.subscribe('orders', async (message) => {
  await processOrder(message.orderId);
});

Сравнение подходов

ПодходИспользованиеПлюсыМинусы
ClusterSingle serverПросто, встроеноMax 1 сервер
PM2ProductionУправление, мониторингПлатная версия
Docker+K8sLarge scaleГибкость, масштабируемостьСложность
NginxБалансировкаБыстро, надёжноКонфигурация
RedisКэшОгромная скоростьMemory
MicroservicesВысоконагруженныеНезависимостьОперационная сложность

Best Practices

  1. Мониторинг — слежение за метриками (CPU, RAM, latency)
  2. Health checks — регулярная проверка состояния
  3. Graceful shutdown — завершение обработки перед выключением
  4. Load testing — нагрузочное тестирование перед production
  5. Circuit breaker — защита от каскадных отказов
  6. Rate limiting — ограничение количества запросов

Выбор инструмента зависит от размера приложения, команды и инфраструктуры.

Какие знаешь инструменты масштабирования кроме worker threads? | PrepBro