Opcje komunikacji międzydziedzinowej w węźle.Gromada js

Więc pracuję nad węzłem.js game server application w tej chwili, a ja Uderzyłem trochę ściany tutaj. Moim problemem jest to, że używam socket.io aby akceptować połączenia przychodzące od klientów Gry. Klienci ci mogą być podłączeni do jednej z kilku stref lub obszarów świata gry.

Podstawowa architektura jest wyświetlana poniżej. Proces master forks proces potomny dla każdej strefy gry, która uruchamia proces Zone Manager; proces dedykowany do utrzymania Dane strefowe (modele 3d, pozycje graczy/podmiotów itp.). Proces główny rozwidla wiele "wątków komunikacyjnych" dla każdego tworzonego Menedżera stref. Wątki te tworzą instancję socket.io i nasłuchuj na porcie dla tej strefy (wiele wątków nasłuchuje na jednym porcie). Wątki te będą obsługiwać większość logiki gry we własnym procesie, a także komunikować się z bazą danych obsługującą serwer gry. Jedynym problemem jest to, że w pewnych okolicznościach mogą potrzebować komunikuj się z menedżerem strefy, aby otrzymywać informacje o strefie, graczach itp.

Architektura

Na przykład: gracz chce kupować/sprzedawać/handlować z postacią non-player (NPC) w strefie. Wątek komunikacji strefowej musi zapytać wątek Menedżera stref, czy gracz jest wystarczająco blisko NPC, aby dokonać transakcji, zanim pozwoli na wymianę.

Problem, na który tu wpadam, polega na tym, że planowałem wykorzystać węzeł.funkcjonalność klastra js i użyj metod send() i on() procesów do obsługi przekazywania wiadomości tam iz powrotem. To byłoby w porządku, z wyjątkiem jednego zastrzeżenia, NA które się natknąłem. Ponieważ wszystkie procesy potomne wydzielone z cluster.fork() mogą komunikować się tylko z procesem "master". Węzeł.proces js root staje się wąskim gardłem dla całej komunikacji. Uruchomiłem kilka benchmarków na moim systemie za pomocą skryptu, który dosłownie po prostu odbijał wiadomość tam iz powrotem za pomocą komunikacji między procesami klastra (IPC) i śledziłem, jak wykonywano wiele przekaźników na sekundę. Wydaje się, że w końcu node caps się na około 20k na sekundę pod względem liczby IPC może przekazać. Liczba ta była zgodna zarówno w przypadku czterordzeniowego laptopa Phenom II 1,8 ghz, jak i 8-rdzeniowego komputera stacjonarnego FX-8350 4,0 ghz.

Teraz to brzmi dość przyzwoicie wysoko, z wyjątkiem tego, że zasadniczo oznacza to, że niezależnie od tego, ile stref lub wątków komunikacyjnych istnieje, Wszystkie IPC nadal jest wąskie przez jeden proces, który działa jako "przekaźnik" dla cała aplikacja. Co oznacza, że chociaż wydaje się, że każdy pojedynczy wątek może przekazywać > 20k IPC na sekundę, cała aplikacja jako całość nigdy nie przekaże więcej niż to, nawet jeśli byłoby to na jakimś szalonym 32 rdzeniowym systemie, ponieważ cała komunikacja przechodzi przez jeden wątek.

Więc to jest mój problem. Teraz dylemat. Czytałem dużo o różnych innych opcji tam i przeczytać jak 20 różnych pytań tutaj na stack na ten temat i widziałem kilka rzeczy pojawiają się regularnie:

Redis : Aktualnie uruchamiam Redis na moim serwerze i używam go jako socket.io datastore tak, że socket.io w wielu wątkach może udostępniać dane połączenia, dzięki czemu użytkownik może połączyć się z dowolną z N liczby socket.io wątki dla swojej strefy, dzięki czemu serwer może automatycznie ładować balans przychodzących połączeń.

Moim zmartwieniem jest to, że działa przez stos sieci. Trudno idealne do komunikacji między wiele procesów na tym samym serwerze. Myślę, że opóźnienie będzie poważnym problemem na dłuższą metę.

0MQ (zeromq/zmq) : Nigdy wcześniej tego nie używałem, ale ostatnio trochę o tym słyszałem. Opierając się na czytaniu, które zrobiłem, znalazłem wiele przykładów osób używających go z gniazdami TCP, ale nie ma wiele szumu o ludziach używających go do IPC. Miałem nadzieję, że być może ktoś tutaj pracował z 0MQ dla IPC wcześniej (być może nawet w node.js?) i może rzucić trochę światła na tę opcję dla mnie.

Dnode : Znowu nigdy tego nie używałem, ale z tego, co widziałem, wygląda na to, że jest to kolejna opcja zaprojektowana do pracy przez TCP, co oznacza, że stos sieci ponownie wchodzi w drogę.

Node-udpcomm : Ktoś podlinkował to w innym Pytaniu na tutaj (którego niestety nie mogę znaleźć ponownie). Nigdy o tym nie słyszałem i wygląda na bardzo małe rozwiązanie, które otwiera się i nasłuchuje na połączeniach UDP. Chociaż prawdopodobnie nadal byłoby to szybsze niż opcje TCP, nadal mamy stos sieciowy w drodze prawda? Jestem zdecydowanie około mili poza moją "strefą programistyczną", jak jest tutaj i dobrze w sferze sieci/architektury komputerowej rzeczy, które nie wiem zbyt wiele o lol

W każdym razie najważniejsze jest to, że utknąłem tu całkowicie i nie mam pojęcia, jaka byłaby najlepsza opcja dla IPC w tym scenariuszu. Zakładam w tej chwili, że 0MQ jest najlepszą opcją z tych Wymieniłem powyżej, ponieważ jest to jedyny, który wydaje się oferować opcję " IPC " dla protokołu komunikacyjnego, co, jak przypuszczam, oznacza, że używa gniazda UNIX lub czegoś, co nie przechodzi przez stos sieciowy, ale nie mogę tego potwierdzić ani nic.

Mam nadzieję, że niektórzy ludzie wiedzą wystarczająco dużo, by wskazać mi właściwy kierunek lub powiedzieć, że już tam jadę. Projekt, nad którym pracuję to serwer gier multiplayer zaprojektowany do pracy "po wyjęciu z pudełka" z multiplayerem klient gry zasilający swoją grafikę 3D/obliczenia za pomocą trzech.js. Klient i serwer staną się open source dla wszystkich, gdy wszyscy będą pracować ku mojej satysfakcji, i chcę się upewnić, że architektura jest tak skalowalna, jak to możliwe, aby ludzie nie budowali gry na tym, a następnie skalują się i kończą uderzając w ścianę.

W każdym razie dzięki za poświęcony czas, jeśli rzeczywiście przeczytać to wszystko:)

Author: Brian, 2013-01-20

1 answers

Myślę, że 0MQ byłby bardzo dobrym wyborem, ale przyznaję, że nie znam innych: d

Dla 0MQ jest przejrzyste, jakiego transportu zdecydujesz się użyć, wywołania biblioteki są takie same. Chodzi tylko o wybranie konkretnego punktu końcowego (a tym samym transportu) podczas wywołania zmq_bind i zmq_connect na początku. W zasadzie są 4 ścieżki, które możesz wybrać:

  1. "inproc://<id>" - punkt końcowy komunikacji w procesie pomiędzy wątkami poprzez pamięć
  2. "ipc://<filepath>" - zależne od systemu Inter-process communication endpoint
  3. "tcp://<ip-address>" - Wyczyść
  4. "pgm://..." lub "epgm://..." - punkt końcowy dla pragmatycznego niezawodnego multicastu

Mówiąc najprościej, im wyżej jesteś na liście, tym szybciej i mniej problemów z opóźnieniami i niezawodnością, z którymi musisz się zmierzyć. Więc powinieneś starać się utrzymać tak wysokie, jak to możliwe. Ponieważ twoje komponenty są procesami, powinieneś oczywiście skorzystać z transportu IPC. Jeśli później będziesz musiał coś zmienić, możesz po prostu zmienić definicja punktu końcowego i jesteś w porządku.

Teraz to, co jest w rzeczywistości ważniejsze od wybranego transportu, to typ gniazda, a raczej wzór, którego zdecydujesz się użyć. Twoja sytuacja jest typowym rodzajem komunikacji typu Prośba-odpowiedź, więc możesz albo zrobić

  1. Manager: REP socket, Threads: REQ socket; or
  2. Manager: ROUTER, wątki: REQ lub DEALER

Następnie wątki podłączają swoje gniazda do przypisanego im pojedynczego gniazda menedżera i to wszystko, mogą zacząć wysyłać swoje prośby i czekać na odpowiedzi. Wszystko, co muszą zdecydować, to ścieżka, którą wykorzystują jako punkt końcowy.

Ale szczegółowe opisanie, co oznaczają te wszystkie typy gniazd i wzorce, zdecydowanie nie wchodzi w zakres tego postu, ale możesz i powinieneś przeczytać więcej na ten temat w ZeroMQ Guide . Można tam nie tylko dowiedzieć się o wszystkich typach gniazd, ale także o wielu różnych sposobach łączenia komponentów i pozwalania im ze sobą rozmawiać. Na jeden, o którym wspomniałem, jest bardzo prosty. Gdy zrozumiesz, możesz zbudować dowolne hierarchie. To jak LEGO; -)

Mam nadzieję, że trochę pomogło, zdrówko!

 8
Author: tchap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-22 00:08:36