Czy istnieje sposób na uczynienie dynamicznego świata takim jak MMORPG skalowalnym w poziomie?

11

Wyobraź sobie otwarty świat ponad 500 graczy z danymi zmieniającymi się tak szybko, jak 20 aktualizacji / gracza / sekundę. Ostatnim razem, gdy pracowałem w podobnej MMORPG, używał SQL, więc oczywiście nie mógł cały czas sprawdzać DB. Zamiast tego załadował wszystkie odtwarzacze z bazy danych do pamięci jako obiekty C ++ i wykorzystał je. Oznacza to, że skalowane są w pionie. Czy zamiast tego można by uczynić ten serwer skalowanym poziomo? Czy istnieje baza danych zaprojektowana tak, aby obsługiwać tę liczbę aktualizacji jednocześnie?

MaiaVictor
źródło
Dlaczego chcesz aktualizować odtwarzacz w bazie danych 20 razy / sekundę?
Balon
@Balon, gdzie jestem zdezorientowany. Jeśli nie zaktualizuję go w bazie danych, tylko w pamięci, będę mieć różne stany między różnymi komputerami. Ale wydaje mi się, że aktualizacje DB mają duże obciążenie, więc tak naprawdę nie zadziała w przypadku tak dużej liczby aktualizacji?
MaiaVictor
2
Jeśli naprawdę, naprawdę uważasz, że różne maszyny (lub nawet procesy) potrzebują aktualizacji 20 Hz dla setek obiektów, całkowicie pomiń bazę danych i użyj bezpośrednio systemu przesyłania wiadomości. Ale to, co naprawdę myślisz, że chcesz, nie jest tym, czego naprawdę chcesz. To, czego chcesz, to mieć rozsądny zakres tego, kto musi wiedzieć, a następnie mieć sposób na porządny transport obiektów między lunetami. Powinieneś odpowiedzieć na pytanie, dlaczego potrzebujesz aktualizacji 20 Hz między różnymi maszynami, aby uzyskać świetne odpowiedzi, ktoś może pomyśleć o nowym sposobie spojrzenia na problem.
Patrick Hughes
@PatrickHughes Nie wiem, czego potrzebuję, wyjaśniam tylko, jak działa gra. Postacie poruszają się 2 ~ 3 płytki na sekundę. Polowanie na gracza może być otoczone przez kilka potworów, więc co najmniej 10 płytek / gracza / sekundę. Następnie na podłodze, na plecaku gracza rozkładają się przedmioty. Są ataki poruszające się w kierunku gracza, są ataki poruszające się w kierunku potwora. Gnije zdrowie, używa się many, liczniki zadają graczowi obrażenia od trucizny. Rzeczy zmieniają się naprawdę szybko. To jest projekt gry. Jak taki projekt można skalować w pionie?
MaiaVictor
1
Widziałem to jakiś czas temu w HackerNews: paralleluniverse.co Pracują nad bazą danych, która wykonuje wszystkie operacje segmentacji / dystrybucji przestrzennej. Sądzę, że pod maską robią wszystkie rzeczy z poniższych odpowiedzi.
holowniki

Odpowiedzi:

17

Przypadek testowy 500 graczy, którzy się komunikują, czyli 250 000 strumieni informacji latających z częstotliwością 20 Hz. Wewnętrzna przepustowość tego, przy założeniu 100 bajtów każdej wiadomości, wynosiłaby około 500 MB / s. Brzmi ambitnie. Zwłaszcza między procesami.

Jeśli posegregujesz graczy do grup po 100, obniży się to do 20 MB / s i tak dalej. Właśnie dlatego MMO mają strefy, aw tych strefach małe bąbelki wpływów i tak dalej w dół, aż przepustowość stanie się rozsądna.

Pierwotny problem można stwierdzić, że jeśli masz 10 osób, które dzielą się informacjami w czasie rzeczywistym, a chcesz 500 osób , to gwałtownie rośnie liczba łączy komunikacyjnych i jak możemy to obejść . Obawiam się, że nie ma żadnej magicznej kuli, o której kiedykolwiek słyszałem, która magicznie sprawiłaby, że geometryczny postęp zniknął.

Nie używaj bazy danych do komunikacji, po to jest przesyłanie wiadomości. Użyj bazy danych, aby wymusić transakcje i przechowywać informacje, których nie chcesz, aby gracze stracili. Większość MMO, które znam, aktualizuje bazę danych dynamicznymi informacjami o graczach co 1-10 minut lub w przydatnych punktach, takich jak przejścia stref lub wchodzenie do „bezpiecznych” stref w projekcie.

Być może trzeba będzie przeprojektować w grze konieczność dla każdego gracza, niezależnie od tego, jak daleko, aby mieć w czasie rzeczywistym aktualizacje zawartości plecaka każdego innego gracza.

Zmień również wzór aktualizacji z 20 Hz na prędkość zależną od odległości, ktoś w odległości 1 mili nie musi wiedzieć, że przesunąłeś 1 stopę dokładnie o 230,6 sekundy, a następnie kolejną stopę o 231,4 sekundy, może poradzić sobie z tobą poruszając się 15 stóp co 10 sekundy.

Patrick Hughes
źródło
Świetna i pouczająca odpowiedź, dzięki. Ale mogę dodać, że podczas gdy świat zmienia się w bardzo szybkim tempie, gracz widzi tylko innych graczy bezpośrednio obok niego. Nie uważam tego za geometryczne - 500 graczy wysyła informacje na serwer; serwer okresowo wysyła informacje do tych 500 graczy. Jak widzę, jest liniowy. Ale główny punkt dotyczy czwartego akapitu: jeśli używam tylko bazy danych do przechowywania, to ładuję dane do pamięci. Jeśli ładuję dane do pamięci na komputerze, tworzę desynchronizowaną wersję świata. Tego nie rozumiem.
MaiaVictor
Dla 1 klienta: 1 msg na zewnątrz + 1 msg na = 2. Dla 2 klientów: 2 msg na zewnątrz, 2 msg na = 4. Dla 3 klientów: 3 msg na zewnątrz, 3 msg na = 9. I tak to idzie. To jest tak: wyślij wiadomość o stanie, serwer wysyła wyniki do mnie i pozostałych 2 klientów (1 wejście, 3 wyjścia) i 3 klientów, którzy to robią (1 wejście na 9 wyjść). Choć wygląda na liniowy tylko dla jednego klienta z 3, można pomnożyć to przez wszystkich klientów dla całkowitej przepustowości systemu. Jeśli chodzi o desynchronizację, nawet procesy na tym samym fizycznym urządzeniu nie są zsynchronizowane, dopóki komunikat o stanie nie zostanie utworzony i wysłany, to tylko kwestia miejsca opróżnienia potoku, lokalnej pamięci RAM lub sieci.
Patrick Hughes
5

Użyj filtrowania obszaru zainteresowania. Jeśli świat jest podzielony na 3 serwery, a obszar na serwerze 1 nie znajduje się w pobliżu obszaru serwera 3, nie ma powodu, aby dzielili się informacjami o bytach.

Podobnie, na jednym serwerze, wysyłaj tylko odpowiednie informacje do klientów. Jeśli gracz A znajduje się na przeciwległym końcu mapy od gracza B, nie ma powodu, aby przesyłać informacje o B do A lub odwrotnie.

Gdy masz wiele serwerów w ciągłym świecie, będziesz mieć jednostki blisko krawędzi na serwerze 2, które są blisko jednostek na serwerze 1. Możesz wysyłać aktualizacje z serwera „autorytatywnego” dla jednostki na inny serwer (w razie potrzeby) , a także odpowiednio przekazywać wszelkie wiadomości do wiarygodnego serwera.

Tak, w takim przypadku jeden serwer będzie nieco nieaktualny dla poszczególnych podmiotów. Nie próbuj tego rozwiązywać. Licz sie z tym. Załóżmy, że podmioty mogą być nieco nieaktualne. Wykonuj dowolną logikę, która wymaga aktualnych informacji tylko na serwerze, który jest autorytatywnym właścicielem jednostek. Kiedy jednostka wpływa na inną, wyślij wiadomość i załóż, że może potrwać wiele tyknięć logiki gry, zanim zostanie przetworzona i twój widok się zaktualizuje.

Taka konstrukcja znacznie ułatwia wątkowanie pojedynczego serwera. Żaden podmiot nie powinien bezpośrednio modyfikować innego, tylko wysyłać wiadomości, a lokalne pamięci podręczne proxy na serwer / wątek powinny być nieco nieaktualne.

Na przykład, jeśli jednostka A atakuje jednostkę B, nie sprawdzaj żywotności B, a następnie wyślij wiadomość o śmierci, jeśli osiągnie 0. Po prostu wyślij wiadomość „uszkodzoną”, pozwól, aby serwer autorytatywny dla B zajął się nią, a następnie dowolną komunikat „byt umarł” wysłany później przez serwer B, jeśli bytu A to obchodzi.

To samo dotyczy każdej dużej, skalowalnej aplikacji innej niż gry. Centralna baza danych nie jest magiczną technologią natychmiastowego udostępniania. Dwa serwery muszą komunikować się z komunikatami, asynchronicznie, partiami, aby zachować wysoką przepustowość. Stąd popularność technologii takich jak AMPQ i tym podobne. Bazy danych służą do przechowywania i wsparcia synchronizacji z konieczności, umożliwiając ich wykorzystanie do komunikacji, a nie dlatego, że same są przeznaczone do synchronizacji lub komunikacji.

Sean Middleditch
źródło
Dzięki, to zakończyło większość moich pozostałych wątpliwości. Pomyślałeś też o oddzieleniu serwerów od graczy, a nie od obszarów - wyglądałoby to płynniej. Każdy serwer obsługuje x graczy. Naprawdę to lubię! Czy to jest używane? Jest też jeszcze jedna rzecz. Jak zadałem powyżej, właśnie dowiedziałem się o nowej bazie danych NoSQL, Couchbase. Ma to być jak CouchDB, z wyjątkiem bardzo szybkich prędkości zapisu / odczytu: do 200 000 aktualizacji na sekundę! Może to może faktycznie działać jako „wspólny model świata w czasie rzeczywistym”, czy jeszcze nie?
MaiaVictor,
Nie mam pojęcia, czy ta technika jest używana na wolności, poza zwykłym gruboziarnistym „dzieleniem” serwerów. Robienie tego przez graczy i obszar geograficzny oznacza, że ​​każdy serwer może być świadomy bardzo dużej liczby podmiotów w różnych zestawach obszarów, zwiększając obciążenie serwera i znacznie zwiększając komunikację między serwerami. Robienie tego według obszaru oznacza, że ​​Twój serwer może być przeciążony w zatłoczonych obszarach (choć w tym przypadku możesz dynamicznie dzielić i łączyć obszary), ale oznacza to, że każdy serwer ma mniejszy zestaw odpowiednich bytów innych graczy i geometrię do śledzenia .
Sean Middleditch,
@Dokkat: Możliwe, że mogą istnieć jakieś „miękkie obszary”, w których każdy serwer obsługuje głównie graczy w określonej części świata gry, ale przekazuje graczowi przezroczysty serwer na inny serwer, jeśli zbyt daleko od niego odejdą region oryginalnego serwera. Musisz tylko upewnić się, że przekazanie jest wystarczająco płynne, aby gracze tak naprawdę tego nie zauważyli. Możesz nawet spróbować zastosować fantazyjne techniki adaptacyjne, aby utrzymać klastry interaktywnych graczy na tym samym serwerze, nawet jeśli znajdują się na granicy regionu.
Ilmari Karonen
3

Prawdopodobnie zainteresuje Cię ten artykuł o Gamasutrze , w którym programiści Eve Online omawiają, w jaki sposób można pomyślnie uruchomić grę z 400 000 aktywnych graczy ... w jednej bazie danych SQL.

Liosan
źródło
2

Nie myśl o bazie danych jako o jakimś modelu współdzielonego świata w czasie rzeczywistym przechowującym wszystko o wszystkim przez cały czas - jak zauważyłeś, to prawdopodobnie nie może działać.

Zamiast tego traktuj bazę danych bardziej jak automatycznie aktualizowany plik składowania: aktualizujesz bazę danych tylko od czasu do czasu, na przykład gdy gracze logują się, wylogowują lub przechodzą z jednej strefy do drugiej lub gdy dzieje się coś ważnego, czego nie chcesz utracone w przypadku awarii serwera.

Rzeczywisty stan świata w czasie rzeczywistym powinien być przechowywany przez serwery gry w pamięci, tak jak w twoim oryginalnym przykładzie. Teraz sztuczka skalowania poziomego polega na tym, że nie każdy serwer musi wiedzieć wszystko w każdej chwili . Na przykład, jeśli gracz A gra w strefie A na serwerze A, serwer B działa strefa B zazwyczaj nie trzeba wiedzieć, co gracz A ma w swoim plecaku - i, jeśli to nie muszą wiedzieć, że z jakiegoś powodu (powiedzmy, ponieważ gracz B w strefie B rzuca jakieś zaklęcie zdalnego szpiegowania na A), może po prostu poprosić inny serwer o te informacje .

Wymaga to przypisania jasnych obowiązków serwerom, aby serwer B chciał wiedzieć o plecaku gracza A, wiedziałby, który serwer ma na ten temat wiarygodne informacje. Prawdopodobnie będziesz chciał również włączyć mechanizm subskrypcji aktualizacji, aby np. Serwer B mógł po prostu powiedzieć serwerowi A „ Mam kogoś szpiegującego gracza A, informuj mnie o wszystkim, co robią, dopóki nie powiem inaczej. Prawdopodobnie będziesz chcą również uwzględnić jakiś globalny system transmisji ważnych wydarzeń globalnych, o których gracze mogą wiedzieć, bez względu na to, gdzie się znajdują; oczywiście takie zdarzenia powinny być również rejestrowane w bazie danych, ale ich aktywna transmisja na wszystkie serwery oznacza, że ​​serwery nie będą musiały dalej sondować bazy danych w poszukiwaniu aktualizacji.

Ilmari Karonen
źródło
Świetna odpowiedź! Właśnie o to prosiłem, dziękuję. Być może kluczem jest podzielenie serwera na obszary, zachowując logikę w pamięci. Może jednak dodam: Właśnie dowiedziałem się o nowej bazie danych NoSQL, Couchbase. Ma to być jak CouchDB, z wyjątkiem bardzo szybkich prędkości zapisu / odczytu: do 200 000 aktualizacji na sekundę! Może to może faktycznie działać jako „wspólny model świata w czasie rzeczywistym”, czy jeszcze nie?
MaiaVictor
@Dokkat nie, nie będzie. Kanapa nie jest magią.
Philipp
2

Inne odpowiedzi wykonały dobrą robotę, wskazując, jak korzystać z bazy danych, a nie z bazy danych do komunikacji. Innym aspektem, na który możesz zwrócić uwagę, jest kategoryzowanie aktualizacji na podstawie tego, w jaki sposób informacje muszą być przekazywane innym podmiotom. Zamiast zasięgać komunikacji z serwerami, możesz rozpowszechniać wiadomości i używać mechanizmów pubsub do komunikowania aktualizacji między jednostkami. Na przykład możesz traktować lokalizację inaczej w zależności od tego, kto jest blisko Ciebie:

  • Dokładna lokalizacja w czasie rzeczywistym może być przydatna w promieniu R.
  • Mniej precyzyjne, rzadziej aktualizowane aktualizacje lokalizacji mogą być przydatne w promieniu 2 * R
  • Informacje o lokalizacji mogą być niepotrzebne poza promieniem 2 * R

Możesz przekazać informacje o lokalizacji dla encji, okresowo skanując w poszukiwaniu encji w promieniu 2 * R (lub ich wielokrotności w oparciu o częstotliwość aktualizacji i maksymalną prędkość encji) i subskrybując encję na dokładnym lub nieprecyzyjnym kanale lokalizacji drugiej encji.

Możesz mieć różne strategie dla różnych rodzajów informacji, grupować wspólne rzeczy w te same kolejki wiadomości lub mieć różne kolejki dla wiadomości, które muszą przejść do różnych jednostek (lub po prostu wysłać je do najszerszego zestawu jednostek i odrzucać wiadomości, jeśli nie są przydatne).

David N.
źródło