Эта статья была впервые опубликована вПубличный аккаунт команды разработчиков Maoyan, Пожалуйста, укажите источник.
предисловие
Если вы используете PM2 для управления процессами Node.js, вы обнаружите, что он поддерживает режим кластера. После включения режима кластера для Node.js можно создать несколько процессов. Если вы установите для экземпляров в режиме кластера значение max, будет также создано соответствующее количество процессов Node в зависимости от количества ядер ЦП на сервере.
PM2 на самом деле реализуется с помощью модуля Node.js Cluster, который решает однопоточную работу экземпляров Node.js и не может использовать преимущества многоядерных процессоров. Итак, как кластер работает внутри? Как взаимодействуют несколько процессов? Как несколько процессов прослушивают один и тот же порт? Как Node.js распределяет запросы между процессами? Если вам все еще не ясны приведенные выше вопросы, вы можете прочитать дальше.
основной принцип
Рабочие процессы Node.js запускаютсяchild_process.fork()
создание метода, что также означает наличие родительского процесса и нескольких дочерних процессов. Код примерно такой:
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
for (var i = 0, n = os.cpus().length; i < n; i += 1) {
cluster.fork();
}
} else {
// 启动程序
}
Студенты, изучавшие операционные системы, должны быть знакомы с системным вызовом fork() Процесс, вызывающий его, является родительским процессом, а вилка исходит из дочернего процесса. Дочерний процесс и родительский процесс имеют один и тот же сегмент кода, сегмент данных и стек, но их пространство памяти не является общим. Родительский процесс (то есть главный процесс) отвечает за прослушивание порта и отправку новых запросов следующим рабочим процессам после их получения. Здесь задействованы три проблемы: взаимодействие родительского и дочернего процессов, стратегия балансировки нагрузки и мониторинг портов с несколькими процессами.
Примечание: fork() в Linux поддерживает копирование при записи.Только при изменении содержимого каждого сегмента пространства процесса содержимое родительского процесса будет скопировано в дочерний процесс. Таким образом, дочерний процесс и родительский процесс изначально используют одно и то же пространство памяти.
связь процесса
Главный процесс создает дочерние процессы через process.fork() и обменивается данными между ними через канал IPC (межпроцессное взаимодействие). Основные способы межпроцессного взаимодействия в операционной системе следующие:
- Общая память Разные процессы совместно используют одно и то же пространство памяти. Обычно необходимо ввести семафорный механизм для достижения синхронизации и взаимного исключения.
- обмен сообщениями В этом режиме информация синхронизируется между процессами путем отправки и получения сообщений.
- сигнал Семафор — это просто значение состояния, присвоенное процессу системой.Процесс, который не контролируется, будет вынужден остановиться в определенном месте, ожидая сигнала, который может продолжаться. Если семафор имеет только два значения, 0 или 1, его также называют «блокировкой мьютекса». Этот механизм также широко используется в различных шаблонах программирования.
- трубопровод Сам канал также является процессом, он используется для соединения двух процессов, принимая выходные данные одного процесса в качестве входных данных другого процесса. Каналы можно создавать с помощью системного вызова pipe. Мы часто используем командную строку «|», чтобы использовать конвейерный механизм.
Node.js предоставляет механизм событий для обмена сообщениями между родительским и дочерним процессами. В следующем примере родительский процесс передает дескриптор объекта TCP-сервера дочернему процессу.
const subprocess = require('child_process').fork('subprocess.js');
// 开启 server 对象,并发送该句柄。
const server = require('net').createServer();
server.on('connection', (socket) => {
socket.end('被父进程处理');
});
server.listen(1337, () => {
subprocess.send('server', server);
});
process.on('message', (m, server) => {
if (m === 'server') {
server.on('connection', (socket) => {
socket.end('被子进程处理');
});
}
});
Тогда снова возникает вопрос, если между процессами нет отношения родитель-потомок, другими словами, как мы должны реализовать связь между произвольными процессами? Вы можете перейти к этой статье:Альтернативная реализация межпроцессного взаимодействия
стратегия балансировки нагрузки
Как упоминалось ранее, все запросы распределяются через главный процесс.Чтобы обеспечить сбалансированное распределение нагрузки сервера между каждым рабочим процессом, используется стратегия балансировки нагрузки. Стратегия по умолчанию, принятая Node.js, такова:round-robinМетод вращения временного среза.
Циклический алгоритм — это очень распространенный алгоритм балансировки нагрузки, который также используется в качестве одной из стратегий балансировки нагрузки в Nginx. Его принцип очень прост: каждый раз запрос от пользователя назначается каждому процессу по очереди, начиная с 1, до N (количество рабочих процессов), а затем цикл начинается заново. Проблема с этим алгоритмом заключается в том, что он предполагает, что производительность обработки каждого процесса или сервера одинакова, но если интервал обработки запросов велик, легко вызвать дисбаланс нагрузки. Поэтому мы обычно используем другой алгоритм на Nginx:WRR, взвешенный круговой метод. Присвоив каждому серверу определенный вес, каждый раз, когда выбирается сервер с наибольшим весом, его вес уменьшается на 1 до тех пор, пока все веса не будут равны 0, а опрос выполняется согласно сгенерированной в это время последовательности.
Политику балансировки нагрузки можно изменить, установив переменную среды NODE_CLUSTER_SCHED_POLICY или с помощью cluster.setupMaster(options). Прочитав это, вы обнаружите, что мы можем выполнять балансировку нагрузки на многомашинном кластере с помощью Nginx, а затем использовать кластер Node.js для достижения балансировки нагрузки на одной машине и нескольких процессах.
Многопроцессорное прослушивание портов
В исходном Node.js несколько процессов прослушивали один и тот же порт и конкурировали друг с другом за новые принятые соединения. Это приведет к тому, что загрузка каждого процесса будет очень несбалансированной, поэтому упомянутая выше стратегия циклического перебора используется позже. Конкретная идея заключается в том, что главный процесс создает сокет, привязывает адрес и слушает. fd сокета не передается отдельным рабочим процессам. Когда главный процесс получает новое соединение, он решает передать принятое клиентское соединение назначенному рабочему процессу для обработки. Проще говоря, главный процесс прослушивает порт, а затем перенаправляет соединение рабочему процессу с помощью некоторой стратегии распределения (например, циклического перебора). Таким образом, поскольку клиентские подключения получает только главный процесс, решается проблема несбалансированной нагрузки, вызванной конкуренцией. Но эта конструкция требует, чтобы стабильность основного процесса была достаточно хорошей.
Суммировать
В этой статье режим кластера PM2 используется в качестве отправной точки для ознакомления с основными принципами кластера Node.js для достижения многопроцессорности. Основное внимание уделяется трем аспектам взаимодействия процессов, балансировке нагрузки и мониторингу портов с несколькими процессами. Изучая модуль кластера, можно обнаружить, что многие лежащие в его основе принципы или алгоритмы на самом деле являются общими. Например, циклический алгоритм также используется при планировании процессов в нижней части операционной системы; например, архитектура master-worker знакома многопроцессорной архитектуре Nginx; такие механизмы, как семафоры и каналы, также могут использоваться в различных Они встречаются в различных шаблонах программирования. Сегодня на рынке появляются различные новые технологии, но ядро на самом делепостоянно меняющийся, поняв эти самые базовые знания, остальные тоже можно использовать по аналогии.
Ссылка на ссылку: