Wenn Sie einen Backend-Dienst in einen Anwendungs-Load-Balancer einbinden, ist es wichtig, die Leistung eines Backend-Dienstes allein zu messen, wenn kein Load-Balancer vorhanden ist. Lasttests unter kontrollierten Bedingungen helfen Ihnen, Kompromisse im Rahmen der Kapazitätsplanung zwischen verschiedenen Leistungsdimensionen wie Durchsatz und Latenz abzuwägen. Da eine sorgfältige Kapazitätsplanung die tatsächliche Nachfrage weiterhin unterschätzen kann, empfehlen wir, über Lasttests proaktiv zu bestimmen, wie sich die Verfügbarkeit eines Dienstes auf die Überlastung auswirkt.
Lasttestziele
Bei einem typischen Lasttest wird das extern sichtbare Verhalten des Backend-Dienstes unter verschiedenen Lastdimensionen gemessen. Zu den wichtigsten Dimensionen dieser Tests gehören:
- Anfragedurchsatz: Die Anzahl der pro Sekunde verarbeiteten Anfragen.
- Nebenläufigkeit von Anfragen: Die Anzahl der Anfragen, die gleichzeitig verarbeitet werden.
- Verbindungsdurchsatz: Die Anzahl der pro Sekunde von Clients initiierten Verbindungen. Die meisten Dienste, die Transport Layer Security (TLS) verwenden, haben für jede Verbindung, die unabhängig von der Anfrageverarbeitung ist, einen gewissen Netzwerktransport- und TLS-Verhandlungsaufwand.
Verbindungs-Nebenläufigkeit: Die Anzahl der Clientverbindungen, die gleichzeitig verarbeitet werden.
Anfragelatenz: Die Gesamtzeit zwischen dem Beginn der Anfrage und dem Ende der Antwort.
Fehlerrate: Gibt an, wie oft Anfragen Fehler verursachen, darunter HTTP 5xx-Fehler und vorzeitig geschlossene Verbindungen.
Zur Bewertung des Zustands des Servers unter Last kann ein Lasttestverfahren auch folgende interne Dienstmesswerte erfassen:
Nutzung von Systemressourcen: Systemressourcen, darunter Werte für CPU, RAM und Dateihandles (Sockets), werden normalerweise in Prozent angegeben.
Die Bedeutung dieser Messwerte hängt davon ab, wie der Dienst implementiert ist. Wenn Anwendungen ihre Ressourcen erschöpfen, kommt es zu einer geringeren Leistung, einer verminderten Last oder einem Absturz. Daher ist es wichtig, die Verfügbarkeit von Ressourcen zu ermitteln, wenn der Host stark ausgelastet ist.
Nutzung anderer begrenzter Ressourcen: Nicht-Systemressourcen, die unter Last erschöpft sind, z. B. auf Anwendungsebene.
Beispiele für solche Ressourcen:
- Ein begrenzter Pool von Worker-Threads oder ‑prozessen.
- Bei einem Anwendungsserver, der Threads verwendet, ist in der Regel die Anzahl der gleichzeitig ausgeführten Worker-Threads begrenzt. Thread-Pool-Größenlimits sind nützlich, um zu verhindern, dass Arbeitsspeicher und CPU überlastet werden. Die Standardeinstellungen sind jedoch oft sehr konservativ. Zu niedrige Limits können die angemessene Nutzung von Systemressourcen verhindern.
- Einige Server verwenden Prozess- anstelle von Threadpools. Beispiel: Ein Apache-Server weist bei Einrichtung mit dem Prefork Multi-Processing-Modell jeder Clientverbindung einen Prozess zu. Die Größenbeschränkung des Pools bestimmt also die Obergrenze für die Gleichzeitigkeit von Verbindungen.
- Ein Dienst, der als Frontend für einen anderen Dienst mit einem Backend-Verbindungspool von begrenzter Größe bereitgestellt wird.
Kapazitätsplanung und Überlastungstests
Mit Lasttesttools können Sie verschiedene Skalierungsdimensionen einzeln messen. Legen Sie für die Kapazitätsplanung Lastgrenzwerte für die akzeptable Leistung in verschiedenen Dimensionen fest. Anstatt beispielsweise das absolute Limit einer Dienstanfrage vollständig zu messen, könnten Sie Folgendes messen:
- Die Anfragerate, mit der der Dienst mit einer Latenz des 99. Perzentils verarbeitet werden kann, die unter einer angegebenen Anzahl an Millisekunden liegt. Die Anzahl wird durch den SLO-Wert des Dienstes festgelegt.
- Die maximale Anfragerate, bei der die Systemressourcenauslastung die optimalen Werte nicht überschreitet. Die optimale Auslastung variiert je nach Anwendung und kann deutlich unter 100 % liegen. Bei einer Spitzenauslastung von 80 % kann die Anwendung beispielsweise kleinere Lastspitzen besser bewältigen als die Spitzenauslastung von 99 %.
Es ist zwar wichtig, die Ergebnisse von Lasttests zu verwenden, um Entscheidungen zur Kapazitätsplanung zu bilden, aber es ist ebenso wichtig zu verstehen, wie sich ein Dienst verhält, wenn die Last die Kapazität überschreitet. Zu den Serververhalten, die häufig mit Überlastungstests bewertet werden, zählen:
Load-Shedding: Wenn ein Dienst übermäßig viele eingehende Anfragen oder Verbindungen erhält, kann er deswegen alle Anfragen verlangsamt oder einige Anfragen ablehnt, um für die übrigen Anfragen eine akzeptable Leistung zu erhalten. Wir empfehlen den zweiten Ansatz, um Zeitüberschreitungen des Clients vor dem Empfang einer Antwort zu verhindern und das Risiko einer Speicherausschöpfung durch die Verringerung der gleichzeitigen Anfrage auf dem Server zu reduzieren.
Sicherheit vor Ressourcenüberlastung: Ein Dienst vermeidet im Allgemeinen das Abstürzen der Ressourcen, da es für ausstehende Anfragen schwierig ist, weitere Fortschritte zu machen, wenn der Dienst abstürzt. Wenn ein Backend-Dienst viele Instanzen hat, ist die Robustheit der einzelnen Instanzen für die Gesamtverfügbarkeit des Dienstes entscheidend. Während eine Instanz nach einem Absturz neu gestartet wird, können andere Instanzen eine höhere Last haben, was zu Kaskadenfehlern führen kann.
Allgemeine Testrichtlinien
Berücksichtigen Sie bei der Definition Ihrer Testfälle folgende Richtlinien.
Begrenzte Tests erstellen
Erstellen Sie begrenzte Tests, um die Leistungsgrenzen des Servers zu messen. Bei übermäßiger Serverkapazität besteht das Risiko, dass ein Test nicht die Leistungsgrenzen des Dienstes selbst aufdeckt, sondern Engpässe in anderen Systemen erkennt, z. B. in den Clienthosts oder in der Netzwerkebene.
Die besten Ergebnisse erzielen Sie mit einem Testfall, der eine einzelne VM-Instanz oder einen GKE-Pod (Google Kubernetes Engine) verwendet, um den Dienst unabhängig zu testen. Sie können bei Bedarf mehrere VMs verwenden, um eine vollständige Auslastung des Servers zu erzielen. Denken Sie jedoch daran, dass dies die Erfassung von Leistungsdaten komplizieren kann.
Lademuster für Open-Loop-Systeme auswählen
Die meisten Lastgeneratoren verwenden das Closed-Loop-Muster, um die Anzahl der gleichzeitigen Anfragen zu begrenzen und neue Anfragen zu verzögern, bis die vorherigen abgeschlossen wurden. Wir raten von diesem Ansatz jedoch ab, da die Produktionsclients des Dienstes möglicherweise kein solches Drosselungsverhalten aufweisen.
Im Gegensatz dazu ermöglicht es das Open-Loop-Muster Load-Generatoren, die Produktionslast zu simulieren. Dazu werden Anfragen mit einer konstanten Rate gesendet, unabhängig von der Rate, mit der Serverantworten eingehen.
Tests mit empfohlenen Lastgeneratoren ausführen
Wir empfehlen folgende Lastgeneratoren für die Lasttests des Backend-Dienstes:
Nighthawk
Nighthawk ist ein Open-Source-Tool, das in Zusammenarbeit mit dem Envoy-Projekt entwickelt wurde. Sie können damit Clientlasten generieren, Benchmarks visualisieren und die Serverleistung für die meisten Lasttestszenarien von HTTPS-Diensten messen.
HTTP/1 testen
Testen Sie HTTP/1 mit folgendem Befehl:
nighthawk_client URI \ --duration DURATION \ --open-loop \ --no-default-failure-predicates \ --protocol http1 \ --request-body-size REQ_BODY_SIZE \ --concurrency CONCURRENCY \ --rps RPS \ --connections CONNECTIONS
Ersetzen Sie Folgendes:
URI
: Die zu vergleichende URIDURATION
: Die gesamte Testlaufzeit in SekundenREQ_BODY_SIZE
: Größe der POST-Nutzlast pro AnfrageCONCURRENCY
: Die Gesamtzahl der gleichzeitigen EreignisschleifenDiese Zahl sollte mit der Anzahl der Kerne der Client-VM übereinstimmen
RPS
: Zielrate der Anfragen pro Sekunde und EreignisschleifeCONNECTIONS
: Anzahl der gleichzeitigen Verbindungen pro Ereignisschleife
Sehen Sie sich folgendes Beispiel an:
nighthawk_client http://10.20.30.40:80 \ --duration 600 --open-loop --no-default-failure-predicates \ --protocol http1 --request-body-size 5000 \ --concurrency 16 --rps 500 --connections 200
Die Ausgabe der einzelnen Testläufe enthält je ein Histogramm der Antwortlatenzen. Im Beispiel aus der Nighthawk-Dokumentation beträgt die Latenz des 99. Perzentils etwa 135 µs.
Initiation to completion samples: 9992 mean: 0s 000ms 113us pstdev: 0s 000ms 061us Percentile Count Latency 0 1 0s 000ms 077us 0.5 4996 0s 000ms 115us 0.75 7495 0s 000ms 118us 0.8 7998 0s 000ms 118us 0.9 8993 0s 000ms 121us 0.95 9493 0s 000ms 124us 0.990625 9899 0s 000ms 135us 0.999023 9983 0s 000ms 588us 1 9992 0s 004ms 090us
HTTP/2 testen
Testen Sie HTTP/2 mit folgendem Befehl:
nighthawk_client URI \ --duration DURATION \ --open-loop \ --no-default-failure-predicates \ --protocol http2 \ --request-body-size REQ_BODY_SIZE \ --concurrency CONCURRENCY \ --rps RPS \ --max-active-requests MAX_ACTIVE_REQUESTS \ --max-concurrent-streams MAX_CONCURRENT_STREAMS
Ersetzen Sie Folgendes:
URI
: Die zu vergleichende URIDURATION
: Die gesamte Testlaufzeit in SekundenREQ_BODY_SIZE
: Größe der POST-Nutzlast pro AnfrageCONCURRENCY
: Die Gesamtzahl der gleichzeitigen EreignisschleifenDiese Zahl sollte mit der Anzahl der Kerne der Client-VM übereinstimmen
RPS
: Die Zielrate von Anfragen pro Sekunde pro EreignisschleifeMAX_ACTIVE_REQUESTS
: Die maximale Anzahl gleichzeitiger aktiver Anfragen für die einzelnen EreignisschleifeMAX_CONCURRENT_STREAMS
: die maximale Anzahl gleichzeitiger Streams, die für die einzelnen HTTP/2-Verbindung zulässig sind
Sehen Sie sich folgendes Beispiel an:
nighthawk_client http://10.20.30.40:80 \ --duration 600 --open-loop --no-default-failure-predicates \ --protocol http2 --request-body-size 5000 \ --concurrency 16 --rps 500 \ --max-active-requests 200 --max-concurrent-streams 1
ab (Apache Benchmark-Tool)
ab
ist eine weniger flexible Alternative zu Nighthawk, die aber als Paket in fast jeder Linux-Distribution verfügbar ist. ab
wird nur für schnelle und einfache Tests empfohlen.
Verwenden Sie zum Installieren von ab
den folgenden Befehl:
- Führen Sie unter Debian oder Ubuntu
sudo apt-get install apache2-utils
aus. - Führen Sie für RedHat-basierte Distributionen
sudo yum install httpd-utils
aus.
Führen Sie nach der Installation von ab
folgenden Befehl aus, um es auszuführen:
ab -c CONCURRENCY \ -n NUM_REQUESTS \ -t TIMELIMIT \ -p POST_FILE URI
Ersetzen Sie Folgendes:
CONCURRENCY
: Anzahl der nebenläufig auszuführenden AnfragenNUM_REQUESTS
: Anzahl der auszuführenden AnfragenTIMELIMIT
: Maximale Anzahl an Sekunden, die für Anfragen aufgewendet werden sollenPOST_FILE
: Lokale Datei mit der HTTP-POST-NutzlastURI
: Die zu vergleichende URI
Sehen Sie sich folgendes Beispiel an:
ab -c 200 -n 1000000 -t 600 -P body http://10.20.30.40:80
Der Befehl im vorherigen Beispiel sendet Anfragen mit einer Gleichzeitigkeit von 200 (Geschlossen-Schleife-Muster) und wird nach 1.000.000 (oder 1 Million) Anfragen oder 600 Sekunden verstrichener Zeit beendet. Der Befehl enthält auch den Inhalt der Datei body
als HTTP-POST-Nutzlast.
Der Befehl ab
erstellt Antwortlatenz-Histogramme, die denen von Nighthawk ähneln. Die Höchstauflösung ist jedoch Millisekunden statt Mikrosekunden:
Percentage of the requests served within a certain time (ms) 50% 7 66% 7 75% 7 80% 7 90% 92 95% 121 98% 123 99% 127 100% 156 (longest request)