<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Node JS]]></title><description><![CDATA[Node JS]]></description><link>https://forum.exlends.ru/category/6</link><generator>RSS for Node</generator><lastBuildDate>Wed, 20 May 2026 09:01:39 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/category/6.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 09 Jan 2026 20:16:15 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Node.js и Балансировщик Нагрузки: Полное Руководство для Новичков]]></title><description><![CDATA[Node.js Load Balancer: Быстрый Старт - Готовые Примеры

Вариант 1: Nginx + 3 Node.js сервера (самый простой способ)
Шаг 1. Создайте простой Node.js app
Файл app.js:
const http = require('http');
const PORT = process.env.PORT || 3000;

const server = http.createServer((req, res) =&gt; {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    message: 'Hello from Node.js',
    port: PORT,
    timestamp: new Date().toISOString()
  }));
});

server.listen(PORT, () =&gt; {
  console.log(`Server running on port ${PORT}`);
});

Шаг 2. Запустите 3 копии
# Терминал 1
PORT=3000 node app.js

# Терминал 2
PORT=3001 node app.js

# Терминал 3
PORT=3002 node app.js

Шаг 3. Установите Nginx
# macOS
brew install nginx

# Ubuntu
sudo apt-get update &amp;&amp; sudo apt-get install nginx

Шаг 4. Настройте Nginx
Отредактируйте /usr/local/etc/nginx/nginx.conf (macOS) или /etc/nginx/nginx.conf (Ubuntu):
http {
  upstream backend {
    server localhost:3000;
    server localhost:3001;
    server localhost:3002;
  }

  server {
    listen 8080;
    location / {
      proxy_pass http://backend;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
  }
}

Шаг 5. Запустите Nginx
# macOS
nginx
# или перезагрузить
nginx -s reload

# Ubuntu
sudo systemctl start nginx

Шаг 6. Тестируйте
# Откройте браузер и несколько раз перейдите на
# http://localhost:8080

# Или используйте curl
for i in {1..9}; do 
  curl http://localhost:8080 
  echo ""
done

Видите меняющиеся порты (3000, 3001, 3002)? Балансировка работает! 

Вариант 2: Собственный балансировщик на Node.js
Файл: load-balancer.js
const express = require('express');
const axios = require('axios');

const app = express();

// Backend серверы
const servers = [
  'http://localhost:3000',
  'http://localhost:3001',
  'http://localhost:3002'
];

let currentIndex = 0;

// Middleware для балансировки
app.use(async (req, res) =&gt; {
  try {
    // Round-robin: выбираем сервер по порядку
    const server = servers[currentIndex];
    currentIndex = (currentIndex + 1) % servers.length;

    // Отправляем запрос на backend сервер
    const response = await axios.get(server);
    
    res.json(response.data);
  } catch (error) {
    console.error('Backend error:', error.message);
    res.status(503).json({ error: 'Service unavailable' });
  }
});

app.listen(8080, () =&gt; {
  console.log('Load balancer running on port 8080');
});

Установите зависимости:
npm init -y
npm install express axios

Запустите:
node load-balancer.js

Тестируйте:
curl http://localhost:8080


Вариант 3: PM2 Cluster Mode (для одной машины)
Файл: server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) =&gt; {
  res.json({
    message: 'Hello from Node.js',
    port: PORT,
    processId: process.pid
  });
});

app.listen(PORT, () =&gt; {
  console.log(`Server running on port ${PORT}, PID: ${process.pid}`);
});

Файл: ecosystem.config.js
module.exports = {
  apps: [{
    name: 'myapp',
    script: './server.js',
    instances: 4,      // 4 копии приложения
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'development'
    }
  }]
};

Установите PM2:
npm install -g pm2
npm install express

Запустите:
pm2 start ecosystem.config.js

Полезные команды:
pm2 status          # Статус всех процессов
pm2 logs           # Логи в реальном времени
pm2 stop all       # Остановить всё
pm2 delete all     # Удалить из PM2

Тестируйте на порту 3000:
for i in {1..8}; do 
  curl http://localhost:3000 
  echo ""
done

Видите разные PID? PM2 распределяет между 4 воркерами! 

Вариант 4: Sticky Sessions (если нужны сессии)
Backend сервер с Express-session:
const express = require('express');
const session = require('express-session');

const app = express();
const PORT = process.env.PORT || 3000;

// Сессии в памяти (для локальной разработки)
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: { maxAge: 60000 }
}));

app.get('/login', (req, res) =&gt; {
  req.session.userId = 123;
  req.session.username = 'john_doe';
  res.json({ 
    message: 'Logged in',
    port: PORT
  });
});

app.get('/profile', (req, res) =&gt; {
  if (req.session.userId) {
    res.json({
      username: req.session.username,
      port: PORT
    });
  } else {
    res.status(401).json({ error: 'Not logged in' });
  }
});

app.listen(PORT);

Nginx config с sticky sessions:
upstream backend {
  ip_hash;  # Один IP адрес — один сервер
  server localhost:3000;
  server localhost:3001;
  server localhost:3002;
}

server {
  listen 8080;
  location / {
    proxy_pass http://backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

Тестируйте:
# Логинитесь
curl -c cookies.txt http://localhost:8080/login

# Проверяете профиль (должен вернуть ваше имя)
curl -b cookies.txt http://localhost:8080/profile

# Повторяйте несколько раз - всегда один и тот же port!
curl -b cookies.txt http://localhost:8080/profile


Вариант 5: Least Connections для лучшей балансировки
Node.js балансировщик с Least Connections:
const express = require('express');
const axios = require('axios');

const app = express();

// Серверы с отслеживанием соединений
const servers = [
  { url: 'http://localhost:3000', connections: 0 },
  { url: 'http://localhost:3001', connections: 0 },
  { url: 'http://localhost:3002', connections: 0 }
];

function selectServer() {
  // Выбираем сервер с наименьшим количеством активных соединений
  return servers.reduce((prev, curr) =&gt; 
    prev.connections &lt; curr.connections ? prev : curr
  );
}

app.use(async (req, res) =&gt; {
  const server = selectServer();
  server.connections++;

  try {
    const response = await axios.get(server.url);
    res.json(response.data);
  } catch (error) {
    res.status(503).json({ error: 'Service unavailable' });
  } finally {
    server.connections--;
  }
});

app.listen(8080, () =&gt; {
  console.log('Load balancer (least connections) on port 8080');
});


Вариант 6: Health Checks (проверка живых серверов)
Backend сервер с health endpoint:
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// Health check endpoint
app.get('/health', (req, res) =&gt; {
  res.json({
    status: 'OK',
    uptime: process.uptime(),
    timestamp: new Date().toISOString()
  });
});

app.get('/', (req, res) =&gt; {
  // Иногда симулируем ошибку
  if (Math.random() &gt; 0.8) {
    res.status(500).json({ error: 'Internal error' });
  } else {
    res.json({ port: PORT });
  }
});

app.listen(PORT);

Балансировщик с health checks:
const express = require('express');
const axios = require('axios');

const app = express();

const servers = [
  { url: 'http://localhost:3000', healthy: true },
  { url: 'http://localhost:3001', healthy: true },
  { url: 'http://localhost:3002', healthy: true }
];

// Периодически проверяем здоровье серверов
setInterval(async () =&gt; {
  for (const server of servers) {
    try {
      await axios.get(server.url + '/health', { timeout: 2000 });
      server.healthy = true;
    } catch (error) {
      server.healthy = false;
    }
  }
}, 5000);

let currentIndex = 0;

app.use(async (req, res) =&gt; {
  // Находим живой сервер
  const healthyServers = servers.filter(s =&gt; s.healthy);
  
  if (healthyServers.length === 0) {
    return res.status(503).json({ error: 'All backends down' });
  }

  // Round-robin только среди живых
  const server = healthyServers[currentIndex % healthyServers.length];
  currentIndex++;

  try {
    const response = await axios.get(server.url);
    res.json(response.data);
  } catch (error) {
    res.status(503).json({ error: 'Service unavailable' });
  }
});

app.listen(8080);


Вариант 7: Docker Compose (полная локальная setup)
docker-compose.yml:
version: '3.8'

services:
  app1:
    image: node:18
    working_dir: /app
    volumes:
      - ./app.js:/app/app.js
    environment:
      PORT: 3000
    command: node app.js
    ports:
      - "3000:3000"

  app2:
    image: node:18
    working_dir: /app
    volumes:
      - ./app.js:/app/app.js
    environment:
      PORT: 3000
    command: node app.js
    ports:
      - "3001:3000"

  app3:
    image: node:18
    working_dir: /app
    volumes:
      - ./app.js:/app/app.js
    environment:
      PORT: 3000
    command: node app.js
    ports:
      - "3002:3000"

  nginx:
    image: nginx:latest
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "8080:80"
    depends_on:
      - app1
      - app2
      - app3

nginx.conf:
events {
  worker_connections 1024;
}

http {
  upstream backend {
    server app1:3000;
    server app2:3000;
    server app3:3000;
  }

  server {
    listen 80;
    location / {
      proxy_pass http://backend;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
  }
}

Запустите:
docker-compose up

Тестируйте:
curl http://localhost:8080


Сравнение вариантов



Вариант
Сложность
Масштабируемость
Когда использовать




Nginx
Низкая
На 1 машину
Для простых случаев, production


Node.js балансировщик
Средняя
На 1 машину
Когда нужна кастомная логика


PM2
Низкая
На 1 машину
Быстрый старт, development


Docker
Средняя
На несколько машин
Микросервисы, облако




Частые ошибки и как их избежать
Ошибка 1: Забыли установить зависимости
npm install express axios  # Для Node.js балансировщика

Ошибка 2: Порты уже заняты
# Найти процесс на порту 8080
lsof -i :8080

# Убить процесс
kill -9 &lt;PID&gt;

Ошибка 3: Nginx ошибка при перезагрузке
# Проверить конфиг
nginx -t

# Если ошибка - смотреть её и исправлять

Ошибка 4: Соединение отказано (Connection refused)
# Убедитесь что все backend серверы работают!
curl http://localhost:3000
curl http://localhost:3001
curl http://localhost:3002


Команды для тестирования нагрузки
Простый тест через curl:
for i in {1..20}; do 
  curl http://localhost:8080 
  echo ""
done

Apache Bench (если установлен):
ab -n 1000 -c 10 http://localhost:8080/

Установка Apache Bench:
# macOS
brew install httpd

# Ubuntu
sudo apt-get install apache2-utils

wrk (продвинутый инструмент):
# Установка
git clone https://github.com/wg/wrk.git
cd wrk &amp;&amp; make

# Тест: 4 потока, 100 соединений, 30 секунд
./wrk -t4 -c100 -d30s http://localhost:8080/


Логирование и отладка
PM2 логи:
pm2 logs myapp --lines 100
pm2 logs myapp --err  # Только ошибки

Nginx логи:
# Все запросы
tail -f /var/log/nginx/access.log

# Ошибки
tail -f /var/log/nginx/error.log

Node.js логирование:
// Добавьте в app.js
const fs = require('fs');

app.use((req, res, next) =&gt; {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});


Дополнительные ресурсы

Документация Nginx: https://nginx.org/en/docs/
PM2 документация: https://pm2.io/docs/runtime/
Express.js: https://expressjs.com/
Axios: https://axios-http.com/

Готово! Выбирайте вариант, который вам нравится, и начинайте масштабировать!
]]></description><link>https://forum.exlends.ru/topic/386/node.js-i-balansirovshik-nagruzki-polnoe-rukovodstvo-dlya-novichkov</link><guid isPermaLink="true">https://forum.exlends.ru/topic/386/node.js-i-balansirovshik-nagruzki-polnoe-rukovodstvo-dlya-novichkov</guid><dc:creator><![CDATA[Aladdin]]></dc:creator><pubDate>Fri, 09 Jan 2026 20:16:15 GMT</pubDate></item><item><title><![CDATA[Node.js v25: ключевые изменения и рекомендации для миграции]]></title><link>https://forum.exlends.ru/topic/276/node.js-v25-klyuchevye-izmeneniya-i-rekomendacii-dlya-migracii</link><guid isPermaLink="true">https://forum.exlends.ru/topic/276/node.js-v25-klyuchevye-izmeneniya-i-rekomendacii-dlya-migracii</guid><pubDate>Thu, 16 Oct 2025 18:18:42 GMT</pubDate></item><item><title><![CDATA[Как удалять npm пакеты из package.json]]></title><description><![CDATA[А ещё может быть кому-то будет полезно удаление глобальных пакетов (не для конкретного проекта), можно к примеру воспользоваться командой: npm uninstall -g (название_пакета)
]]></description><link>https://forum.exlends.ru/topic/250/kak-udalyat-npm-pakety-iz-package.json</link><guid isPermaLink="true">https://forum.exlends.ru/topic/250/kak-udalyat-npm-pakety-iz-package.json</guid><dc:creator><![CDATA[Gleb_Osin]]></dc:creator><pubDate>Thu, 18 Sep 2025 13:48:27 GMT</pubDate></item><item><title><![CDATA[Сортировать двоичное дерево по уровням]]></title><link>https://forum.exlends.ru/topic/162/sortirovat-dvoichnoe-derevo-po-urovnyam</link><guid isPermaLink="true">https://forum.exlends.ru/topic/162/sortirovat-dvoichnoe-derevo-po-urovnyam</guid><pubDate>Thu, 26 Jun 2025 15:28:20 GMT</pubDate></item><item><title><![CDATA[Гайд по работе с TensorFlow.js: от нуля до первого нейрона 🧠]]></title><link>https://forum.exlends.ru/topic/133/gajd-po-rabote-s-tensorflow.js-ot-nulya-do-pervogo-nejrona</link><guid isPermaLink="true">https://forum.exlends.ru/topic/133/gajd-po-rabote-s-tensorflow.js-ot-nulya-do-pervogo-nejrona</guid><pubDate>Mon, 19 May 2025 16:53:00 GMT</pubDate></item><item><title><![CDATA[Релиз Node.js 24: Что нового в последней версии?]]></title><description><![CDATA[@Jspi Ого, прям побыстрее стал на 20% ±
Главное что бы работал 
]]></description><link>https://forum.exlends.ru/topic/126/reliz-node.js-24-chto-novogo-v-poslednej-versii</link><guid isPermaLink="true">https://forum.exlends.ru/topic/126/reliz-node.js-24-chto-novogo-v-poslednej-versii</guid><dc:creator><![CDATA[kirilljsx]]></dc:creator><pubDate>Wed, 14 May 2025 09:38:05 GMT</pubDate></item></channel></rss>