Параметры взаимодействия между дочерними процессами в кластере node.js

Итак, я сейчас работаю над приложением на игровом сервере node.js, и здесь я наткнулся на стену. Моя проблема в том, что я использую socket.io для приема входящих подключений от игровых клиентов. Эти клиенты могут быть подключены к одной из нескольких зон или областей игрового мира.

Основная архитектура показана ниже. Главный процесс разветвляет дочерний процесс для каждой зоны игры, в которой выполняется процесс диспетчера зон; процесс, посвященный ведению данных Зоны (3d модели, позиции игроков / сущностей и т. д.). Затем главный процесс разветвляет несколько "коммуникационных потоков" для каждого менеджера зон, который он создает. Эти потоки создают экземпляр socket.io и прослушивают порт для этой зоны (несколько потоков прослушивают один порт). Эти потоки будут обрабатывать большую часть игровой логики в своем собственном процессе, а также взаимодействовать с базой данных, поддерживающей игровой сервер. Единственная проблема заключается в том, что в некоторых случаях им может потребоваться связаться с менеджером зоны, чтобы получить информацию о зоне, игроках и т. Д.

Архитектура

Как пример: игрок хочет купить / продать / обменять с неигровым персонажем (NPC) в Зоне. Поток Zone Communication должен спросить поток Zone Manager, находится ли игрок достаточно близко к NPC, чтобы совершить сделку, прежде чем он позволит совершить сделку.

Проблема, с которой я здесь сталкиваюсь, заключается в том, что я планировал использовать функциональность кластера node.js и использовать send() а также on() методы процессов для обработки передачи сообщений туда и обратно. Это было бы хорошо, за исключением одного предупреждения, с которым я столкнулся. Поскольку все дочерние процессы cluster.fork() может общаться только с "мастером" процесса. Корневой процесс node.js становится узким местом для всего взаимодействия. Я запустил некоторые тесты в моей системе, используя скрипт, который буквально просто перебрасывал сообщение назад и вперед, используя межпроцессное взаимодействие кластера (IPC), и отслеживал, сколько выполнялось реле в секунду. Похоже, что в конечном итоге узел работает со скоростью около 20 Кбит / с с точки зрения количества IPC, которые он может передавать. Это число было одинаковым как для четырехъядерного ноутбука Phenom II 1,8 ГГц, так и для 8-ядерного настольного компьютера FX-8350 4,0 ГГц.

Теперь это звучит довольно прилично, за исключением того, что это в основном означает, что независимо от того, сколько существует зон или коммуникационных потоков, все IPC все еще остаются узким местом в одном процессе, который действует как "ретранслятор" для всего приложения. Это означает, что, хотя кажется, что каждый отдельный поток может ретранслировать> 20 тыс. IPC в секунду, все приложение в целом никогда не будет ретранслировать больше, чем это, даже если бы оно было в какой-то безумной 32-ядерной системе, поскольку вся связь проходит через один поток.

Вот в чем проблема. Теперь дилемма. Я много читал о различных других вариантах и ​​прочитал около 20 различных вопросов в стеке по этой теме, и я видел несколько вещей, которые появляются регулярно:

Redis: На самом деле я сейчас запускаю Redis на своем сервере и использую его в качестве хранилища данных socket.io, чтобы socket.io в нескольких потоках мог обмениваться данными о подключении, чтобы пользователь мог подключиться к любому из N номеров socket.io потоки для их зоны, так что сервер может сортировать балансировку нагрузки входящих соединений.

Меня беспокоит то, что он проходит через сетевой стек. Вряд ли идеально подходит для связи между несколькими процессами на одном сервере. Я чувствую, что задержка будет главной проблемой в долгосрочной перспективе.

0MQ (zeromq / zmq): я никогда раньше не использовал его ни для чего, но в последнее время немного слышал об этом. Основываясь на прочитанном мною чтении, я нашел много примеров людей, использующих его с сокетами TCP, но людей, использующих его для IPC, не так много. Я надеялся, что кто-то здесь раньше работал с 0MQ для IPC (возможно, даже в node.js?) И мог бы пролить свет на эту опцию для меня.

dnode: Опять же, я никогда не использовал это, но из того, что я видел, похоже, что это еще один вариант, разработанный для работы через TCP, что означает, что сетевой стек снова мешает.

node-udpcomm: Кто-то связал это в другом вопросе здесь (который, к сожалению, я не могу найти снова). Я никогда даже не слышал об этом, и похоже, что это очень маленькое решение, которое открывается и прослушивает соединения UDP. Хотя это, вероятно, все еще будет быстрее, чем параметры TCP, у нас все еще есть сетевой стек, верно? Я определенно нахожусь примерно в миле от моей "зоны программистов", как и здесь, и хорошо разбираюсь в области сетевой / компьютерной архитектуры, которую я мало знаю о LOL

В любом случае, суть в том, что я полностью застрял здесь и понятия не имею, какой вариант будет лучшим для IPC в этом сценарии. На данный момент я предполагаю, что 0MQ - лучший вариант из перечисленных выше, поскольку он единственный, который предлагает опцию "IPC" для протокола связи, который, как я предполагаю, означает, что он использует сокет UNIX или что-то такое, что не проходит через сетевой стек, но я не могу подтвердить это или что-то еще.

Я думаю, я просто надеюсь, что некоторые люди здесь могут знать достаточно, чтобы указать мне правильное направление или сказать мне, что я уже направился туда. Проект, над которым я работаю, представляет собой многопользовательский игровой сервер, предназначенный для работы "из коробки" с многопользовательским игровым клиентом, который обеспечивает работу 3D-графики / вычислений с Three.js. Клиент и сервер станут открытыми для всех, как только я заставлю их всех работать к своему удовольствию, и я хочу убедиться, что архитектура максимально масштабируема, чтобы люди не строили игру на этом, а затем переходили к масштабированию. и в конечном итоге ударить стену.

В любом случае, спасибо за ваше время, если вы действительно все это прочитали:)

1 ответ

Решение

Я думаю, что 0MQ был бы очень хорошим выбором, но я признаю, что я не знаю других:D

Для 0MQ прозрачно, какой транспорт вы решите использовать, библиотечные вызовы одинаковы. Это просто о выборе конкретной конечной точки (и, следовательно, транспорта) во время вызова zmq_bind а также zmq_connect в начале. Есть четыре основных пути, по которым вы можете выбрать:

  1. "inproc://<id>" - конечная точка связи в процессе между потоками через память
  2. "ipc://<filepath>" - системно-зависимая конечная точка межпроцессного взаимодействия
  3. "tcp://<ip-address>" - Чисто
  4. "pgm://..." или же "epgm://..." - конечная точка для Pragmatic Reliable Multicast

Проще говоря, чем выше вы находитесь в списке, тем быстрее он работает и тем меньше проблем, связанных с задержкой и надежностью. Поэтому вы должны стараться держаться как можно выше. Поскольку ваши компоненты являются процессами, вы, естественно, должны использовать IPC-транспорт. Если вам позже потребуется что-то изменить, вы можете просто изменить определение конечной точки, и у вас все в порядке.

Теперь, что на самом деле важнее, чем выбранный вами транспорт, это тип сокета или, скорее, шаблон, который вы решили использовать. Ваша ситуация представляет собой типичный тип запроса-ответа, поэтому вы можете сделать

  1. Менеджер: REP сокет, Темы: REQ сокет; или же
  2. Менеджер: ROUTER, Темы: REQ или ДИЛЕР

Затем потоки подключают свои сокеты к одному назначенному им сокету диспетчера, и все, они могут начать отправлять свои запросы и ждать ответов. Все, что им нужно выбрать, это путь, который они используют в качестве конечной точки.

Но подробное описание того, что означают все эти типы и шаблоны сокетов, определенно выходит за рамки этого поста, но вы можете и должны прочитать об этом подробнее в Руководстве по ZeroMQ. Там вы можете не только узнать обо всех типах сокетов, но и о множестве различных способов подключения компонентов и обеспечения их взаимодействия друг с другом. Тот, который я упомянул, очень простой. Как только вы понимаете, вы можете строить произвольные иерархии. Это как LEGO;-)

Надеюсь, это помогло немного, ура!

Другие вопросы по тегам