Jak mmorpg przechowuje dane?

22

Chcę użyć bazy danych SQL w moim server.exe.

powiedzmy 1000 użytkowników online. Gracze zmienią swoje dane podczas gry. I serwer musi zapisać te aktualizacje.

Ale jak ?

myślę tam na dwa sposoby:

1) serwer zapisze w pamięci RAM w czasie wykonywania i czasami lub co godzinę serwer zapisze dane (aktualizacje) do bazy danych SQL z pamięci RAM. Ale jeśli nastąpi przerwa w dostawie prądu lub serwer się wyłączy, aktualizacje nie zostaną zapisane. oczywiście nie chcę tracić aktualizacji.

2) serwer zapisze aktualizacje w bazie danych w czasie wykonywania. ale co stanie się z prędkością? Myślałem o metodzie. pokażę Ci poniżej obraz. Czy za pomocą tej metody mogę uzyskać wystarczającą prędkość dla 1000 graczy online? wprowadź opis zdjęcia tutaj

Emre Kaya
źródło
11
Czy zrobiłeś jakieś testy? Co sprawia, że ​​uważasz, że operacje na bazie danych byłyby problemem dla Twojej gry?
congusbongus
3
Jeśli Twój stan gry jest rzeczywiście relacyjny? Czy na pewno chcesz bazę danych SQL?
Stop Harming Monica
6
Przeczytaj także, jak obsługiwać hasła przy użyciu skrótów. Lub przynajmniej powiadom użytkownika, że ​​jego hasło jest zapisywane jako zwykły tekst, więc są świadomi, że nie używają innego bezpiecznego hasła.
TomTsagk
24
Na marginesie, jeśli chcesz zbudować komercyjną grę MMO i zadajesz takie pytania, prawdopodobnie powinieneś zacząć od czegoś mniejszego. MMO są niewiarygodnie trudne, nie mówiąc już o robieniu ich właściwie, i nie są tak świetne z biznesowego punktu widzenia. Jeśli jest to tylko sprawa osobista i chcesz zdobyć dużą liczbę graczy, zacznij od czegoś takiego jak 64 graczy, a następnie przejdź dalej. Będzie to o wiele łatwiejsze niż próba zaprojektowania „idealnej” architektury od zera bez doświadczenia. Zobacz to .
Pozew funduszu Moniki
1
Możesz napisać ogólny interfejs API, który jest niezależny od pamięci. Następnie napisz adapter, który buforuje dane w pamięci RAM w celu opóźnionego przechowywania. Możesz też napisać adapter, który buforuje dane w pliku tymczasowym przed opróżnieniem go w SQL DB. W ten sposób możesz włączać i wyłączać buforowanie, aby dowiedzieć się, który jest najlepszy. Nie musisz pisać zbyt dużego kodu, jeśli twoja architektura jest poprawnie zbudowana.
0xC0DEGURU

Odpowiedzi:

37

Większość MMO (lub projektów wykorzystujących podobną architekturę), nad którymi pracowałem lub wiem o użyciu pierwszej metody: serwery gier działają głównie z pamięcią RAM na komputerach z procesami serwerowymi i tylko okresowo serializują odpowiednie dane gry do bazy danych SQL do archiwizacji (jeśli w ogóle jest używana).

Problemy, które zauważysz w związku z awarią zasilania, są prawidłowe, ale mniej prawdopodobne niż problemy, takie jak awarie procesu (niezawodność czasu działania jest ogólnie jedną z rzeczy, za które zapłacisz centrum danych). Ale nadal. Łagodzisz te problemy, na przykład dostrajając interwał zapisywania (więc awaria kosztuje najwyżej kilka minut postępu), rozprowadzając kolejki zapisywania na wielu komputerach, agresywnie określając ilość danych, które należy zapisać, i wdrażając zapis restartu kolejki.

Ogólnie mówiąc, używanie samego serwera SQL jako pamięci głównej będzie nieprzyjemnie wolne (i uciążliwe). Nie widzę wystarczająco dużo szczegółów w twojej propozycji, aby móc z całą pewnością stwierdzić, czy zadziałałoby tylko dla około 1000 graczy - prawdopodobnie byłoby dobrze. Ale nie wierzę, że można sprawić, by była agresywnie skalowalna.

Co więcej, to nie rozwiązuje problemu. Awaria zasilania podczas procesu składowania nadal spowoduje utratę lub uszkodzenie danych, chyba że wykonasz pracę w celu wdrożenia tego samego rodzaju kolejki składowania, którą można zrestartować (co nawet wtedy, gdy tylko poważnie zmniejsza prawdopodobieństwo katastrofalnej utraty danych, nie zapobiega temu) .

Poleciłbym ci pierwsze podejście.


źródło
10
Jeśli chodzi o „dostrajanie interwału zapisu”, ostatnia gra MMO, nad którą pracowałem, miała interwał zapisu w oparciu o liczbę aktywnych graczy. Wiedzieliśmy, że poradzi sobie z zapisywaniem danych X graczy na sekundę bez zauważalnego wąskiego gardła, więc po prostu zaoszczędziliśmy nieco mniej niż X graczy na sekundę na zasadzie rotacji. Zazwyczaj kończyło się to zapisaniem dla każdego gracza co około dwie minuty w pracowite dni, a może dwa razy na minutę w wolnym czasie.
Meanbits
4
„Restartable save queue” brzmi jak dziennik, zaimplementowany przez wiele systemów plików i silników baz danych?
grawity
6
Kwestie te nie są specyficzne dla gier MMO, a nawet gry wideo, w ogóle . Prawie każda istniejąca ORM zapewnia pewien mechanizm buforowania / przetwarzania wsadowego. Nie ma potrzeby wdrażania własnego rozwiązania.
BlueRaja - Danny Pflughoeft
3
Jeśli skończysz zapisywanie na dysku w określonych odstępach czasu, zaleciłbym zaprojektowanie systemu, w którym można natychmiast zapisać rzeczy, na wypadek, gdy ludzie dostaną rzadkie upuszczenie / śmierć / etc. W ten sposób, jeśli nastąpi awaria serwera lub coś takiego, ludzie, którzy osiągnęli coś dużego, nie będą zbyt zdenerwowani.
Jon
5
@Jon, a następnie napotykasz problem polegający na tym, że ludzie mogą powielać obiekty. Idealnie, zapisujesz cały stan gry okresowo jako pojedynczą transakcję. Gdy zaczniesz zapisywać fragmentarycznie, znajdziesz się w sytuacjach, w których awaria może spowodować niespójne dane; gracze, którzy mogą wywołać awarię na żądanie, a nawet przewidzieć, kiedy awaria może się zdarzyć, mogą to wykorzystać na swoją korzyść.
Mark
15

1000 graczy może, ale nie musi stanowić problemu. Zależy to od częstotliwości aktualizacji bazy danych. Istnieje jednak proste rozwiązanie: umieść bazę danych na własnym serwerze.


Rzuciłem okiem na to, jak działa system baz danych w grze, którą ludzie nazywają MMO-Lite - której nie ujawnię - ale mogę powiedzieć, że konsekwentnie ma ponad 1000 graczy, oto streszczenie:

  • Korzystają z baz danych „No-SQL” opartych na dokumentach, aby uzyskać informacje o prywatnych postaciach (ekwipunek, wyposażenie itp.).
  • Używają bardziej tradycyjnej relacyjnej bazy danych do rzadko aktualizowanych informacji o postaci publicznej (imię, osiągnięcia itp.) Oraz statystyk.

Korzystanie z bazy danych opartej na dokumentach okazuje się być dobrym pomysłem na wydajność w tym przypadku. Jest dobry do uzyskiwania dostępu do danych, nawet jeśli jest zły do ​​wykonywania połączeń i agregacji ... ale nie zrobią tego z danymi, które się tam znajdują.

Z drugiej strony, kiedy muszą zrobić coś takiego, jak zmienić obiekt innym obiektem dla wszystkich, potrzeba uruchomienia skryptu w tle, który przechodzi znak po znaku i aktualizuje je jeden po drugim, zajmuje to zauważalny czas.


Dane postaci istnieją zarówno na kliencie, jak i na serwerze, a system został zaprojektowany w taki sposób, aby synchronizować je, wykonując te same operacje po obu stronach.

Teraz, gdy gracz dokonuje transakcji z systemem - na przykład wymienia przedmiot na inny za pośrednictwem NPC lub podobnego - ma to następujące etapy:

  • Klienci sprawdzają, czy operacja jest poprawna
  • Klient wysyła operację do serwera (operacja asynchroniczna)
  • Klient aktualizuje swój model w pamięci RAM
  • Serwer sprawdza, czy operacja jest poprawna
  • Serwer aktualizuje swój model w pamięci RAM
  • Serwer aktualizuje bazę danych (operacja asynchroniczna)
  • Serwer informuje klienta, że ​​nastąpiła zmiana

Uwagi :

  • Aktualizacje bazy danych, mimo że asynchroniczne, są wykonywane od razu. Jeśli z jakiegokolwiek powodu serwer gry ulegnie awarii, nie zostanie wiele stracony.
  • Spadek wydajności nie jest wielkim problemem dzięki umieszczeniu baz danych na własnych serwerach.

Transakcje między graczami są obsługiwane w podobny sposób, z dodatkowymi zasadami, aby zapobiec oszustwom innych graczy, oraz dodatkową identyfikowalność w przypadku konieczności cofnięcia transakcji. Słyszałem, że istnieją specjalne dzienniki wszystkich transakcji, które są przechowywane przez pewien czas (aby rozwiązać problemy, gdy ktoś narzeka), nie wiem więcej o tym, jak ta część działa.


Czasami coś idzie nie tak, ma to dwa możliwe skutki:

  • Jeśli błąd wystąpi natychmiast, serwer poinformuje klienta, który cofnie operację (gracz widzi operację cofniętą).
  • Interfejs użytkownika mówi, że gracz ma przedmiot, ale serwer się nie zgadza. Jeśli użytkownik spróbuje go użyć, zapyta serwer i zakończy się niepowodzeniem, uniemożliwiając korzystanie z fałszywego obiektu. Fałszywy obiekt znika po ponownym załadowaniu ekwipunku, który jest wykorzystywany jako okazja do synchronizacji modelu.

W obu przypadkach klient jest świadomy błędu i zarejestruje go wraz ze wszystkim, co robił gracz. Logowanie po stronie klienta odbywa się cały czas. Następnie po wylogowaniu, jeśli wystąpił błąd, klient wysyła dzienniki na serwer.


Ta gra nie wykorzystuje tradycyjnego codziennego lub cotygodniowego przestoju konserwacyjnego, jaki ma większość gier MMORPG. Ta planowa konserwacja jest często używana do resetowania liczników, timerów, uruchamiania procedur bazy danych. Są również okazją do zamiany wersji serwera na aktualizację.

Theraot
źródło
Dzięki, ale co na przykład z ruchami graczy, jeśli gracz porusza się ze swojej aktualnej pozycji: x:10,y:10,z:10Do x:11,y:11,z:11, czy należy to natychmiast zapisać w bazie danych? co jeśli gracz będzie kontynuował bieg, oznacza to, że zapisujemy jego aktualną pozycję co 1 sekundę lub mniej, a jeśli są tysiące graczy, to miliony zapytań do DB co sekundę. Czy tak to działa?
dwix
2
Pozycja gracza powinna być zapisywana bardzo rzadko w bazie danych. Chcielibyśmy tego tylko przy specjalnych okazjach, takich jak otwieranie menu, rozpalanie ogniska, odpoczynek itp. W zależności od gry nawet nie zostaną zapisane tak szczegółowe informacje. Niektóre gry powodują, że zawsze odradzasz się w najbliższym mieście itp., Co oszczędziłoby kłopotów z zapisaniem pozycji. Ale to zmienia się w opinie.
Nico
1
@dwix w przypadku gry, o której mówię, pozycja gracza nie jest nawet zapisywana. Jeśli wylogujesz się i zaloguj lub serwer ulegnie awarii, odtwarzacz zostanie ponownie umieszczony w bezpiecznej znanej pozycji (edytuj: jest to prywatna instancja, jeśli chcesz, „house”, ale dla wszystkich taka sama). Jednak niektóre gry zachowują dokładną pozycję gracza, nawet podczas przypadkowego rozłączenia. Aby to zrobić, zwykle stosuje się rzadziej przechowywanie tych informacji. Niezależnie od tego nie robisz tego, co serwer czeka na bazie danych.
Theraot
1
@dwix, mówiąc o pozycji awatara, tak naprawdę nie dbasz o wartości historyczne, prawda? Cóż, jeśli baza danych ma wąską szyjkę, to ogranicz dane. Zamiast zapisywać poszczególne tiki serwera, przechowuj rzadziej. Oznacza to, że baza danych nie będzie miała najbardziej aktualnej wartości, ale nie wpłynie tak bardzo na wydajność. Tymczasem serwer nadal zachowuje wartość aktualizacji w pamięci RAM i właśnie z tym współpracuje. Dodatek: szczerze mówiąc, odradzałbym przechowywanie pozycji, ale niektóre gry to robią.
Theraot
1
@dwix patrz komentarz meanbits
Theraot
7

Oba podejścia są stosowane w MMORPG. Przechowywanie wszystkiego w pamięci i okresowe sprawdzanie kierowania go na dysk wydaje się być najpopularniejszą opcją, przynajmniej w przypadku starszych gier. Ma tę zaletę, że jest dość łatwa do wdrożenia i skalowania dość dobrze, ale zapewnienie niezawodności zależy wyłącznie od dewelopera. Bazy danych SQL zapewniają właściwości ACID, które ułatwiają niezawodność, ale ogólnie są bardziej skomplikowane w zakresie prawidłowej implementacji i mogą mieć problemy ze skalowaniem.

EVE Online jest przykładem MMO, w którym wszystko jest przechowywane w bazie danych SQL. Myślę, że osiągnął szczyt około 60 000 jednoczesnych użytkowników i przez lata musiał poświęcić serwerom bazy danych drogi sprzęt, aby nadążyć za obciążeniem. Jednak EVE przechowuje o wiele więcej danych na użytkownika niż większość MMORPG i ma o wiele częstsze i zróżnicowane transakcje. Właściwości ACID bazy danych pozwalają na utrzymanie całej ogromnej i skomplikowanej bazy danych w spójnym stanie.

Rozważmy na przykład przypadek, gdy ktoś daje przedmiot innemu graczowi. Baza danych EVE gwarantuje, że nawet w przypadku awarii lub awarii zasilania przedmiot trafi do ekwipunku tylko jednego gracza. Oznacza to, że transakcja w bazie danych, która usuwa przedmiot z ekwipunku jednego gracza i dodaje go do ekwipunku innego gracza, jest atomowa. Transakcja jest w pełni zakończona lub w ogóle się nie dzieje. Nie możesz skończyć w stanie, w którym przedmiot nie istnieje w ekwipunku żadnego z graczy ani w obu.

MMORPG, który przechowuje dane gracza w pamięci i okresowo kontroluje, musi sam zaimplementować tę atomowość. Jednym ze sposobów, aby to zrobić, byłby punkt kontrolny danych każdego gracza w tym samym czasie, zapewniając, że nowy punkt kontrolny jest w pełni przypisany do dysku, zanim zostanie uznany za najnowszy punkt kontrolny. Gra musiałaby również dopilnować, aby dane gracza nie mogły się zmienić podczas kontroli. Przy dużej liczbie aktywnych graczy wyzwanie staje się tym wszystkim bez powodowania opóźnienia wystarczająco długo, aby gracze to zauważyli.

Nie lekceważ, jak ważna jest spójność. Gdy rozwijasz swoją grę, będzie się ona często zawieszać. Nie musisz śledzić, dlaczego przedmioty znikają i / lub powielają się, nie wtedy, gdy problemem jest niezwiązany błąd, który powoduje awarię gry w złym momencie. Co więcej, gdy gra zostanie uruchomiona, zawiesi się znacznie bardziej, niż się spodziewasz. Twój serwer, który działał idealnie podczas testowania, nagle ujawni liczne błędy pod pełnym obciążeniem, a gracze robią rzeczy, których się nie spodziewałeś.

Zauważ, że większość MMORPG używa baz danych SQL do informacji związanych z kontem, nawet jeśli nie do rzeczywistych danych gry. Jeszcze ważniejsze niż utrzymanie stanu gry w spójnym stanie jest utrzymanie stanu fakturowania. Najgorszym przypadkiem uszkodzenia bazy danych gier jest konieczność przywracania bazy danych z codziennej kopii zapasowej. Najgorszym przypadkiem uszkodzenia bazy danych kont jest to, że bankrutujesz z powodu wszystkich obciążeń zwrotnych.

Do swojego projektu prawdopodobnie możesz pójść w obie strony. Posiadanie 1000 równoczesnych użytkowników prawdopodobnie nie przekroczy limitów, jakie może obecnie obsługiwać serwer SQL na zwykłym komputerze PC, ale wiele będzie zależeć od charakteru transakcji. Jeśli znasz SQL i projektowanie relacyjnych baz danych, może to działać dla Ciebie. Będziesz chciał zminimalizować transakcje w jak największym stopniu, dla czegoś takiego jak bieżące punkty życia gracza możesz chcieć tylko okresowo zapisywać je w bazie danych, ponieważ takie statystyki niekoniecznie muszą być spójne. (W grze PvP mogą jednak ...) W ogóle nie przechowują takich rzeczy jak HP potworów w bazie danych, w większości gier tylko dane dotyczące graczy są trwałe.

Z drugiej strony, jeśli nie jesteś kreatorem SQL, przechowywanie wszystkich danych w pamięci może być znacznie prostsze, aby zapewnić niezawodne działanie. Bazy danych SQL ułatwiają spójność i niezawodność, ale nie są automatyczne. Źle zaprojektowana baza danych może słabo działać i prowadzić do niespójności. Transakcje nie będą atomowe, chyba że je zrobisz. Jeśli nie użyjesz sparametryzowanych instrukcji religijnie, otworzysz się na ataki typu SQL injection.

Ross Ridge
źródło
0

Różne gry przechowują różne rzeczy na różne sposoby. Często firmy gier tworzą jakiś sposób, aby to zrobić, a większość ich gier używa tego samego. Oczywiście różne studia często używają różnych sposobów. SQL jest z pewnością używany w grach, np. CCP (EVE) ma (lub przynajmniej miał) sieć serwerów SQL, nie jestem pewien, jak teraz to robią. Inni używają tylko wielu plików.

Może zacznij od stworzenia agnostycznego „mechanizmu brokera danych” do obsługi różnych transakcji danych w grze? Ponieważ i tak właśnie testujesz, stwórz mechanizm, który pozwoli ci nie przejmować się zbytnio pamięcią masową z punktu widzenia samej gry. To znaczy, skoncentruj się na tym, jak z aplikacji hosta zamierzasz sobie z tym poradzić.

Osobiście uważam, że byłoby wielkim atutem, gdybyś mógł zmienić rzeczywisty sklep bez konieczności przepisywania gry i samego brokera. Po prostu przełącz się na inny moduł z tym samym interfejsem, z którym broker może rozmawiać.

Samo przechowywanie danych prawdopodobnie nie będzie stanowić problemu. Skuteczne przesyłanie danych do / z tego sklepu między hostem a wszystkimi klientami może być trudniejsze. Czy wysyłam cały zestaw danych odtwarzacza, czy też dzielę go na części, jaką ziarnistość wybieram na partycje itp. Który z nich jest bardziej zasobochłonny w jakiej sytuacji itp.

Jednym z formatów przesyłania danych może być XML. W ten sposób możesz łatwiej być dynamicznym w tym, jak możesz go podzielić. Jeden znak vs. wiele znaków lub jeden element vs. zbiór elementów itp. Możesz wtedy „przechowywać” XML jako XML (w SQL) i / lub zlecić SQLowi jego dystrybucję w bardziej transakcyjny sposób z XML, do jak chcesz, aby dane były faktycznie przechowywane.

Innym sposobem jest system binarny, który jest bardziej wydajny pod względem wysyłki, ale może wiązać się z większymi kosztami w innych sytuacjach.

Przy 1000 klientów możesz zacząć od łatwego przechowywania 10 MB na klienta i używać tylko 10 GB efektywnej pamięci RAM + dodać trochę systemowej administracyjnej pamięci RAM do zarządzania tymi danymi, powiedzmy kolejną GB lub dwie. Możesz zachować to w pamięci RAM na hoście już w strukturze danych, gotowe do użycia. I ładuj / zapisuj dynamicznie, w zależności od tego, kto jest online, na różnych częstotliwościach w zależności od aktywności itp.

Możesz nawet przechowywać informacje o każdym kliencie w osobnym pliku i tak dalej.

Obrabować
źródło
0

Trzymaj graczy * online * w pamięci RAM i wypychaj ich do bazy danych (SQLite? MySQL?), Gdy się wylogują. jeśli martwisz się opóźnieniem we / wy podczas wylogowywania, daj każdemu wylogowaniu swój własny wątek, nie rób tego w głównym wątku / grze (w rzeczywistości mam dedykowany wątek dla każdego gracza online, dzięki temu kod sieci jest o wiele łatwiejszy niż zastosowanie podejścia async network io)

hanshenrik
źródło