Проверяет понимание особенностей разработки Node.js-приложений, работающих в кластерном режиме с несколькими воркерами, и типичных ошибок при работе с общим состоянием.
Кластерный режим в Node.js запускает несколько процессов-воркеров, каждый из которых является полноценным экземпляром приложения со своей памятью, event loop и стеком. Это значит, что любые данные, сохранённые в переменных модуля или в глобальном объекте, будут существовать отдельно в каждом воркере и не будут синхронизированы между ними.
Приложение должно быть stateless: каждый запрос обрабатывается независимо, а состояние хранится во внешних сервисах. Сессии — в Redis или в подписанных cookie, кэш — в Redis/Memcached, очереди — в RabbitMQ/Kafka, блокировки — через распределённый lock (например, Redlock).
// Плохо: счётчик живёт в памяти одного воркера
let counter = 0;
app.get('/inc', (req, res) => res.json({ count: ++counter }));
// Хорошо: состояние в Redis, доступно всем воркерам
const redis = require('redis').createClient();
app.get('/inc', async (req, res) => {
const count = await redis.incr('counter');
res.json({ count });
});
Каждый воркер открывает собственные соединения с БД, Redis и другими сервисами. Нужно следить за размером пула соединений: суммарное число коннектов = пул × количество воркеров. Также таймеры и интервалы создаются в каждом процессе отдельно, что может привести к дублированию действий.
Если приложение всё же хранит состояние в памяти (например, WebSocket-сессии), потребуется sticky sessions на балансировщике, чтобы запросы одного клиента попадали в один воркер. Но это усложняет масштабирование и не спасает при падении воркера.
Итог: приложение для кластера должно быть stateless, а всё общее состояние вынесено во внешние хранилища. Это делает систему горизонтально масштабируемой и устойчивой к падению отдельных воркеров.