한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

Game-Lag-Whitepaper › L9 Spielprozess auf dem Server

Lock-Contention Lock contention

Ursachen-ID sp-lock · Hauptzuständig Server-Entwicklung (Entwicklungsteam)

In der interaktiven Fassung mit Grafiken und Experimenten öffnen →

Warten mehrere Threads auf denselben Lock, um auf dieselben Daten zuzugreifen, läuft trotz zusätzlicher Threads immer nur einer zur Zeit.

Warum Mehrere Threads greifen gleichzeitig auf gemeinsame Daten zu, etwa Auktionshaus oder Gildenbank → Folge Bis der Thread mit dem Lock fertig ist, warten alle anderen → Auf dem Bildschirm Nur bestimmte Funktionen langsam, im schlimmsten Fall verzögert sich der gesamte Tick

Symptome
Input-Lag, Freeze
Faktoren
Stillstand
Wer ist betroffen
Nur eine bestimmte Funktion, Ganzer Server
Wann
Bei großem Andrang
Zuständigkeit
Hauptzuständig Server-Entwicklung (Entwicklungsteam)
Aufgaben Entwicklungsteam
Locks feingranularer aufteilen, Arbeit innerhalb von Locks reduzieren, nachrichtenbasierte Architektur (für alle Daten einen zuständigen Thread festlegen, andere Threads schicken nur Anfragen per Nachricht).
Größenordnungen
Macht die Arbeit innerhalb des Locks 20 % der Gesamtarbeit aus, erreicht der Durchsatz egal mit wie vielen Threads höchstens das 5-Fache eines einzelnen Threads. Bei 40 % ist beim 2,5-Fachen Schluss.
Im Graphen
Steigt mit Spielerzahl und Last · Verarbeitungszeit der Anfragen, CPU und Kontextwechsel pro Thread
Wo nachsehen
Mit pidstat -w -t 1 die freiwilligen Kontextwechsel pro Thread prüfen (cswch/s: wie oft ein Thread anhält, um auf eine Ressource zu warten), mit bcc offcputime -p ermitteln, wo Threads außerhalb der CPU warten (Wartezeit pro Call-Stack). Bei .NET die Zahl der Lock-Contentions in dotnet-counters (ab .NET 9 dotnet.monitor.lock_contentions, bis 8 Monitor Lock Contention Count)
Spricht dafür
Mit steigender Last bleibt die CPU-Auslastung niedrig, die Verarbeitungszeit wächst aber, der Großteil der Wartezeit entfällt auf Call-Stacks, die einen Lock anfordern, und die Zahl der Lock-Contentions steigt mit
Spricht dagegen
CPU voll ausgelastet: Problem der Rechenlast (überschrittenes Tick-Budget, überlastetes Gebiet auf einem einzelnen Thread). Gewartet wird auf DB- oder Dateiaufrufe: eher synchrone Aufrufe im Game-Thread
Prüfmittel
Mit Infrastruktur-Tools prüfbar (ohne Spielcode)
Mehr dazu
Das tritt in Architekturen auf, in denen mehrere Threads gemeinsam Spieldaten ändern. Ist für jedes Gebiet und jede Funktion ein einzelner Thread zuständig und läuft der Austausch nur über Nachrichten, gibt es kaum Locks. Dafür muss man darauf achten, dass sich die Arbeit nicht auf einem Thread ballt (überlastetes Gebiet auf einem einzelnen Thread). Wartet der Game-Thread auf einen Lock, den ein langsamer Speichervorgang hält, steht der ganze Tick still.
Reale Fälle
Roblox 2021: Roblox, 73-stündiger Ausfall: Contention im Service-Discovery-Cluster (Consul)

Quellen

  1. Amdahl's Law in the Multicore Era IEEE
    Artikel in IEEE Computer 2008 (Autorenfassung). Ist der nicht parallelisierbare Anteil 1−f, kann der Speedup egal mit wie vielen Kernen 1/(1−f) nicht überschreiten (Amdahlsches Gesetz)
  2. Request scheduling Microsoft
    Grains (Actors) in Orleans arbeiten Anfragen nach einem Single-Thread-Ausführungsmodell einzeln bis zum Ende ab und ändern ihren Zustand daher nie gleichzeitig, warten Grains gegenseitig auf ihre Antworten, ist ein Deadlock möglich
  3. pidstat(1) — Linux manual page sysstat
    cswch/s bei -w ist die Zahl freiwilliger Kontextwechsel, bei denen ein Thread anhält, um auf eine Ressource zu warten, -t zeigt die Werte pro Thread
  4. Demonstrations of offcputime, the Linux eBPF/bcc version IO Visor
    Summiert die Zeit, in der Threads angehalten waren und die CPU verlassen hatten (off-CPU), pro Call-Stack, -p wählt den Prozess
  5. Well-known EventCounters in .NET Microsoft
    Monitor Lock Contention Count (monitor-lock-contention-count): Zahl der Konflikte beim Versuch, einen Monitor-Lock zu erhalten
  6. .NET runtime metrics .NET
    Ab .NET 9 dotnet.monitor.lock_contentions: Zahl der Konflikte beim Versuch, einen Monitor-Lock zu erhalten, seit Prozessstart

Verwandte Ursachen

Gleiche Schicht: L9 Spielprozess auf dem Server

Ursachen aus anderen Schichten mit demselben Symptom (Input-Lag)

Karte in der interaktiven Fassung mit Grafiken und Experimenten ansehen