Verbesserungen bei der Ping-Berechnung

5.2.2019
Von Das Fortnite-Team
Hallo zusammen! Ich bin Bart Hawthorne, Senior Networking Engineer vom Engine-Team bei Epic, und ich möchte euch erklären, wie wir die Ping-Werte in Fortnite darstellen. Außerdem zeige ich euch die neue Methode aus Version 7.30 und erkläre, warum sie schiefging, und stelle euch unsere Zukunftspläne zur Verbesserung der Anzeigegenauigkeit vor.

Doch zuerst zu einigen Begriffen, die ich verwenden werde und die manche möglicherweise noch nicht kennen:

Client und Server: Jede Konsole, jedes mobile Gerät, jeder PC oder Mac ist ein Client, und Clients verbinden sich mit einem dafür vorgesehenen Server, der das jeweilige Spiel hostet. Der Server ist dafür da, das Spiel insgesamt zu erhalten, also Spielerorte, Lage des Sturms, welche Truhen aktiv sind und vieles mehr. Außerdem sorgt der Server dafür, dass alle Clients aktualisiert werden, wenn sich das Spiel in irgendeiner Form verändert hat.

Paket: Ein Paket ist ein Datenblock, der über das Netzwerk entweder vom Client zum Server oder umgekehrt geschickt wird. Auf diese Weise kommunizieren Clients und Server miteinander. Bei Fortnite (und UE4) nutzen wir diese Pakete in unserer Ping-Berechnungsmethode

Frame: Auf dem Server benennt ein Frame, wie schnell ebendieser Server in der Lage ist, all seine Aufgaben einmal durchzuführen. Dazu gehört die Suche nach neuen Paketen sowie Spiel- und Client-Updates. Auf dem Client bezeichnet ein Frame, wie oft ein Bild auf dem Bildschirm aktualisiert wird. Die Framerate, auch bekannt als FPS (Frames pro Sekunde), zeigt an, wie viele Frames auf dem Server oder Client in einer Sekunde verarbeitet werden. Wenn ein Client also mit 60 FPS läuft, bedeutet das: Jede Sekunde enthält 60 Frames.

Nun, da all das geklärt ist, kommen wir zum Ping!

Unsere alte Berechnungsmethode für Ping-Pakete

Als Ping bezeichnet man die Zeit, die ein Client braucht, um ein Paket an den Server zu schicken, bzw. eine Antwort vom Server zu erhalten oder umgekehrt. Dies nennt man auch Umlaufzeit (round-trip time) oder RTT. Sie liefert die Informationen, die die meisten Spieler interessiert, und zwar, wie lange es für sie dauert, Updates vom Server zu erhalten, bzw. umgekehrt. Je höher der Ping eines Spielers ist, desto wahrscheinlicher sieht er Spielelemente wie teleportierende Spieler, unerwartete Eliminierungen oder Verzögerungen bei der Interaktion mit Truhen oder anderen Objekten.

Wir zeigen den Ping in Millisekunden an, und je niedriger er ist, desto besser. Wer also zufällig genau neben einem Datenzentrum wohnt, das unsere Server hostet, könnte sogar einen einstelligen Ping haben! Wer allerdings auf einem Server spielt, der am anderen Ende der Welt steht, kann einen Ping von 100ms oder mehr haben.

Doch es gibt noch andere Faktoren als hin und her geschickte Pakete, die bei der Client-Server-Kommunikation eine Rolle spielen. Bei Fortnite suchen wir am Anfang jedes Frames auf Server und Client einmal nach neuen Paketen. Das heißt, dass es zu einer Verzögerung von bis zu einem vollen Frame kommen kann, wenn ein Paket ankommt und der Client oder Server genau dann nach einem Paket sucht, nachdem wir ebendas geprüft haben. Außerdem dauert es etwas, bis das Paket vollständig gelesen und der Spielstatus dementsprechend angepasst wurde.

Hier ist ein Diagramm, das die Sache veranschaulicht:


Die schwarzen Pfeile für Client und Server repräsentieren die Zeit. In diesem Beispiel laufen beide Server synchron und auf derselben Framerate. Die senkrechten, schwarzen Linien repräsentieren den Anfang jedes Frames, die blauen Zacken, wenn Server oder Client prüfen, ob Pakete vorhanden sind, und die orangefarbenen Linien zeigen, wann Client oder Server Pakete aussenden. Die lila gestrichelten Linien repräsentieren ein Paket, das gerade im Internet unterwegs ist.

Hier ist der Ablauf der Ereignisse:

  1. Der Client schickt ein Paket an den Server.
  2. Der Server erhält das vom Client geschickte Paket.
  3. Der Server sucht nach neuen Paketen – an dieser Stelle „sieht“ der Server das Paket vom Client. Nun wartet das Paket aber schon fast einen ganzen Frame, weil es genau in dem Moment ankam, als der Server gerade nach neuen Paketen gesucht hat.
  4. Der Server schickt seine Antwort zum Client, dass er das Paket erhalten hat.
  5. Die Antwort des Servers erreicht den Client.
  6. Der Client liest die Serverantwort.
Wir wollen nur die Umlaufzeit anzeigen – das sind die grünen Pfeile – und die Zeit, die die roten Pfeile repräsentieren, abziehen. Also tun wir unser Bestes – wenn wir ein Paket vom Server an den Client schicken, ist darin die Server-Framezeit enthalten. So können wir für ein bestimmtes Paket diesen Server und den Client von der Framezeit bis zu dem Punkt abziehen, an dem wir das Paket verarbeiten. Unsere Ping-Berechnung sieht wie folgt aus:
Ping = Paket-Übermittlungsdauer zum Server + Paket-Übermittlungsdauer zum Client - Server-Framezeit - bisherige Client-Framezeit

Für den angezeigten Wert mitteln wir diesen berechneten Wert von Paketen über mehrere Sekunden, um einen stabileren Wert zu ermitteln.

In der Praxis ist dies nur leider nicht so präzise, wie wir es gern hätten. Dabei wird nämlich die Zeit außer acht gelassen, die verstreicht, wenn Pakete eingetroffen sind, die noch auf Verarbeitung warten. Dadurch ist der angezeigte Ping oft zu hoch. Die Herausforderung dabei ist, dass die meisten Plattformen nicht kommunizieren, wann ein Paket tatsächlich eingetroffen ist, sodass wir schlicht nicht wissen, wie viel Zeit abgezogen werden muss.

Unsere Berechnungsmethode für Ping-Pakete in Version 7.30

Vor Version 7.30 hatten wir eine neue Idee, die wir ausprobieren wollten: Was, wenn wir nur die Pakete nutzen würden, die am wenigsten Zeit vom Client zum Server brauchen, und eine Antwort erhalten? Der Gedanke dahinter war, dass die Pakete, die am wenigsten Zeit brauchen, auch diejenigen sind, die sofort verarbeitet werden, sodass wir etwaige Wartezeiten ignorieren könnten, weil sie gen Null gehen würden. Also nutzten wir die schnellsten 25 % unserer Pakete für die Berechnung von Ping-Werten, weil uns die Balance aus den schnellsten Paketen, kombiniert mit genügend Daten für einen realistischen Wert, ausgeglichen erschien.

Was ging schief?

Nachdem Version 7.30 veröffentlicht worden war, gingen überdurchschnittlich viele Berichte von Spielern ein, deren Pings niedrig oder sogar 0 waren, obwohl sie höher hätten sein sollen. Wäre das wahr, würden wir Pakete mit Überlichtgeschwindigkeit verschicken, und so großartig UE4 auch ist, so gut ist sie nun auch wieder nicht! Es war also eindeutig irgendetwas schiefgelaufen.

Das Problem rührte aus unserer Ping-Berechnung. Hier ist sie noch einmal:
Ping = Paket-Übermittlungsdauer zum Server + Paket-Übermittlungsdauer zum Client - Server-Framezeit - bisherige Client-Framezeit

Das Problem ist die Subtraktion der Server-Framezeit. Wenn wir nämlich nur die schnellsten Pakete berücksichtigen, ziehen wir viel zu viel ab – wenn ein Paket gleich nach Eintreffen auf dem Server verarbeitet wird, braucht es nur einige Millisekunden, um eine Antwort zu schicken. Die gesamte Server-Framezeit könnte aber fünffach so lang sein!

Dieses Diagramm zeigt, wie das aussieht:



Dieser Client hat eine viel höhere Framerate als der Server. Wir schauen nur auf die grünen Pakete, die genau vor der Prüfung seitens des Servers eintreffen. In diesem Fall läuft der Server schneller als seine eingerastete Framerate, sodass er bei Framestart schläft (also eine Weile nichts tut), ehe er wieder nach Paketen sucht.
 



Die rote Linie repräsentiert, was wir als Server-Framezeit abziehen, doch korrekt wäre die orangefarbene Linie. Das ist eindeutig zu viel Zeit, weswegen einige Clients einen Ping von 0 anzeigten.
Mit unserer alten Methode berücksichtigten wir zwar eine größere Menge an Paketen, doch das Problem bleibt. Dennoch haben wir damit eine größere Chance, Pakete einzubeziehen, die länger auf Verarbeitung warten müssen, sodass diese die Pakete aufwiegen, die zu viel Zeit abziehen.

Zukunftspläne

Wir haben Ideen für zukünftige Veröffentlichungen, in denen wir den angezeigten Ping-Wert so akkurat wie möglich darstellen möchten. Wie ich vorhin schon sagte:

„Die Herausforderung ist, dass viele Plattformen nicht kommunizieren, wann ein Paket tatsächlich eingetroffen ist, sodass wir schlicht nicht wissen, wie viel Zeit abgezogen werden muss.“


Glücklicherweise ist das bei Linux anders! Da unsere Server exklusiv auf Linux laufen, steht es uns frei, die Ping-Berechnung wie folgt zu verändern:

Ping = Paket-Übermittlungsdauer zum Server + Paket-Übermittlungsdauer zum Client - Zeit zwischen Paketankunft und Senden einer Antwort - bisherige Client-Framezeit.


Damit entfällt die Mutmaßung durch Abziehen der Server-Framezeit. Wir gehen davon aus, dass dies deutlich präzisere Werte liefern wird, aber haben noch eine Menge Tests vor uns.

Außerdem untersuchen wir, wie und ob wir den Client dazu bringen können, öfter nach Paketen zu suchen, damit wir die Variable „bisherige Client-Framezeit“ auslassen können.

Diese beiden Veränderungen werden uns hoffentlich mit einem präziseren Ping-Wert versorgen.

Schlussfolgerung

Ich hoffe, diese Erklärung war hilfreich, und ihr versteht nun, wie wir Pings ermitteln und wie wir diese Berechnungen in Zukunft verbessern wollen. Wenn wir Informationen wie diese anzeigen, ist es extrem wichtig, dass sie stimmen – falsche Werte können schlimmer sein als gar keine. Schließlich ist es wichtig zu wissen, dass es am Ping liegt, wenn man einen Schuss verfehlt oder das Spiel „laggt“, denn nur so kann man Vorkehrungen treffen, dass es nicht wieder passiert.

Falls ihr weitere Fragen habt – ich schaue mir regelmäßig die Kommentare an und beantworte gern, was ich kann. Danke fürs Lesen!