smaller update + bibliography
This commit is contained in:
+19
-14
@@ -104,7 +104,7 @@
|
||||
|
||||
%% Anotace práce, včetně anglické (obvykle překlad z jazyka
|
||||
%% práce). Jeden odstavec!
|
||||
\annotation{V diplomová práci se budeme zabývat optimalizacemi datového přenosu v distribuovaných systémech. Konkrétně se zaměřuje na systémy pro hry více hráčů. Analyzovali jsme jejich problematiku a specifika, které popíšeme. Následně představíme optimalizace, které jsme implementovali. Mezi hlavní části patří náš vlastní protokol transportní vrstvy. Mimo jiné v práci popisujeme vývoj našeho vlastního herního enginu, do kterého právě různé techniky a optimalizace implementujeme.}
|
||||
\annotation{V diplomové práci se zabýváme optimalizacemi datového přenosu v distribuovaných systémech. Konkrétně se zaměřujeme na systémy pro hry více hráčů. Analyzujeme a popisujeme jejich problematiku a specifika. Následně představujeme optimalizace, které jsme implementovali. Mezi hlavní části patří náš vlastní protokol transportní vrstvy a vývoj našeho vlastního herního enginu pro implementaci hry pro více hráčů.}
|
||||
|
||||
\annotation[english]{Sample text of thesis at the \kitextdepten,
|
||||
\kitextfacultyen, \kitextuniven{} and, at the same time,
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
%% Volitelné poděkování. Stručné! Výchozí je prázdné. Makro nemá
|
||||
%% nepovinný parametr pro uvedení jazyka.
|
||||
\thanks{Děkuji, děkuji, děkuji.}
|
||||
\thanks{Děkuji vedoucímu této práce Mgr. Tomáši Urbancovi, Ph.D. za spolupráci, ochotu a čas, který mi věnoval při konzultacích. Dále bych rád poděkoval rodině a přátelům za podporu a motivaci.}
|
||||
|
||||
%% Cesta k souboru s bibliografií pro její sazbu pomocí BibLaTeXu
|
||||
%% (zvolenou nepovinným parametrem biblatex makra
|
||||
@@ -164,9 +164,9 @@ Dalším typem jsou masivní multiplayerové online hry, tzv. MMO, které zvlád
|
||||
|
||||
V práci se zaměřujeme právě na metody optimalizace datového přenosu v síťových systémech pro hry více hráčů. Charakteristiky jsme analyzovali a implementovali různá řešení. Na konci představíme naše testovací scénáře pro měření optimality těchto technik. Zároveň popíšeme, jaké nástroje jsme k měření použili a jak.
|
||||
|
||||
Nejprve v další kapitole popíšeme distribuované systémy obecně: jak probíhá komunikace mezi dvěma procesy na dvou různých počítačích. Tyto procesy budeme skládat do distribuovaného systému. Uvedeme různé modely a atributy, které může komunikace nebo distribovaný systém mít.
|
||||
Nejprve v další kapitole popíšeme distribuované systémy obecně: jak probíhá komunikace mezi dvěma procesy na dvou různých počítačích. Tyto procesy budeme skládat do distribuovaného systému. Uvedeme různé modely a atributy, které může komunikace nebo distribuovaný systém mít.
|
||||
|
||||
V následujících kapitolách popisujeme samotnou hru. Představíme náš vlastní herní engine, který vytvořili. Engine je navrhžen jako modulární monolit. Zároveň s ním budeme popisovat architekturu samotné hry. Začneme hrou pro jednoho hráče a návrh rozšíříme o hru více hráčů tak, aby byl přehledný a snadno se s kódem pracovalo.
|
||||
V následujících kapitolách popisujeme samotnou hru. Představíme náš vlastní herní engine, který jsme vytvořili. Engine je navržen jako modulární monolit. Zároveň s ním budeme popisovat architekturu samotné hry. Začneme hrou pro jednoho hráče a návrh rozšíříme o hru více hráčů tak, aby byl přehledný a snadno se s kódem pracovalo.
|
||||
|
||||
Pro demonstraci různých technik jsme vytvořili hru. Jedná se o jednoduchou hru ve 3D prostoru, kde každý hráč má svou postavu, se kterou může pohybovat. Tu stavíme na vlastním herním enginu tak, abychom různé algoritmy měli pod kontrolou. Například jsme vytvořili vlastní protokol pro obousměrné posílání spolehlivých i nespolehlivých zpráv zvaný QUICr. Celý engine jsme navrhovali jako modulární monolit a snažíme se organizovat jednotlivé řešení problémů do modulů. Díky tomu je návrh intuitivní a snadno rozšiřitelný.
|
||||
|
||||
@@ -212,7 +212,7 @@ V poslední kapitole představíme měření, které jsme provedli a jejich výs
|
||||
|
||||
\section{Distribuované systémy}
|
||||
|
||||
V této kapitole představíme distribuované systémy. Nejprve si zadefinujeme, co distribuovaný systém je. Podíváme se, čím jsou specifické a jaké vlastnosti mohou mít. Následně se podíváme hlouběji jak takové systémy fungují. Distribuované systémy jsou často složité, proto představíme různé architektonické vzory, které i později při implementaci vlastního distribuovaného systému využijeme.
|
||||
V této kapitole představíme distribuované systémy. Nejprve si zadefinujeme, co distribuovaný systém je. Podíváme se, čím jsou specifické a jaké vlastnosti mohou mít. Následně se podíváme hlouběji jak takové systémy fungují. Distribuované systémy jsou často složité, proto představíme různé architektonické vzory, které i později při implementaci vlastního distribuovaného systému využijeme. Ty pomáhají s udržitelností systému.
|
||||
|
||||
Začneme pojmem, co je vlastně počítačový systém. Ten se skládá ze služeb, každá implementovaná jako kolekce procesů, které dohromady plní společný úkol. Moderní systémy jsou ale čím dál větší a úkoly, které musí plnit, jsou složitější. To vedlo ke vzniku síťových systémů, ve kterých jsou procesy rozmístěné přes více počítačů a komunikují spolu posíláním zpráv. Výhod je hned několik. Část systému může být umístěna na počítači blíž uživateli pro snížení odezvy. Když jeden proces selže, může být jiný, který plní stejnou službu a může systém udržet v provozu. Konkrétní skupinou jsou distribuované systémy, které mají mnoho procesů rozmístěných přes více počítačů, které aktivně spolupracují a jeví se jako jeden celek.
|
||||
|
||||
@@ -232,7 +232,7 @@ Dva počítače, přímo propojené fyzickým médiem, komunikují posíláním
|
||||
% az tady říkáme, že síťový systém nemá sdílenou pamět???
|
||||
V této části popíšeme, jak samotná komunikace posíláním zpráv funguje. Představíme, jaké nástroje a vzory používáme. Konkrétně nás bude zajímat, jak můžeme komunikaci co nejvíce skrýt. Dále zmíníme vlastnosti, které může komunikace mít.
|
||||
|
||||
Ke skrytí komunikace v distribuovaných systémech používáme komponenty, kterým se říká \uv{middleware}. Ty leží mezi aplikací a operačním systémem a poskytuje komunikační služby. Není závislá na žádné konkrétní aplikaci. Příkladem je distribuovaná služba DNS, která podle doménového jména vyhledá síťovou adresu, jako například adrese \texttt{www.seznam.cz} přiřadí síťovou IP adresu \texttt{77.75.77.222}.
|
||||
Ke skrytí komunikace v distribuovaných systémech používáme komponenty, kterým se říká \uv{middleware}. Ty leží mezi aplikací a operačním systémem a poskytuje komunikační služby. Není závislá na žádné konkrétní aplikaci. Příkladem je distribuovaná služba DNS, která podle doménového jména vyhledá síťovou adresu, jako například adrese \texttt{www.seznam.cz} přiřadila dne 3. sprna 2026 síťovou IP adresu \texttt{77.75.77.222}.
|
||||
|
||||
Komunikace může mít různé vlasnosti. Například email je typický příklad \uv{persistentní} komunikace. Po odeslání si persistentní middleware zprávu uloží do té doby, dokud ji příjemce nepřijme. To znamená, že proces příjemce nemusí běžět v době, kdy odesílatel odesílá. Na druhou stranu máme \uv{transientní} komunikaci, kdy zpráva je uložena jen po dobu, kdy běží proces odesílatele a příjemce. To znamená, že pokud příjemce není dostupný, zprávu nikdy nepřijme.
|
||||
|
||||
@@ -407,15 +407,15 @@ Zajímavou novinkou je HTTP/3, která je založena na protokolu QUIC, který je
|
||||
|
||||
\subsection{Protokoly v transportní vrstvě}
|
||||
|
||||
Protokoly transportní vrstvy poskytují end-to-end komunikační služby pro aplikace. Příkladem takových služeb může být komunikace s navázáním spojení, spolehlivost doručení, zamezení zahlcení sítě nebo multiplexing.
|
||||
Protokoly transportní vrstvy poskytují end-to-end komunikační služby pro aplikace. Služba může mít různé vlastnosti, jako komunikace s navázáním spojení, spolehlivost doručení, zamezení zahlcení sítě nebo multiplexing.
|
||||
|
||||
Nejčastějším protokolem je TCP, který naváže spojení a zaručuje spolehlivé doručení dat jako proud bytů. Alternativou je UDP, které nezaručuje doručení, ale je vhodnější pro streamovací služby. Poslední příklad, který zmíníme, je protokol QUIC od Google, který poskytuje spolehlivou komunikaci přes navázané spojení a s podporou multiplexování. Byl důležitou inspirací pro náš vlastní protokol z praktické části.
|
||||
Nejčastějším protokolem je TCP, který naváže spojení a zaručuje spolehlivé doručení dat jako proud bytů. Alternativou je UDP, které nezaručuje doručení, ale je vhodnější pro streamovací služby, které to neomezuje. Poslední příklad, který zmíníme, je protokol QUIC od Google, který poskytuje spolehlivou komunikaci přes navázané spojení a s podporou multiplexování. Byl důležitou inspirací pro náš vlastní protokol z praktické části.
|
||||
|
||||
\subsubsection{TCP}
|
||||
|
||||
Nejběžnější protokol je TCP. Při použití mezi sebou dva koncové body vytvoří spojení s obousměrným proudem bytů. Protokol garantuje spolehlivé doručení dat v pořadí, ve kterém byly odeslány. Zároveň řeší zahlcení sítě udržováním okna paketů, které jsou v oběhu a redukuje jeho velikost v případě, že je síť přehlcená. To pozná tak, že si pakety čísluje a příjemce musí za každý odeslat potvrzení přijetí. Pokud odesílatel toto potvrzení nedostane, odešle paket znovu. Pokud nedostává potvrzení pro až moc velkou část okna, může toto okno zmenšit.
|
||||
Nejběžnější protokol je TCP. Při použití mezi sebou dva koncové body vytvoří spojení s obousměrným proudem bytů. Protokol garantuje spolehlivé doručení dat v pořadí, ve kterém byly odeslány. Zároveň řeší zahlcení sítě udržováním okna paketů, které jsou v oběhu a redukuje jeho velikost v případě, že je síť přehlcená. To pozná tak, že si pakety čísluje a příjemce musí za každý odeslat potvrzení, že paket přijal. Pokud odesílatel toto potvrzení do časového limitu od odeslání nedostane, odešle paket znovu. Pokud nedostává potvrzení pro až moc velkou část okna, může toto okno zmenšit. Tím sníží i zatížení sítě.
|
||||
|
||||
Pro navázání spojení a následnou komunikaci musejí oba procesy vytvořit koncový bod, kterému se říká \uv{soket}. Jedná se o objekt, který se chová jako soubor. Odesílatel do něj zapisuje data, která chce odeslat a příjemce je z něj může přečíst. Na jednom počítači může být otevřeno více soketů a jsou identifikované \uv{portem}. Ten slouží pro směrování paketů správnému soketu, ze kterého příjemce čte. Pro navázání musí jedna strana spojení iniciovat a druhá ho musí přijmout.
|
||||
Pro navázání spojení a následnou komunikaci musejí oba procesy vytvořit koncový bod. Velmi často používané rozhraní je přes \uv{soket}. Jedná se o objekt, který se chová jako soubor. Odesílatel do něj zapisuje data, která chce odeslat a příjemce je z něj může přečíst. Na jednom počítači může být otevřeno více soketů a jsou identifikované \uv{portem}. Ten slouží pro směrování paketů správnému soketu, ze kterého příjemce čte. Pro navázání musí jedna strana spojení iniciovat a druhá ho musí přijmout.
|
||||
|
||||
Popíšeme si, jak TCP zajišťuje spolehlivost pomocí odesílání potvrzení o přijetí. Pokaždé, co příjemce dostane paket, odešle druhému koncovému bodu zprávu označenou jako \uv{ACK} s číslem paketu. V případě, že odesílatel potvrzení o přijetí nedostane, odešle paket znova. Příjemce si u sebe postupně skládá seřazený proud bytů. Jakmile je na socketu seřazená posloupnost bytů, umožní ji ze soketu přečíst.
|
||||
|
||||
@@ -602,6 +602,8 @@ Pro hru jsme vyvinuli vlastní herní engine tak, abychom mohli celý systém do
|
||||
|
||||
Mezi hlavní komponenty patří \uv{stav} hry a \uv{řídící logika}. Stav obsahuje množinu entit, které jsou ve hře a jejich vlasnosti a atributy. Entity jsou objekty v herním světě, jako postava hráče, nepřátele nebo interaktivní prvky jako truhla s pokladem. Entita má přiřazené vlastnosti, které ji dávají stav. Entita nepřítele může mít vlastnost "množství životů" a truhla vlastnost "poklad", která definuje, co je v truhle obsaženo. Stavu hry se někdy říká pouze \uv{svět}.
|
||||
|
||||
|
||||
|
||||
% Detaily k implementaci, ale stále dost abstrahované.
|
||||
% Zmínit svět, ve kterém držíme stav hry. Zmínit derivaci (proces sbírání vstupů, prozatím jen od hráče). Zmínit integraci jako aplikaci derivace na stav.
|
||||
|
||||
@@ -642,7 +644,6 @@ V programu využíváme architekturu entity-component-system, zkráceně ECS, kt
|
||||
|
||||
Motivací této architektury je jednoduché skládání různých entit, které jsou pro rozmanité herní světy typické. Pomocí stromu dědičnosti bychom tyto různé scénáře hůře skládali. Další výhoda je zlepšení výkonu. Protože si engine může poskládat entity a jejich komponenty do paměti jak chce, může umístění optimalizovat pro definované systémy tak, aby iterování bylo co nejrychlejší. Tomuto se říká problém lokality.
|
||||
|
||||
https://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
|
||||
|
||||
|
||||
|
||||
@@ -705,7 +706,7 @@ Jako první jsme implementovali model klient-server. Diagram systému vidíme na
|
||||
|
||||
Druhá varianta je model peer-to-peer. Ta je složitější z hlediska konzistence. Účastníci si mezi sebou posílají akce a každý si udržuje svůj stav, který ale nikomu nereplikuje. Každý se tak chová jako server v modelu klient-server. Je potřeba, aby každý účastník měl kompletní historii akcí všech ostatních v systému ve správném pořadí. Tomuto se říká \uv{event-sourcing}. V případě, že se historie liší, dochází k nekonzistenci.
|
||||
|
||||
Druhá komplikace peer-to-peer je, že výsledek každé aplikace akce být všude stejný. Problém nastává u generování pseudo-náhodných čísel nebo u integrace. Například fyzický engine postupně integruje pozice entit podle derivace, která je reprezentována vektorem zrychlení. Každá integrace musí definovat, o jak velký časový krok se jedná (tzv. delta-time) a všichni účastníci se na něm musejí shodnout. Různé délky by rychle způsobily desynchronizaci. Zároveň všechny pseudonáhodné generátory musejí mít stejný počáteční seed. Je třeba si dát pozor na aritmetriku s plovoucí desetinou čárkou, která na různých platformách může dopadnout trochu jinak. I malé rozdíly se mohou rychle projevit.
|
||||
Druhá komplikace peer-to-peer je, že aplikace stejné akce na stejný stav musí mít vždy stejný výsledek. Pokud by dva procesy ve stejném stavu po aplikaci stejné akce na stav dospěli do jiného stavu, dochází k desynchronizaci. Problémové oblasti jsou generování pseudo-náhodných čísel a integrace. Výsledek integrace je často závislý na frekvenci. Například fyzický engine postupně integruje pozice entit podle derivace, která je reprezentována vektorem zrychlení. Každá integrace musí definovat, o jak velký časový krok se jedná (tzv. delta-time) a všichni účastníci se na něm musejí shodnout. Různé délky by rychle způsobily desynchronizaci. Zároveň všechny pseudonáhodné generátory musejí mít stejný počáteční seed. Je třeba si dát pozor na aritmetriku s plovoucí desetinou čárkou, která na různých platformách může dopadnout trochu jinak. I malé rozdíly se mohou rychle projevit.
|
||||
|
||||
Rozšířenou architekturu vidíme na obrázku \ref{fig:multi_player_game}. Hned si všimneme, že se svět rozdvojil na instanci na serveru a instanci na klientovi. Jsou to právě tyto dvě instance, které se snažíme posíláním zpráv synchronizovat. Řídící logiku jsme rozdělili na Server World Controller a Client World Controller. Všimněme si, že ovladač na klientovi ne nutně obsahuje systémy, které by měnili stav hry, ale pouze kopíruje to, co mu server poslal ve zprávě pro snapshot. Na druhou stranu posílá akce, které přečetl od hráče. Oba ovladače ale zapisují do své instance světa.
|
||||
|
||||
@@ -740,7 +741,7 @@ Komponenta, která se snaží synchronizovat stav klientů s lokálním stavem n
|
||||
|
||||
\subsubsection{Správa zájmů}
|
||||
|
||||
Komponenta, která řeší důležitost entit pro jednotlivé hráče, je \uv{manažer zájmu}. Důležitost definujeme pro každou dvojici klienta a entity. Manažer zájmu podle definované logiky, například na základě vzdálenosti, určí důležitost entity pro klienta. V základní verzi jsme měli pouze dvě hodnoty: důležitá, takže je nutné ji synchronizovat, a nedůležitá, která není. Replikátor se dotazuje manažera zájmu v moment, kdy klientovi chce stav synchronizovat.
|
||||
Komponenta, která řeší důležitost entit pro jednotlivé hráče, je \uv{manažer zájmu}. Důležitost definujeme pro každou dvojici klienta a entity. Manažer zájmu podle definované logiky, například na základě vzdálenosti, určí důležitost entity pro klienta. V základní verzi jsme měli pouze dvě hodnoty: důležitá a nedůležitá. Synchronizovali jsme pouze důležité. Replikátor se dotazuje manažera zájmu v moment, kdy klientovi chce stav synchronizovat.
|
||||
|
||||
Dotazu na všechny body, které jsou dostatečně blízko od konkrétního bodu, se říká `range-query`. Datové struktury které tuto operaci akcelerují jsou například fixní mřížka, dynamická mřížka nebo quad-tree.
|
||||
|
||||
@@ -758,7 +759,11 @@ Abychom oddělili to, jak replikátor funguje, vytvořili jsme pro něj na stran
|
||||
|
||||
\subsubsection{Interpolace}
|
||||
|
||||
Když jsme začali systém měřit, zjistili jsme, že vysoká frekvence replikace až příliš zatěžuje síť. Graf s průměry pro počet hráčů vidíme na grafu. Snížili jsme proto frekvenci na 20Hz. To snížilo zátěž na třetinu. Problém ale najednou byl neplynulost hry. Klient sice vykresloval s frekvencí 60Hz, ale méně časté aktualizace způsobili neplynulý pohyb. Řešení je na klientovi interpolovat spojité proměnné, jako pozice nebo rotace. Do klienta replikátoru jsme přidali komponentu \uv{interpolátor}. Ta si ukládá historii konkrétních hodnot a jejich časovou známkou do bufferu. Hodnota, kterou nastaví, je pak interpolovaná z bufferu fixní čas zpět\cite{interpolation}.
|
||||
Když jsme začali systém měřit, zjistili jsme, že vysoká frekvence replikace až příliš zatěžuje síť. Graf s průměry pro počet hráčů vidíme na grafu. Snížili jsme proto frekvenci na 20Hz. To snížilo zátěž na třetinu. Hra potom nebyla plynulá. Klient vykresloval s frekvencí 60Hz, ale aktualizace pozice s frekvencí 20Hz způsobily neplynulý pohyb. Řešení je na klientovi interpolovat spojité proměnné, jako pozice nebo rotace.
|
||||
|
||||
Vytvořili jsme novou komponentu \uv{interpolátor}. Ta umožňuje zapsat pozici entity v konkrétní čas. Komponenta si udržuje časovou osu stavu pozice. Zároveň umožňuje číst pozici entity pro konkrétní čas. Pokud je vybraný čas na ose mezi dvěma body, tak vrátí mezi nimi interpolovanou pozici. Pokud je vybraný čas až po posledním známém bodě na ose, tak vrací poslední známou hodnotu.
|
||||
|
||||
Změnili jsme objekt, do kterého klient replikátoru zapisuje pozice entit na právě objekt interpolátoru. Do něj zapisuje původní sníženou frekvencí 20Hz. Řídící logika ale může z interpolátoru číst s vyšší frekvencí, například 60Hz. Aby čtecí funkce interpolátoru měla mezi čím interpolovat, není vhodné číst hned nejnovější hodnoty. Lepší je počkat, a interpolovat pozici určitý čas zpět. To má za následek zvýšení odezvy mezi vstupem od hráče a fyzickým posunem postavy hráče. Klient nejprve čeká na odpověď serveru a poté čeká ještě o jednu odpověď navíc. To není problém, pokud takto interpolujeme postavu, kterou neovládá přímo hráč. Rozdíl odezvy pár set milisekund bude zanedbatelný.
|
||||
|
||||
\subsubsection{Rollback}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user