Sie haben einen Endpunkt ausgeliefert. Er funktioniert in Ihrem Browser. Aber Sie haben keine Ahnung, was passiert, wenn 400 Leute gleichzeitig darauf zugreifen. Bleibt die Latenz stabil, oder explodiert das neunundneunzigste Perzentil? Hält der Server 1.000 Anfragen pro Sekunde stand, oder bricht er bei 300 zusammen?
wrk beantwortet das. Es ist ein kleines Befehlszeilen-Tool, das viel HTTP-Traffic an eine URL sendet und meldet, wie schnell der Server unter dieser Last reagiert hat.
Was wrk ist und wann man es einsetzt
wrk ist ein modernes HTTP-Benchmarking-Tool. Es erzeugt Last von einem einzigen Multi-Core-Computer und misst die Latenz und Anfragerate, die der Server zurückgibt. Es verwendet Multithreading plus eine skalierbare Event-Schleife (epoll unter Linux, kqueue unter macOS), sodass eine Instanz viel Traffic erzeugen kann, ohne eine Flotte von Lastgeneratoren zu benötigen.
Greifen Sie zu wrk, wenn Sie reine Performance-Zahlen wollen:
- Wie viele Anfragen pro Sekunde kann dieser Endpunkt aufrechterhalten?
- Wie sieht die Latenz im Median im Vergleich zum Tail aus?
- Hält der Server über einen längeren Zeitraum stand, oder verschlechtert er sich nach einer Minute?
wrk ist ein Benchmarking-Tool, keine Testsuite. Es misst die Geschwindigkeit. Es prüft nicht, ob der JSON-Body korrekt ist, ob der Statuscode 200 ist oder ob der API-Vertrag eingehalten wurde. Behalten Sie diesen Unterschied im Hinterkopf. Wir kommen am Ende darauf zurück, da es die Art und Weise verändert, wie Sie wrk in einen echten Test-Workflow einbinden. Wenn Sie zuerst das Gesamtbild wollen, behandelt dieser Leitfaden zum API-Lasttest die Konzepte, die wrk in die Praxis umsetzt.
wrk installieren
macOS
Homebrew hat ein vorgefertigtes Binary, was der Weg des geringsten Widerstands ist:
brew install wrk
Bei Apple Silicon ist das wichtig. Das Bauen aus dem Quellcode kann zu LuaJIT ARM64-Problemen führen, sodass das Homebrew-Binary Ihnen Kopfschmerzen erspart.
Linux (aus dem Quellcode bauen)
Es gibt kein offizielles apt-Paket, daher müssen Sie es selbst bauen. Installieren Sie zuerst die Toolchain und die OpenSSL-Header:
sudo apt-get install build-essential libssl-dev git -y
Dann klonen und kompilieren Sie:
git clone https://github.com/wg/wrk.git
cd wrk
make
Das erzeugt eine wrk-Binary im aktuellen Verzeichnis. Verschieben Sie sie in Ihren PATH, damit Sie sie von überall aufrufen können:
sudo cp wrk /usr/local/bin
Bestätigen Sie, dass es läuft:
wrk --version
Der grundlegende Befehl
So sieht jeder wrk-Lauf aus:
wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html
Vier Dinge passieren. Lassen Sie uns die Flags aufschlüsseln.
-t, --threadslegt die Anzahl der OS-Threads fest, die wrk startet. Ein guter Ausgangspunkt ist ein Thread pro CPU-Kern. Hier sind es 12.-c, --connectionslegt die Gesamtzahl der offenen HTTP-Verbindungen über alle Threads hinweg fest. Hier werden 400 Verbindungen auf die 12 Threads verteilt. Verbindungen simulieren gleichzeitige Clients.-d, --durationlegt fest, wie lange der Test läuft. Akzeptiert Werte wie30s,2moder2h. Hier sind es 30 Sekunden.
Zwei weitere Flags, die Sie ständig verwenden werden:
--latencygibt eine detaillierte Aufschlüsselung der Latenz-Perzentile aus. Schalten Sie dies fast jedes Mal ein. Durchschnittswerte verbergen Tail-Latenz, und der Tail ist normalerweise das, was den Benutzern wehtut.--timeoutregistriert eine Anfrage als abgelaufen, wenn innerhalb des von Ihnen festgelegten Zeitfensters keine Antwort eintrifft, z.B.--timeout 2s. Ohne dies können langsame Antworten Ihre Latenzwerte verfälschen.
Ein Lauf, den Sie oft verwenden werden, sieht so aus:
wrk -t8 -c200 -d30s --latency http://localhost:3000/api/users
Acht Threads, 200 Verbindungen, 30 Sekunden, mit der vollständigen Latenzverteilung am Ende ausgegeben.
Die Ausgabe lesen
wrk gibt einen kompakten Bericht aus. Hier ist ein echter Lauf gegen einen kleinen Dienst:
Running 5s test @ http://10.135.232.163:3000
2 threads and 5 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.82ms 2.64ms 26.68ms 85.81%
Req/Sec 550.90 202.40 0.98k 68.00%
5494 requests in 5.01s, 1.05MB read
Requests/sec: 1096.54
Transfer/sec: 215.24KB
Lesen Sie es von unten nach oben, denn die letzten beiden Zeilen sind die Schlagzeile.
Requests/sec ist der Durchsatz: wie viele Anfragen der Server pro Sekunde im Durchschnitt abgeschlossen hat. Hier sind es 1.096. Dies ist die Zahl, die Sie bei Vergleichen zwischen Läufen und Code-Änderungen verwenden.
Transfer/sec ist die Bandbreite: wie viele Daten pro Sekunde übertragen wurden. Nützlich, wenn die Nutzlasten groß sind oder Sie vermuten, dass Sie bandbreitenbegrenzt statt CPU-begrenzt sind.
Nun die Tabelle Thread Stats, die die Verteilung beschreibt, nicht nur den Durchschnitt:
- Latency-Zeile: Die durchschnittliche Latenz betrug 3,82 ms, aber die Standardabweichung betrug 2,64 ms und das Maximum stieg auf 26,68 ms. Ein hohes Maximum im Verhältnis zum Durchschnitt ist ein Signal. Einige Anfragen sind langsam, auch wenn die meisten schnell sind.
- Req/Sec-Zeile: Die Anfragerate pro Thread, wieder mit ihrer Streuung.
Die Spalte +/- Stdev sagt Ihnen, welcher Prozentsatz der Stichproben innerhalb einer Standardabweichung lag. Kleinere Prozentsätze bedeuten eine breitere, weniger vorhersagbare Streuung.
Die Zeile 5494 requests in 5.01s bestätigt das Gesamtvolumen, das der Lauf tatsächlich erzeugt hat.
Wenn Sie --latency hinzufügen, gibt wrk einen Perzentil-Block aus, damit Sie den Tail direkt sehen können:
Latency Distribution
50% 3.21ms
75% 4.86ms
90% 7.09ms
99% 14.13ms
Das 99. Perzentil ist die Zahl, die man beobachten sollte. Wenn 99 % der Anfragen in 14 ms abgeschlossen sind, aber Ihr Durchschnitt bei 3,82 ms liegt, wartet einer von hundert Benutzern viel länger, als der Durchschnitt vermuten lässt. Durchschnittswerte täuschen über Tails hinweg. Perzentile tun das nicht.
POST-Anfragen und benutzerdefinierte Header mit einem Lua-Skript senden
Standardmäßig sendet wrk GET-Anfragen. Um eine POST-Anfrage zu senden, einen Body hinzuzufügen oder benutzerdefinierte Header festzulegen, übergeben Sie ein Lua-Skript mit -s.
Erstellen Sie eine Datei namens post.lua:
wrk.method = "POST"
wrk.body = '{"name": "Ada", "role": "engineer"}'
wrk.headers["Content-Type"] = "application/json"
Drei Felder erledigen die Arbeit. wrk.method legt das HTTP-Verb fest. wrk.body legt den Anfrage-Body fest. wrk.headers ist eine Tabelle, bei der jeder Schlüssel ein Header-Name ist.
Führen Sie es aus, indem Sie -s auf das Skript verweisen:
wrk -t4 -c100 -d30s -s post.lua --latency http://localhost:3000/api/users
Für eine form-encodierte POST-Anfrage anstelle von JSON liefert das wrk-Repository genau dieses Beispiel:
wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
Sie können Header auch mit dem Flag -H für einfachere Fälle festlegen, ohne ein Skript:
wrk -t4 -c100 -d30s -H "Authorization: Bearer TOKEN123" --latency http://localhost:3000/api/protected
Verwenden Sie -H für ein oder zwei Header. Verwenden Sie ein Lua-Skript, wenn Sie einen Body, eine Nicht-GET-Methode oder eine Logik pro Anfrage benötigen.
Die Grenzen: wrk prüft nicht die Korrektheit
Das ist der Teil, den viele Leute übersehen. wrk sagt Ihnen, wie schnell der Server geantwortet hat. Es sagt Ihnen nicht, ob die Antwort richtig war.
Wenn Sie wrk auf einen Endpunkt richten, der bei jeder Anfrage HTTP 500 zurückgibt, erhalten Sie einen sauber aussehenden Bericht mit einer hohen Anzahl von Anfragen pro Sekunde. wrk zählt einen abgeschlossenen HTTP-Austausch. Es überprüft nicht den Statuscode, validiert den Antwort-Body nicht anhand eines Schemas und bestätigt nicht, dass die API das getan hat, was sie tun sollte. Fehler können sogar schnell aussehen, da ein Server, der Anfragen frühzeitig ablehnt, pro Anfrage weniger Arbeit leistet.
wrk beantwortet also die Frage „Ist es schnell genug unter Last?“. Es kann nicht die Frage „Ist es korrekt?“ beantworten. Beide Fragen sind wichtig und erfordern unterschiedliche Tools. Eine Lastzahl für einen fehlerhaften Endpunkt ist eine Zahl, der Sie nicht vertrauen sollten. Genau deshalb kombinieren Teams ein Benchmarking-Tool mit einer funktionalen Testsuite. Das eine beweist Geschwindigkeit. Das andere beweist Verhalten.
Wo Apidog und funktionale Tests passen
Der saubere Workflow besteht aus zwei Ebenen, die nacheinander ausgeführt werden.
Zuerst, das Verhalten validieren. Bevor Sie sich darum kümmern, wie schnell ein Endpunkt ist, bestätigen Sie, dass er korrekt ist. In Apidog erstellen Sie Testszenarien, die echte Anfragen senden und das Zurückkommende überprüfen: Statuscodes, JSON-Felder, Antwortschema und Geschäftslogik. Sie können Anfragen verketten, Daten zwischen den Schritten übergeben und dasselbe Szenario in verschiedenen Umgebungen ausführen. Dies ist die Ebene, die den fehlerhaften 500er abfängt, den wrk fröhlich benchmarkt.
Dann, den Durchsatz benchmarken. Sobald das Verhalten verifiziert ist, führen Sie wrk gegen dieselben Endpunkte aus, um zu sehen, wie sie unter Gleichzeitigkeit und anhaltender Last bestehen. Apidog verfügt auch über integrierte Leistungstests, wenn Sie funktionale und Lasttests lieber an einem Ort behalten möchten, aber wrk ist ein gutes dediziertes Tool für rohes Befehlszeilen-Benchmarking.
Die funktionale Ebene läuft in CI, nicht nur auf Ihrem Laptop. Die Apidog CLI ist headless, sodass sie in jeden Pipeline-Schritt passt, der Node ausführen kann. Installieren Sie sie:
npm install -g apidog-cli
Führen Sie dann ein gespeichertes Testszenario oder eine Suite anhand der ID aus:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
-t ist die Szenario-, Ordner- oder Suite-ID, die ausgeführt werden soll. -e ist die Umgebungs-ID. -r wählt die Berichtsformate, eines oder mehrere von cli, html, json und junit. Die JUnit-Ausgabe lässt sich direkt in die meisten CI-Systeme zur Pass/Fail-Gating integrieren. Für datengesteuerte Läufe fügen Sie -d (oder --iteration-data) mit einem Dateipfad oder einer Testdaten-ID hinzu, um dasselbe Szenario über viele Eingabezeilen zu iterieren.
Die CLI führt gespeicherte Apidog-Szenarien und -Suites aus. Sie ist headless, kein interaktiver Anfragen-Sender, und sie ist kein Lastgenerator. Sie ist das Korrektheits-Gate. wrk ist die Geschwindigkeitsanzeige. Führen Sie das Korrektheits-Gate in Ihrer Pipeline aus (siehe diese CLI CI/CD-Anleitung oder den GitHub Actions-Leitfaden für Copy-Paste-Konfiguration), und benchmarken Sie dann mit wrk, wenn Sie die Durchsatzzahlen benötigen. Die vollständige CLI-Referenz behandelt den Rest der Flags.
FAQ
Was ist der Unterschied zwischen wrk und ab (ApacheBench)? Beide erzeugen HTTP-Last und melden Anfragen pro Sekunde. wrk ist multithreaded und verwendet eine Event-Schleife, sodass es mehr Last von einem einzigen Rechner erzeugt und hohe Parallelität besser verarbeitet. ab ist single-threaded. Für hohe Last von einem einzigen Rechner skaliert wrk normalerweise weiter. Keines von beiden prüft die Korrektheit der Antwort.
Wie viele Threads und Verbindungen sollte ich verwenden? Beginnen Sie mit einem Thread pro CPU-Kern und stellen Sie die Verbindungen auf das Niveau der Parallelität ein, die Sie simulieren möchten. Wenn Sie 8 Kerne haben und 200 gleichzeitige Clients modellieren möchten, versuchen Sie -t8 -c200. Beobachten Sie den Client-Rechner. Wenn wrk selbst CPU-gebunden ist, spiegeln Ihre Zahlen die Grenze des Lastgenerators wider, nicht die des Servers. Erhöhen Sie die Verbindungen, bis der Durchsatz nicht mehr steigt.
Kann wrk HTTPS-Endpunkte testen? Ja. Richten Sie es auf eine https://-URL, und wrk handhabt TLS. Deshalb benötigt der Linux-Build libssl-dev. TLS-Handshakes verursachen CPU-Kosten an beiden Enden, erwarten Sie also einen geringeren Rohdurchsatz bei HTTPS als bei einfachem HTTP.
Validiert wrk den Antwort-Body oder den Statuscode? Nein. wrk zählt abgeschlossene HTTP-Austausche und misst die Zeit. Es überprüft keine Statuscodes oder Bodys, sodass ein Endpunkt, der Fehler zurückgibt, immer noch eine hohe Anzahl von Anfragen pro Sekunde anzeigen kann. Verwenden Sie eine funktionale Testsuite, wie z.B. eine, die über die Apidog CLI ausgeführt wird, um die Korrektheit zu überprüfen, und verwenden Sie dann wrk für den Durchsatz.
Wie lange sollte ein Lasttest laufen? Lange genug, um Aufwärmeffekte wie kalte Caches und JIT-Kompilierung zu überwinden. Ein paar Sekunden sind gut für einen schnellen Check, aber 30 Sekunden bis einige Minuten liefern stabilere Zahlen und decken Verschlechterungen auf, die nur unter anhaltender Last auftreten. Verwenden Sie -d30s als vernünftigen Standard und verlängern Sie es, wenn Sie langsame Lecks jagen.
