Кластер¶
Стабильность: 2 – Стабильная
АПИ является удовлетворительным. Совместимость с NPM имеет высший приоритет и не будет нарушена кроме случаев явной необходимости.
Кластеры процессов Node.js можно использовать для запуска нескольких экземпляров Node.js, которые могут распределять рабочую нагрузку между своими потоками приложений. Если изоляция процессов не требуется, используйте вместо этого модуль worker_threads
, который позволяет запускать несколько потоков приложений в рамках одного экземпляра Node.js.
Модуль кластера позволяет легко создавать дочерние процессы, которые совместно используют серверные порты.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Запущенный Node.js теперь будет делить порт 8000 между рабочими:
1 2 3 4 5 6 |
|
В Windows пока невозможно настроить сервер именованных труб в рабочем.
Как это работает¶
Рабочие процессы порождаются с помощью метода child_process.fork()
, чтобы они могли общаться с родителем по IPC и передавать хэндлы сервера туда и обратно.
Кластерный модуль поддерживает два метода распределения входящих соединений.
Первый (и тот, который используется по умолчанию на всех платформах, кроме Windows) - это метод round-robin, когда основной процесс прослушивает порт, принимает новые соединения и распределяет их между рабочими процессами по кругу, с некоторыми встроенными умными функциями, чтобы избежать перегрузки рабочего процесса.
Второй подход заключается в том, что основной процесс создает сокет для прослушивания и отправляет его заинтересованным рабочим. Затем рабочие принимают входящие соединения напрямую.
Теоретически, второй подход должен обеспечивать наилучшую производительность. На практике, однако, распределение имеет тенденцию быть очень несбалансированным из-за капризов планировщика операционной системы. Наблюдались нагрузки, когда более 70% всех соединений оказывались только в двух процессах из восьми.
Поскольку server.listen()
передает большую часть работы основному процессу, есть три случая, когда поведение обычного процесса Node.js и рабочего кластера различается:
server.listen({fd: 7})
Поскольку сообщение передается первичному процессу, дескриптор файла 7 в родительском будет прослушан, а хэндл передан рабочему, вместо того, чтобы прослушать представление рабочего о том, на что ссылается дескриптор файла с номером 7.- Если
server.listen(handle)
явно прослушивать хэндлы, то рабочий будет использовать предоставленный хэндл, а не обращаться к первичному процессу. server.listen(0)
Обычно это заставляет серверы прослушивать случайный порт. Однако в кластере каждый рабочий будет получать один и тот же "случайный" порт каждый раз, когда он выполняет командуlisten(0)
. По сути, порт является случайным в первый раз, но предсказуемым в последующие. Чтобы прослушивать уникальный порт, сгенерируйте номер порта на основе ID рабочего кластера.
Node.js не предоставляет логику маршрутизации. Поэтому важно разработать приложение таким образом, чтобы оно не слишком полагалось на объекты данных в памяти для таких вещей, как сессии и вход в систему.
Поскольку рабочие являются отдельными процессами, они могут быть убиты или перерождены в зависимости от потребностей программы, не затрагивая других рабочих. Пока живы рабочие, сервер будет продолжать принимать соединения. Если ни один рабочий не жив, существующие соединения будут сброшены, а новые соединения будут отклонены. Однако Node.js не управляет количеством рабочих автоматически. Приложение обязано управлять пулом рабочих в соответствии со своими потребностями.
Хотя основным вариантом использования модуля node:cluster
является работа в сети, его можно использовать и для других случаев, требующих рабочих процессов.
Класс: Worker
¶
- Расширяет:
<EventEmitter>
Объект Worker
содержит всю публичную информацию и метод о работнике. В первичной системе он может быть получен с помощью cluster.workers
. В рабочем он может быть получен с помощью cluster.worker
.
Событие: 'disconnect'
¶
Аналогично событию cluster.on('disconnect')
, но специфично для этого рабочего.
1 2 3 |
|
Событие: error
.¶
Это событие аналогично событию, предоставляемому child_process.fork()
.
Внутри рабочего процесса также может использоваться process.on('error')
.
Событие: exit
¶
code
<number>
Код выхода, если выход произошел нормально.signal
<string>
Имя сигнала (например,'SIGHUP'
), который вызвал завершение процесса.
Аналогично событию cluster.on('exit')
, но специфично для данного рабочего.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Событие: listening
¶
адрес
<Object>
Аналогично событию cluster.on('listening')
, но специфично для этого рабочего.
1 2 3 |
|
1 2 3 |
|
Это не эмитируется в воркере.
Событие: message
¶
message
<Object>
handle
{undefined|Object}
Аналогично событию 'message'
из cluster
, но специфично для этого рабочего.
Внутри рабочего может также использоваться process.on('message')
.
См. событие process
: 'message'
.
Вот пример использования системы сообщений. Он ведет подсчет в основном процессе количества HTTP-запросов, полученных рабочими:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Событие: 'online'
¶
Аналогично событию cluster.on('online')
, но специфично для этого рабочего.
1 2 3 |
|
Это не выдается в воркере.
worker.disconnect()
¶
- Возвращает: {cluster.Worker} Ссылка на
worker
.
В рабочем эта функция закроет все серверы, дождется события 'close'
на этих серверах, а затем отключит IPC-канал.
В первичном, внутреннее сообщение посылается рабочему, заставляя его вызвать .disconnect()
на себя.
Это вызывает установку .exitedAfterDisconnect
.
После закрытия сервера он больше не будет принимать новые соединения, но соединения могут быть приняты любым другим прослушивающим рабочим. Существующие соединения будут закрываться обычным образом. Когда соединений больше не будет, см. server.close()
, IPC-канал к рабочему будет закрыт, что позволит ему умереть изящно.
Вышесказанное относится только к серверным соединениям, клиентские соединения не закрываются автоматически рабочими, и disconnect не ждет их закрытия перед выходом.
В рабочем, process.disconnect
существует, но это не эта функция; это disconnect()
.
Поскольку долгоживущие соединения с сервером могут блокировать отключение рабочих, может быть полезно посылать сообщение, чтобы можно было предпринять конкретные действия для их закрытия. Также может быть полезно реализовать таймаут, убивающий рабочего, если событие 'disconnect'
не было выдано через некоторое время.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
worker.exitedAfterDisconnect
¶
Это свойство равно true
, если рабочий вышел из системы в результате .disconnect()
. Если рабочий вышел другим способом, оно равно false
. Если рабочий не вышел, то не определено
.
Булево значение worker.exitedAfterDisconnect
позволяет отличить добровольный выход от случайного, на основании этого значения первичная система может решить не перезапускать рабочего.
1 2 3 4 5 6 7 8 9 10 |
|
worker.id
¶
Каждому новому работнику присваивается свой уникальный id, этот id хранится в id
.
Пока рабочий жив, это ключ, по которому он индексируется в cluster.workers
.
worker.isConnected()
¶
Эта функция возвращает true
, если рабочий подключен к своему первичному серверу через его IPC-канал, false
в противном случае. Рабочий подключается к своему первичному серверу после его создания. Он отключается после возникновения события 'disconnect'
.
worker.isDead()
¶
Эта функция возвращает true
, если процесс рабочего завершился (либо из-за выхода, либо из-за получения сигнала). В противном случае она возвращает false
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
worker.kill([signal])
¶
signal
<string>
Имя сигнала kill, который нужно послать рабочему процессу. По умолчанию:SIGTERM
.
Эта функция убивает рабочий процесс. В основном рабочем она делает это путем отключения worker.process
, а после отключения убивает с помощью signal
. В рабочем это происходит путем уничтожения процесса с помощью signal
.
Функция kill()
убивает рабочий процесс, не дожидаясь изящного разъединения, она имеет такое же поведение, как и worker.process.kill()
.
Для обратной совместимости этот метод называется worker.destroy()
.
В рабочем процессе существует process.kill()
, но это не эта функция, а kill()
.
worker.process
¶
ChildProcess
Все рабочие создаются с помощью child_process.fork()
, возвращаемый объект из этой функции хранится как .process
. В рабочем хранится глобальный process
.
См: Модуль Child Process.
Рабочие процессы будут вызывать process.exit(0)
, если событие 'disconnect'
произойдет на process
и .exitedAfterDisconnect
не будет true
. Это защищает от случайного отключения.
worker.send(message[, sendHandle[, options]][, callback])
¶
message
<Object>
sendHandle
Handle
options
<Object>
Аргументoptions
, если он присутствует, представляет собой объект, используемый для параметризации отправки определенных типов дескрипторов.options
поддерживает следующие свойства:keepOpen
<boolean>
Значение, которое может использоваться при передаче экземпляровnet.Socket
. Когдаtrue
, сокет остается открытым в процессе отправки. По умолчанию:false
.
callback
<Function>
- Возвращает:
<boolean>
Отправка сообщения на рабочий или первичный сервер, опционально с хэндлом.
В первичном случае это отправляет сообщение конкретному рабочему. Она идентична ChildProcess.send()
.
В рабочем процессе это отправляет сообщение на основной. Это идентично process.send()
.
В этом примере все сообщения от первичного сервера будут возвращены эхом:
1 2 3 4 5 6 7 8 |
|
Событие: разъединение
¶
worker
{cluster.Worker}
Выдается после отключения IPC-канала рабочего. Это может произойти, когда рабочий изящно завершает работу, его убивают или отключают вручную (например, с помощью worker.disconnect()
).
Между событиями 'disconnect'
и 'exit'
может быть задержка. Эти события могут быть использованы для обнаружения того, что процесс застрял в очистке или что есть долгоживущие соединения.
1 2 3 |
|
Событие: выход
¶
worker
{cluster.Worker}code
<number>
Код выхода, если он вышел нормально.signal
<string>
Имя сигнала (например,'SIGHUP'
), который вызвал завершение процесса.
Когда любой из рабочих умирает, кластерный модуль выдает событие 'exit'
.
Это событие можно использовать для перезапуска рабочего путем повторного вызова .fork()
.
1 2 3 4 5 6 7 8 |
|
См. событие child_process
: 'exit'
.
Событие: fork
¶
worker
{cluster.Worker}
При форке нового рабочего модуль кластера будет выдавать событие 'fork'
. Это событие можно использовать для регистрации активности рабочего и создания пользовательского таймаута.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Событие: listening
¶
worker
{cluster.Worker}адрес
<Object>
После вызова функции listen()
от рабочего, когда событие 'listening'
испускается на сервере, событие 'listening'
также будет испущено на cluster
в первичном.
Обработчик события выполняется с двумя аргументами, worker
содержит объект worker, а объект address
содержит следующие свойства соединения: address
, port
и addressType
. Это очень полезно, если рабочий прослушивает более одного адреса.
1 2 3 4 5 |
|
Тип addressType
является одним из:
4
(TCPv4)6
(TCPv6)-1
(Unix domain socket)'udp4`` или
'udp6`` (UDPv4 или UDPv6)
Событие: message
¶
worker
{cluster.Worker}сообщение
<Object>
handle
{undefined|Object}
Выдается, когда основной кластер получает сообщение от любого рабочего.
См. child_process
event: 'message'
.
Событие: online
¶
worker
{cluster.Worker}
После форкинга нового рабочего, рабочий должен ответить сообщением online. Когда основной получает сообщение online, он испускает это событие. Разница между 'fork'
и 'online'
заключается в том, что fork испускается, когда первичный вилкует рабочего, а 'online'
испускается, когда рабочий запущен.
1 2 3 4 5 |
|
Событие: setup
¶
settings
<Object>
Выдается каждый раз при вызове .setupPrimary()
.
Объект settings
представляет собой объект cluster.settings
на момент вызова .setupPrimary()
и является только рекомендательным, так как за один такт может быть сделано несколько вызовов .setupPrimary()
.
Если важна точность, используйте cluster.settings
.
cluster.disconnect([callback])
¶
callback
<Function>
Вызывается, когда все рабочие отсоединены и ручки закрыты.
Вызывает .disconnect()
для каждого рабочего в cluster.workers
.
Когда они будут отключены, все внутренние ручки будут закрыты, что позволит основному процессу изящно завершиться, если не ожидается никакого другого события.
Метод принимает необязательный аргумент обратного вызова, который будет вызван после завершения.
Этот метод может быть вызван только из основного процесса.
cluster.fork([env])
¶
env
<Object>
Пары ключ/значение для добавления в окружение рабочего процесса.- Возвращает: {cluster.Worker}
Порождает новый рабочий процесс.
Это может быть вызвано только из основного процесса.
cluster.isMaster
¶
Утративший силу псевдоним для cluster.isPrimary
.
cluster.isPrimary
¶
Истина, если процесс является первичным. Это определяется process.env.NODE_UNIQUE_ID
. Если process.env.NODE_UNIQUE_ID
не определен, то isPrimary
будет true
.
cluster.isWorker
¶
Истина, если процесс не является основным (это отрицание cluster.isPrimary
).
cluster.schedulingPolicy
¶
Политика планирования, либо cluster.SCHED_RR
для round-robin, либо cluster.SCHED_NONE
, чтобы оставить это на усмотрение операционной системы. Это глобальная настройка и фактически замораживается после порождения первого рабочего или вызова .setupPrimary()
, в зависимости от того, что произойдет раньше.
По умолчанию используется SCHED_RR
во всех операционных системах, кроме Windows. Windows перейдет на SCHED_RR
, когда libuv сможет эффективно распределять ручки IOCP без большого падения производительности.
cluster.schedulingPolicy
также может быть задана через переменную окружения NODE_CLUSTER_SCHED_POLICY
. Допустимыми значениями являются 'rr'
и 'none'
.
cluster.settings
¶
<Object>
execArgv
<string[]>
Список строковых аргументов, передаваемых исполняемому файлу Node.js. По умолчанию:process.execArgv
.exec
<string>
Путь к рабочему файлу. По умолчанию:process.argv[1]
.args
<string[]>
Строковые аргументы, передаваемые рабочему. По умолчанию:process.argv.slice(2)
.cwd
<string>
Текущий рабочий каталог рабочего процесса. По умолчанию:undefined
(наследуется от родительского процесса).serialization
<string>
Укажите вид сериализации, используемой для отправки сообщений между процессами. Возможные значения:'json'' и
'advanced''. Подробнее см. в Advanced serialization forchild_process
. По умолчанию:false
.silent
<boolean>
Посылать ли вывод на родительский stdio. По умолчанию:false
.stdio
<Array>
Настраивает stdio вилочных процессов. Поскольку для работы кластерного модуля используется IPC, эта конфигурация должна содержать запись'ipc'
. Когда эта опция указана, она отменяетsilent
.uid
<number>
Устанавливает идентификатор пользователя процесса. (См. setuid(2).)gid
<number>
Устанавливает групповую идентификацию процесса. (См. setgid(2).)inspectPort
{number|Function} Задает инспекторский порт рабочего. Это может быть число или функция, которая не принимает аргументов и возвращает число. По умолчанию каждый рабочий получает свой собственный порт, увеличивающийся отprocess.debugPort
первичного.windowsHide
<boolean>
Скрыть консольное окно вилочных процессов, которое обычно создается в системах Windows. По умолчанию:false
.
После вызова .setupPrimary()
(или .fork()
) этот объект настроек будет содержать настройки, включая значения по умолчанию.
Этот объект не предназначен для изменения или настройки вручную.
cluster.setupMaster([settings])
¶
Утративший силу псевдоним для .setupPrimary()
.
cluster.setupPrimary([settings])
¶
settings
<Object>
См.cluster.settings
.
setupPrimary
используется для изменения поведения "вилки" по умолчанию. После вызова настройки будут присутствовать в cluster.settings
.
Любые изменения настроек влияют только на будущие вызовы .fork()
и не влияют на уже запущенные рабочие.
Единственный атрибут рабочего, который не может быть установлен через .setupPrimary()
- это env
, переданный в .fork()
.
Приведенные выше значения по умолчанию относятся только к первому вызову; значения по умолчанию для последующих вызовов - это текущие значения на момент вызова cluster.setupPrimary()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Это может быть вызвано только из основного процесса.
cluster.worker
¶
Ссылка на текущий объект worker. Недоступно в основном процессе.
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 |
|
cluster.workers
¶
Хэш, хранящий активные объекты рабочих, с ключом по полю id
. Это позволяет легко перебирать всех рабочих. Он доступен только в основном процессе.
Рабочий удаляется из cluster.workers
после того, как он отключился и вышел. Порядок между этими двумя событиями не может быть определен заранее. Однако гарантируется, что удаление из списка cluster.workers
произойдет до того, как произойдет последнее событие 'disconnect'
или 'exit'
.
1 2 3 4 5 |
|
1 2 3 4 5 |
|