← Назад к вопросам
Как работает в Node.js один процесс с десятью подключениями?
2.0 Middle🔥 141 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает в Node.js один процесс с десятью подключениями?
Event-Driven Architecture
Node.js работает на базе Event Loop — это главная концепция. Один процесс (single-threaded на уровне JavaScript, но с многопоточностью в libuv) может обрабатывать тысячи одновременных соединений благодаря неблокирующему (асинхронному) вводу-выводу.
Как работает одно соединение
// === Клиент отправляет HTTP запрос ===
// Сервер получает событие 'connection' на порту 3000
const http = require('http');
const server = http.createServer((req, res) => {
// Это callback, который вызовется когда запрос пришёл
console.log(`Запрос от клиента: ${req.url}`);
// Обработка НЕБЛОКИРУЮЩАЯ - не ждём ничего
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('OK');
});
server.listen(3000);
10 одновременных подключений: что происходит в Event Loop
// === Сценарий: 10 клиентов отправляют запросы одновременно ===
const http = require('http');
const fs = require('fs').promises;
const server = http.createServer(async (req, res) => {
// МОМЕНТ 1: Запрос 1 приходит, начинаем обработку
console.log(`[${Date.now()}] Начало обработки запроса`);
// МОМЕНТ 2: Асинхронная операция (БД, файл, API)
// Важно: это НЕ блокирует другие запросы!
const data = await fs.readFile('data.json', 'utf8');
// Пока ждём файл, Event Loop может обрабатывать запросы 2-10
// МОМЕНТ 3: Данные готовы, отправляем ответ
res.writeHead(200);
res.end(data);
});
server.listen(3000);
// === Временная шкала (примерно) ===
// T=0ms: Client 1: GET /api/data
// T=1ms: Client 2: GET /api/data
// T=2ms: Client 3: GET /api/data
// ...
// T=9ms: Client 10: GET /api/data
// T=10ms: Client 1: readFile() завершилась -> отправляем ответ
// T=11ms: Client 2: readFile() завершилась -> отправляем ответ
// ...
// T=19ms: Client 10: readFile() завершилась -> отправляем ответ
// Всё заняло ~19ms вместо 19*50ms = 950ms если бы было БЛОКИРУЮЩЕЕ
Event Loop и задачи
// === Event Loop обрабатывает задачи по очереди ===
const server = http.createServer((req, res) => {
// Фаза 1: Синхронный код (БЫСТРО)
const userId = req.query.id;
// Фаза 2: Асинхронная операция
database.findUser(userId, (err, user) => {
// Callback вызовется позже, когда БД вернёт результат
// Тем временем, Event Loop может обработать другие запросы
res.json(user);
});
// Функция завершилась, но callback ещё выполняется в фоне
});
// === Event Loop очередь (примерно) ===
// 1. Timers (setTimeout, setInterval)
// 2. Pending callbacks (асинхронные операции)
// 3. Idle, prepare
// 4. Poll (ждёт новые события)
// 5. Check (setImmediate)
// 6. Close callbacks
// === Пример с setTimeout ===
console.log('1: Начало');
setTimeout(() => {
console.log('2: После timeout 0ms');
}, 0);
console.log('3: Конец');
// Вывод:
// 1: Начало
// 3: Конец
// 2: После timeout 0ms
// (setTimeout 0 всё равно идёт в очередь)
Когда один процесс НЕ справляется
// === ПРОБЛЕМА: Блокирующий код ===
const server = http.createServer((req, res) => {
// Это БЛОКИРУЮЩАЯ операция - останавливает весь Event Loop!
const data = fs.readFileSync('big-file.json');
// Пока читаем файл, ВСЕ 10 клиентов ждут
// Event Loop заморожен
res.json(JSON.parse(data));
});
// Вместо этого:
const server = http.createServer(async (req, res) => {
// Это НЕБЛОКИРУЮЩАЯ операция - освобождает Event Loop
const data = await fs.promises.readFile('big-file.json');
// Пока читаем файл, Event Loop может обработать другие запросы
res.json(JSON.parse(data));
});
CPU-intensive задачи: Worker Threads
// === ПРОБЛЕМА: Тяжёлые вычисления блокируют Event Loop ===
const crypto = require('crypto');
// Это будет блокировать на долгое время!
function slowHash(password) {
return crypto.pbkdf2Sync(password, 'salt', 100000, 64, 'sha512').toString('hex');
}
const server = http.createServer((req, res) => {
const hash = slowHash(req.body.password); // Все 10 клиентов ждут!
res.json({ hash });
});
// === РЕШЕНИЕ: Worker Threads ===
const { Worker } = require('worker_threads');
const path = require('path');
const server = http.createServer((req, res) => {
const worker = new Worker(path.join(__dirname, 'worker.js'));
worker.on('message', (hash) => {
res.json({ hash });
worker.terminate();
});
worker.postMessage(req.body.password);
});
// === worker.js ===
const crypto = require('crypto');
const { parentPort } = require('worker_threads');
parentPort.on('message', (password) => {
const hash = crypto.pbkdf2Sync(password, 'salt', 100000, 64, 'sha512').toString('hex');
parentPort.postMessage(hash);
});
// Теперь вычисления идут в отдельном потоке,
// Event Loop свободен для других запросов
Масштабирование: Cluster Module
// === Один процесс может использовать только один CPU core ===
// Для использования всех cores нужен Cluster
const cluster = require('cluster');
const os = require('os');
const http = require('http');
const numCores = os.cpus().length; // например, 8
if (cluster.isMaster) {
// Главный процесс создаёт worker'ов
for (let i = 0; i < numCores; i++) {
cluster.fork(); // Создаёт отдельный процесс Node.js
}
console.log(`Master запущен. ${numCores} worker'ов готовы обрабатывать запросы`);
} else {
// Каждый worker имеет свой Event Loop
const server = http.createServer((req, res) => {
res.writeHead(200);
res.end(`Worker ${process.pid} обработал запрос\n`);
});
server.listen(3000);
console.log(`Worker ${process.pid} слушает на порту 3000`);
}
// === Балансировка нагрузки ===
// Операционная система (OS) автоматически распределяет
// входящие соединения между worker'ами
// 10 клиентов могут быть распределены:
// Worker 1: 2 клиента
// Worker 2: 2 клиента
// Worker 3: 1 клиент
// и т.д.
Мониторинг памяти и производительности
// === Когда процесс начинает тормозить ===
const http = require('http');
const server = http.createServer((req, res) => {
// Проверяем использование памяти
const memUsage = process.memoryUsage();
console.log(`Память используется: ${Math.round(memUsage.heapUsed / 1024 / 1024)} MB`);
if (memUsage.heapUsed > 500 * 1024 * 1024) {
// Если > 500MB, нужно оптимизировать или рестартовать
console.warn('Критическое использование памяти!');
}
res.writeHead(200);
res.end('OK');
});
server.listen(3000);
// === Graceful shutdown ===
server.on('clientError', (err, socket) => {
if (err.code === 'ECONNRESET' || !socket.writable) {
return;
}
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
process.on('SIGTERM', () => {
console.log('Получен сигнал SIGTERM, закрываем соединения...');
server.close(() => {
console.log('Сервер закрыт. Процесс завершается.');
process.exit(0);
});
});