Post mortem zu den Störungen am Samstag

Am Samstag, den 13.03.2021 gab es zeitweise Störungen der Webseite der Chemnitzer Linux-Tage und des Streamings. Im folgenden soll dargelegt werden, was wir beobachtet haben, wie wir reagiert haben, und was wir in Zukunft anders machen wollen.

Streaming

Zuerst beobachteten wir Störungen am Streaming. Kurz vor Beginn des Eröffnungsvortrags hatten sich wie erwartet ein paar hundert Zuschauende auf den Stream geschaltet. Für die Zuschauenden stellte sich die Situation so dar, dass der Stream einige Sekunden lief und sich dann abrupt beendete. Auf dem Server startete der Docker-Container mit dem Streaming-Server im Abstand von ein paar Sekunden neu. Nach kurzer Zeit war klar, dass der Streaming-Server vom Betriebssystem mit SIGSEGV beendet wurde.

Das Fehlerbild war zunächst recht diffus. Vor den Linux-Tagen haben wir mit der Streaming-Infrastruktur Lasttests durchgeführt. Wir hatten knapp 1500 Chrome-Instanzen per Selenium so gesteuert, dass diese sich innerhalb von einer Minute auf einen Stream aufschalten. Dies funktionierte im Test fehlerfrei. Wir fragten uns, ob es irgendeine merkwürdige Browser-Implementierung sein könnte, die sich anders als die von Chrome verhält, und die den Streaming-Server zum Absturz brachte.

Im Serverlog tauchten als User Agent allerdings nur die üblichen Verdächtigen Chrome/Chromium und Firefox auf. Wir testeten ältere Versionen des Streaming-Servers mit gleichem Resultat. Dasselbe Resultat ereignete sich mit der aktuellen Version des Master-Branches aus dem Git-Repository. Schließlich kamen wir darauf, dass der einzige Unterschied zwischen Test- und Produktionsumgebung die Firewall war, die einen Teil der UDP-Ports freigegeben hatte, aber nicht alle. Als wir mit netstat nachsahen, konnten wir sehen, dass der Streaming-Server auch Ports aus dem Bereich gewählt hatte, der von der Firewall blockiert wurde.

Die Lösung war also ganz einfach: Wir erweiterten den Port-Bereich in der Firewall. Anschließend funktionierte der Streaming-Server wie gewünscht. Leider hat es bis zu dieser Erkenntnis etwas länger als zwei Stunden gedauert.

Webseite

Mit zunehmender Nutzung der CLT-Webseite kam es zu Störungen bei der Auslieferung der Webseite. Unser Monitoring-System meldete uns hohe Last auf dem Webserver, Webseiten wurden mit Statuscode 500 ausgeliefert.

Die CLT-Webseite besteht aus einem in PHP geschriebenen Frontend und einem Django-Backend, das die Programmdaten per REST-API bereitstellt. Für jeden Request im Frontend wurde die API einmal abgerufen. Dies war unser erster Optimierungsansatz. Da sich während der Veranstaltung an der Datenbank so gut wie nichts mehr ändert, haben wir die API-Ergebnisse lokal auf dem Webserver zwischengespeichert. Dies reduzierte die erste Überlastsituation, war aber nur ein Teil der Lösung. Zur nächsten vollen Stunde, als die Vorträge wechselten, gab es wieder eine Überlastsituation.

Parallel zu unseren Umbauarbeiten haben die Kollegen vom Universitätsrechenzentrum der virtuellen Maschine mehr CPUs zur Verfügung gestellt (das hatten wir angefragt). Virtuelle Maschinen auf dem Hypervisor, auf dem der CLT-Webserver lief, wurden auf andere Host-Systeme migriert. Uns wurde zugesichert, dem Webserver weitere CPUs bereitzustellen, wenn wir dies benötigen. Das hätten wir nicht zu fragen gewagt. Vielen Dank an dieser Stelle für die spontane und unkomplizierte Hilfe!

Die zusätzlichen CPUs linderten das Problem allerdings nur kurzfristig. Es gab keine klar erkennbare Ursache. Die Systemlast lag bei 160, die CPUs waren nicht ausgelastet, RAM war genug verfügbar, Disk-IO war nicht ausgelastet, Netzwerkverkehr kein Flaschenhals. Wir haben einzelne Webserver-Prozesse mit strace untersucht. Uns fiel auf, dass alle Prozesse mehrfach auf ein AFS-Verzeichnis zugriffen. AFS ist ein Netzwerkdateisystem, das an der TU Chemnitz große Verbreitung hat. Die Webseiten der älteren CLT liegen alle im AFS, neuere CLT-Webseiten liegen lokal auf dem Webserver.

Bei jedem Aufruf einer Beitragsseite wurde vom entsprechenden AFS-Verzeichnis bis zur Dateisystemwurzel ein lstat-Systemaufruf durchgeführt, der ca. 200 bis 800 Millisekunden benötigte. Die Webserver-Prozesse waren dadurch blockiert.

Ursache für die AFS-Zugriffe waren mehrere Dinge:

  • Mediendaten wie Video-, Audiodateien und Folien liegen im AFS. Jeder lstat-Systemruf erzeugt bei AFS eine Abfrage an den Fileserver und wird nicht vom Client gecacht.
  • Das Document-Root des Webservers lag noch im AFS und verwies per Symlink auf die lokal gespeicherte Webseite für 2021. Zum Auflösen des Symlinks wurde lstat ausgeführt, und führte zum selben Problem wie mit den Mediendateien. Wir haben die Webserver-Konfiguration kurzfristig geändert. Während der CLT waren ältere CLT-Webseiten deswegen nicht erreichbar.

Während der Veranstaltung drosselte der Fileserver irgendwann aus bisher nicht nachvollziebaren Gründen die Bearbeitung der lstat-Aufrufe. Aus diesem Grund kam es während der Veranstaltung zu mehreren Ausfällen der Webseite. In dem Momenten, in dem wir die Zugriffe auf die Mediendateien deaktivierten bzw. das Document-Root umkonfigurierten, normalisierte sich die Lage sofort und die Systemlast reduzierte sich unmittelbar auf nahe 0.

Nach den CLT haben wir die Webseite so umgestellt, dass die Zugriffe auf die Medien und ältere Webseiten wieder möglich waren, ohne dass für jeden Request mehrfach auf das AFS zugegriffen werden muss.

Was wir gelernt haben

Wir hatten nicht mit so vielen Zugriffen auf den Webserver gerechnet (es waren über 770000 Beitragsabfragen) und haben im Gegensatz zum Streaming auch keine Benchmarks durchgeführt. Die Benchmarks fürs Streaming haben wir nur mit der gesonderten Streaming-Webseite durchgeführt, nicht mit dem Rest der CLT-Webseite. Sollten die CLT noch einmal virtuell stattfinden müssen, dann würden wir beim Benchmark sicherlich den gesamten Klickpfad von der Startseite bis zum Stream abbilden, um ein realistischeres Lastszenario zu erhalten und Flaschenhälse frühzeitig zu entdecken.