Website Stresstest: Performance / Ladezeit messen verbessern
In der Vergangenheit hat es immer wieder Seiten gegeben, die unter der Last hoher Besucherzahlen zusammengebrochen sind. Obwohl meine Seite bis dato mit den aktuellen Besucherzahlen gut zurechtkommt, war ich neugierig, wie viele gleichzeitige Besucher mein Webserver bedienen kann, daher habe ich diesen einem Performancetest unterzogen.
Antwortzeit der Website
Die Antwortzeit der Website liefert bereits ein Indiz darauf, wie viele Anfragen der Webserver bewältigen kann:
Wie viele Anfragen / Sekunde sind normal?
Laut Google sollte die Ladezeit des Hauptdokuments einer Website unter 200ms sein (Quelle: developers.google.com/speed/docs/insights/mobile). Ein Blick in die Chrome Devtools, F12 im Browser, verrät die Ladezeit der Seite. Das Hauptdokument lässt sich einfach mit "Doc" filtern:
Je höher diese Ladezeit ist, desto mehr Zeit benötigt der Server, um die Seite serverseitig zu rendern. Der Wert beinhaltet natürlich auch die Latenz zum Server, sowas zwischen 20 und 70ms. Sollte der Server für das Rendern der Seite, sagen wir mal 100ms benötigen, schafft er damit knapp 10 Anfragen / Sekunde. Klar, der Server hat meist mehrere Prozessoren und somit mehrere Threads gleichzeitig am Start und somit mehr Rechenleistung: Wer aber keinen dedizierten Server gemietet hat, teilt sich die Hardware mit anderen. Auch ein vServer oder Cloud-Server mit 2v CPU liefert dann in der Praxis nicht wesentlich mehr als würden die Anfragen einfach der Reihe nach ausgeführt werden. Diese starke Vereinfachung ist so natürlich nicht zulässig, in der Praxis bewegen wir uns bei nur einem Server dennoch mehrheitlich in dieser Dimension ...
Wie kann die Seite beschleunigt werden?
Kaum jemand verwendet heute noch statische Websites, dabei wären Seiten ohne Serverlogik richtig schnell. Je weniger der Server für das Zusammenstellen der Seite rechnen muss, bzw. je weniger Daten der Server aus möglicherweise komplizierten Abfragen aus der Datenbank holen muss, desto schneller kann die Seite zusammengestellt und zum Browser geschickt werden. Ziel ist es also die Rechenzeit für die Seite zu minimieren. Dazu kann der Webserver und dessen Konfiguration getunt werden, zudem werden heutige dynamische Websites meist durch das Cachen bestimmter Teile oder der kompletten Seite beschleunigt. Die Seite wird also beim ersten Aufruf teilweise oder komplett berechnet und das Ergebnis gesondert abgelegt. Beim erneuten Aufruf der Seite werden bereits vorberechnete Ergebnisse für das Ausliefern der Seite herangezogen. Größere Websites verwenden vornehmlich mehrere Webserver, um die Last aufzuteilen, bzw. kann auch ein Dienst wie Cloudflare vorgeschaltet werden um die Inhalte zu cachen.
Geschwindigkeit testen: Tools
Warnung: bitte nur für die eigene Website
Die hier vorgestellten Tools bitte nur für die eigene Website verwenden. Die Loadtests könnten die Website für die Dauer des Tests überfordern bis diese möglicherweise nicht mehr reagiert.
loader.io
Loader.io bietet einen Websites-Stresstest als Cloud-Service. Damit der Service nicht missbraucht werden kann, muss die Domain per Text-File am Server vorab bestätigt werden, siehe auch: loader.io
Ähnliche Ergebnisse liefert das kleine http Benchmarking Tool wrt:
wrk - http Benchmark
wrk - Download
Für die Installation wird ein auf Linux basierter Rechner benötigt. Mit folgenden Terminal-Befehlen kann wrk heruntergeladen und für den Einsatz vorbereitet werden:
git clone https://github.com/wg/wrk.git
cd wrk
make
siehe auch: https://github.com/wg/wrk
Test des eigenen Webservers: wrk
wrk kann dann einfach über das Terminal mit folgenden Parametern gestartet werden:
./wrk -t4 -c400 -d30s http://127.0.0.1:90
Parameter
-t4 ... 4 threads
-c400 ... 400 gleichzeitige Verbindungen
-d30s ... Dauer 30 Sekunden
http://127.0.0.1:90 steht als Beispiel für den lokalen Webserver, wenn der auf Port 90 horcht.
Ergebnis: dynamische Seite vs. statischer Cache
Der Test einer frischen Laravel-Installation und deren Startseite schaut wie folgt aus:
Die Ladezeit beträgt auf meinem lokalen Rechner 59ms für das Laden des Hauptdokumentes, was pro Sekunde und Rechenkern ca. 17 Seiten bedeuten würde. Nachdem mein Rechner 4 Kerne hat und auch die Website am selben Gerät läuft, kann der Rechner mehr als doppelt so viele Anfragen verarbeiten: Das Ergebnis von wrk sind 37,34 Anfragen / Sekunde:
./wrk -t4 -c400 -d30s http://127.0.0.1:90
Running 30s test @ http://127.0.0.1:90
4 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.32s 391.33ms 1.89s 64.29%
Req/Sec 18.57 16.99 150.00 80.23%
1124 requests in 30.10s, 20.43MB read
Socket errors: connect 0, read 0, write 0, timeout 1096
Requests/sec: 37.34
Transfer/sec: 694.86KB
Cache mit statischen .html Files
Als Beispiel cached das Laravel-Paket von Joseph Silber die Website in statische .html-Files. Der Webserver: nginx liefert dabei nur mehr den Inhalt der Files, nachdem diese nach dem ersten Aufruf abgelegt wurden, siehe: github.com/JosephSilber/page-cache
Mit diesem Setup schaut die Sache komplett anders aus:
Die Seite kann in 6ms an den Browser übergeben werden und wrk zeigt bei mir unglaubliche 4766,22 Requests/sec:
./wrk -t4 -c400 -d30s http://127.0.0.1:90
Running 30s test @ http://127.0.0.1:90
4 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.99ms 53.77ms 1.99s 94.57%
Req/Sec 1.33k 1.04k 5.49k 71.34%
143362 requests in 30.08s, 2.38GB read
Socket errors: connect 0, read 0, write 0, timeout 1328
Requests/sec: 4766.22
Transfer/sec: 80.89MB
Der Wert kann nicht direkt auf die Anzahl der Besucher umgemünzt werden, da ein Seitenaufruf zusätzliche Assets: Javascript, CSS und Bilder lädt, entsprechend generiert ein Benutzer mehrere Requests. Da hier das Hauptdokument gleich schnell wie die Assets zur Verfügung gestellt wird, hat die Anzahl und Größe der Assets auch eine gewichtigere Rolle als bei einer dynamischen Seite: Bei einer dynamischen Seite ist die Zeit für das Laden des Hauptdokuments der Flaschenhals, bei statischen Files die Anzahl und Größe der Files.
Fazit
Die Performance einer Website ist extrem abhängig von der eingesetzten Webapplikation und dem Webserver-Setup. Dynamische Websites oder Frameworks sind heute nicht mehr wegzudenken, haben aber einen gewissen Overhead. Die Auswirkung dieses Overheads kann wiederum durch bestimmte Caching-Mechanismen minimiert werden. Neben dem Caching kann der Webserver auch eine bestimmte Rolle spielen, siehe: Erste Erfahrungen mit Laravel Octane 1.0. Die Bandbreite der möglichen Anfragen pro Sekunde schwankt je nach Webserver und Cache-Setup von ein paar Anfragen pro Sekunde bis hin zu mehreren tausend Requests pro Sekunde.
{{percentage}} % positiv