Wenn es um TV-Ausstrahlungen in Form von Werbeblöcken oder gar um Sendungen wie «Die Höhle der Löwen» geht, müssen Websites und Server besonders viel aushalten. Was konkret passiert, wenn viele Menschen gleichzeitig eine Website aufrufen und wie du dich darauf vorbereiten kannst, möchte ich dir anhand eines konkreten Beispiels zeigen.
Bei allen Maßnahmen die Ergriffen werden ist es immer wichtig sich vor Augen zu halten, dass es nicht «die Methode» gibt um eine Website abzusichern. Vielmehr müssen von der Programmierung bis zum Server und Hosting viele Einzelschritte ineinander greifen, um eine Website ideal auf einen Ansturm vorzubereiten.
Das hier beschriebene Vorgehen wurde individuell für eine ganz bestimmte eher einfache Website entwickelt. Sei dir darüber bewusst, dass du es für andere Websites vermutlich modifizieren musst.
Vorüberlegungen
Aber ganz von vorne: Irgendwann war für eine meiner Kund:innen klar: Es wird eine TV-Ausstrahlung geben. Auch der Termin stand bereits fest. Es blieb weniger als ein Monat Zeit, die Website darauf vorzubereiten. Wirklich wenig Zeit.
Zunächst war es wichtig zu überlegen welcher Ansturm in ungefähren Zahlen überhaupt erwartet wird und was die Website theoretisch leisten müsste. Dazu gab es eine simple Rechnung. Die Rechnung beinhaltet absichtlich höhere Zahlen als angenommen, um die Website bestmöglich vorzubereiten:
- ca. 2.000.000 Zuschauer:innen (Einschaltquote) werden in 30 Minuten vor den TV-Geräten erwartet
- ca. 25% der Leute rufen die Website auf = ca. 500.000 erwartete Besucher:innen
- Ein einziger Aufruf der Website erzeugt 20 Requests (Bilder, Scripts, Styles, Fonts, etc…)
- Das entspricht grob 10.000.000 Requests, die in 30 Minuten vom Server bedient werden müssen
- 10% der Besucher:innen senden ein Formular ab = 50.000 Post-Anfragen, welche Mails versenden oder in die Datenbank gehen
- 30 Minuten haben 1800 Sekunden
- 10.000.000 Requests teilen sich 1800 Sekunden = ca. 5555 Requests pro Sekunde
- 50.000 Post-Anfragen teilen sich 1800 Sekunden = das sind 30 theoretische Formular-Anfragen pro Sekunde, die in die Datenbank gehen
- Das größte Bild auf der Startseite ist 2MB groß. Das allein wird also ca. 1GB Traffic verursachen.
Schnell war klar, dass die Website mit dem bisherigen Setup das nicht schaffen wird. Es handelt sich um ein altes WordPress-System auf einem Shared-Hosting. Es ist eine eher einfache Website mit dem ein oder anderen Kontaktformular.
An dieser Stelle war mir das erste mal klar, dass die Website ein Problem bekommen wird, wenn wir jetzt nicht alle Hebel in Bewegung setzen.
Konkrete Maßnahmen
Komprimieren und reduzieren der Website-Assets
Schnell war klar, dass wir mit dem bisherigen WordPress nicht mehr arbeiten können. Das Template war relativ alt, war nicht komprimierbar, war schwer zu bundeln und das Projekt war durchsetzt mit vielen historisch gewachsenen Plugins. Zudem sollte für die Ausstrahlung ein neues Design umgesetzt werden. Wir entschieden uns für einen schnellen Relaunch mit Typo3. Dabei wurde ein eigenes Theme auf Basis von TailwindCSS und Webpack erstellt. Das Resultat waren extrem kleine Javascript und CSS-Files sowie ein schlanker und schneller HTML-Code. Allein das hat die Request und die zu übertragenden Daten extrem reduziert. Natürlich wurde auch auf die Größe der Bilder geachtet. Auf Retina-Bilder in doppelter Größe haben wir verzichtet.
Umwandlung in eine statische Website
Um die Performance noch weiter zu steigern haben wir uns dazu entschieden die Typo3-Website in eine statische Website umzuwandeln. Das geht relativ leicht mit Curl und Wget. Alle Requests können so extrem schnell vom Webserver bedient werden. Via Script können Änderungen aus der Typo3-Instanz schnell und einfach auf die statische Seite kopiert werden. Diese Maßnahme sorgt dafür, dass PHP weitgehend umgangen wird. Das spart Speicher und CPU-Last.
Der Plan war, die statische Website nach der Ausstrahlung wieder durch das Original-System zu ersetzen, damit von der Kund:in selbst Modifikationen vorgenommen werden können.
Reimplementierung von Kontaktformularen
Die Website verfügt über einige Kontaktformulare. Diese können natürlich nicht statisch bleiben. Schließlich müssen die Daten irgendwie gespeichert oder versendet werden. Kurzerhand habe ich daher einen API-Endpunkt in PHP geschrieben, welcher Anfragen von Kontaktformularen entgegennehmen und in einer Datenbank speichern kann. Weil die Zeit wirklich drängte entschieden wir uns außerdem keine Mails zu versenden. Ich wollte unbedingt Probleme mit überlasteten Mailservern in diesem Zusammenhang vermeiden. Die Daten sollten während der Ausstrahlung lediglich gesammelt und erst später verarbeitet werden. Nach der Ausstrahlung kann ein Cronjob nach und nach Bestätigungs-Mails versenden.
Auch die Formularsicherheit wurde zu diesem Zweck reduziert. Ich wollte bei einem solchen Ansturm keine Probleme mit einem Captcha-Service riskieren weshalb lediglich ein simpler Honeypot zum Einsatz kam. Auch gab es keine CSRF-Tokens für die Formulare, welche eigentlich für die Sicherheit unverzichtbar sind. Allerdings müssten derartige Tokens erst wieder generiert werden. Zumindest für die Ausstrahlung wurde darauf verzichtet.
Abschalten aller externer Dritt-Services wie Google Maps, Google Recaptcha, Analytics, externe Fonts, Iframes, etc…
Wir wollten unbedingt Fehler im Zusammenhang mit der Ausstrahlung bzw. der besonders hohen Last vermeiden. Dabei mussten wir auch an Dritte Services denken, welche eventuell auch Requests abbekommen, wenn die Seite aufgerufen wird. Es kann erstens passieren, dass diese Services dadurch ausfallen oder dass sie Limits erreichen. Um derartige böse Überraschungen zu vermeiden wurden diese Services für die Ausstrahlung bewusst deaktiviert bzw. in der Entwicklung vermieden.
Aufrüsten des Servers
Nach intensiven Vorgesprächen mit dem neuen Hoster (MaxCluster) wurde der Server extra für diesen Tag aufgerüstet. Uns stand an diesem Tag eine dedizierte CPU mit 12 Kernen sowie 8 GB exklusiver RAM zur Verfügung. Mehr als genug, um eine weitgehend statische Website zu bedienen.
Varnish aktivieren
Varnish ist ein HTTP Cache, den du vor deinen Webserver schalten kannst, um Inhalte zu cachen und besonders schnell auszuliefern. Derartige Caches sind ein wahrer Booster und helfen deinem Server Requests schneller zu beantworten. Genau das haben wir auch getan. Natürlich musste ich daran denken die API vom Caching auszunehmen.
Einrichten eines CDN
Bis zu diesem Punkt wurde die Seite schon gut optimiert. Aber vermutlich könnte selbst ein größerer Webserver hier an Grenzen kommen. Ich musste unbedingt die Requests an den Server weiter reduzieren. Und zwar drastisch. Ein erster Schritt war, die Assets wie Bilder, Videos, Javascript und CSS in ein CDN auszulagern. Dadurch wurde dann nur noch das HTML von dem eigenen Server ausgeliefert. Alles andere kommt vom CDN.
Wir waren für diese Zeit bei CloudFlare. Aber auch Amazon CloudFront wäre hier eine gute Alternative. Bei CloudFlare konnten wir sogar die komplette Seite in den Cache legen, sodass auf dem Server nur noch von mir eingestellte Ausnahmen wie Requests an die Formular-API ankamen. Einige CDNs haben integrierte Firewalls und Bedrohungserkennungen. Diese haben wir für den Tag der Ausstrahlung bewusst deaktivieren.
Warum die ganzen Maßnahmen?
An dieser Stelle klingt die Optimierung der Website etwas sinnlos. Warum haben wir eine statische Seite mit komprimierten Assets? Und warum nutzen wir Varnish, wenn eh alles aus einem CDN-Cache kommt? Ganz einfach: Erstens kann es passieren, dass wir den Cache des CDN spontan purgen müssen, weil es eine wichtige Änderung gibt. Zweitens kann es zu unerwarteten Problemen kommen, sodass wir schnell reagieren müssen und eventuell Teile des CDNs abschalten müssen. In beiden Fällen würden Requests direkt auf den Server durchschlagen. Das ganze Setup hat quasi mehrere Sicherheitsschirme.
Lastentests – mit einem Hammer auf die Website hauen
Mit loader.io habe ich die Website einem echten Stresstest unterzogen. Du kannst diesen Service buchen und einfach mal testen wie das ist, wenn tausende von Leuten pro Sekunde gleichzeitig auf eine Seite zugreifen. Auf Basis dieser Erkenntnisse kannst du deinen Server weiter optimieren.
Wichtig ist hier jede Schale einzeln zu testen. Also was passiert, wenn 5000 Personen gleichzeitig auf den Webserver zugreifen? Was passiert, wenn diese Anzahl auf Varnish losgelassen wird? Was passiert im gleichen Szenario wenn Cloudflare davor ist? Wie reagiert mein Datenbankserver auf diesen Ansturm? So kannst du diverse Probleme in jeder Schicht beheben.
Mehr Loopback-Adressen einrichten
Das erste, was auf dem Server passierte, als wir den Lastentest starteten: Die verfügbaren Ports auf der default Loopback-Adresse waren am Limit. Es mussten also zusätzliche Loopback-Adressen erstellt werden, um noch mehr parallele Verbindungen bedienen zu können.
PHP und MySQL Limits ändern
Als das Problem mit den Ports behoben war, waren die nächsten üblichen Verdächtigen an der Reihe. Schnell waren die maximalen PHP-Prozesse bzw. die maximalen Datenbankverbindungen erreicht. Die Konfiguration musste hier entsprechend angepasst werden.
Was passierte am Tag der Ausstrahlung
Die Sendung startete an einem Tag unter der Woche um 20:15 Uhr. Die Sendung befasste sich ab ca. 21 Uhr mit der betroffenen Website. Zwischen 21 und 22 Uhr hatten wir einen Peak von ca. 35.000 unique Visits laut CloudFlare. In diesem Zeitraum gab es laut CloudFlare einen Peak von 2,45 Millionen Requests, welche aus dem CloudFlare Cache bedient wurden. Weniger als 10.000 Requests gingen direkt auf unseren Server. Ca. 300 GB wurden im Peak von CloudFlare bedient. Ca. 500 MB kamen direkt von unserem Server. Die Videos und einige große PNG-Bilder haben ordentlich Traffic verursacht. Ein einziges Video auf der Startseite verursachte 134 GB Traffic.
Zusammenfassung
Dank guter Vorplanung hat die Website standgehalten. Die TV-Ausstrahlung war ein voller Erfolg. Es gab weder Probleme beim Laden noch sonstige Ausfälle. Alle Daten wurden sauber in der Datenbank erfasst und konnten in den Folgetagen verarbeitet werden. Vermutlich haben wir sogar mit der ein oder anderen Maßnahme übertrieben. Aber besser so als anders. Die Website wurde nach dieser Aktion wieder entsprechend abgerüstet.
Titelbild: https://pixabay.com/de/photos/fernseher-fernsehen-retro-klassisch-1844964/