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?
mmo
data-structure
databases
scalability
MaiaVictor
źródło
źródło
Odpowiedzi:
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.
źródło
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.
źródło
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.
źródło
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.
źródło
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:
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).
źródło