Lasttests mit k6: Skalierbarkeit von Magento-Shops prüfen
AI generated
PASS
expect()
Load Testing · k6
Lasttests mit k6: Skalierbarkeit von Magento-Shops prüfen
Wie ein Grafana-k6-Skript belastbare Aussagen darüber liefert, wie viele gleichzeitige Nutzer ein Magento-Shop tatsächlich verträgt, bevor die Antwortzeiten kippen

Ein funktionaler E2E-Test bestätigt, dass ein Checkout mit einem einzelnen, isolierten Nutzer korrekt abläuft, sagt aber nichts darüber aus, was passiert, wenn zweihundert Nutzerinnen und Nutzer gleichzeitig denselben Checkout durchlaufen. Genau diese Lücke schließt Lasttesting mit k6, einem quelloffenen, skriptbasierten Lasttest-Werkzeug, das realistische, parallele Nutzerlast simuliert und dabei präzise Kennzahlen zu Antwortzeiten, Fehlerraten und Durchsatz liefert, lange bevor ein echter Sale-Ansturm diese Grenzen im Produktivbetrieb schmerzhaft aufdeckt.

16 Min. Lesezeit k6 Load Testing

1. Warum funktionale Tests allein die Skalierbarkeit nicht prüfen

Ein klassischer E2E-Test mit Playwright oder Cypress bestätigt ausschließlich, dass ein einzelner, isolierter Testlauf funktional korrekt durchläuft, trifft aber keinerlei Aussage darüber, wie sich dieselbe Anwendung verhält, wenn hunderte Nutzerinnen und Nutzer gleichzeitig denselben Server, dieselbe Datenbank und dieselben gemeinsam genutzten Ressourcen beanspruchen. Ein Magento-Checkout, der im Einzeltest binnen 800 Millisekunden abschließt, kann unter gleichzeitiger Last durch Datenbank-Locks, ausgeschöpfte Connection-Pools oder überlastete PHP-FPM-Worker-Prozesse auf mehrere Sekunden ansteigen oder komplett fehlschlagen, ein Verhalten, das sich mit funktionalen Einzeltests grundsätzlich nicht sichtbar machen lässt.

Lasttests schließen genau diese Lücke, indem sie gezielt viele gleichzeitige, virtuelle Nutzer simulieren und dabei systematisch messen, ab welchem Lastniveau Antwortzeiten unzumutbar werden oder Fehlerraten ansteigen. Für einen Magento-Shop ist diese Erkenntnis besonders wertvoll vor planbaren Lastspitzen, etwa einem Black-Friday-Sale oder einer großen Marketingkampagne, da sie erlaubt, Kapazitätsgrenzen vorab zu kennen und gezielt zu adressieren, statt sie live unter echtem Kundenandrang schmerzhaft zu entdecken.

k6 hat sich in diesem Umfeld als weit verbreitetes, entwicklerfreundliches Werkzeug etabliert, weil Testskripte in gewöhnlichem JavaScript geschrieben werden, sich damit nahtlos in bestehende Entwicklungs- und CI-Workflows einfügen und ohne eine schwergewichtige, separate Infrastruktur wie bei älteren Lasttest-Werkzeugen auskommen.

2. Grundlagen: virtuelle Nutzer, Iterationen und Stufen

Ein k6-Skript definiert einen Ablauf, der von jedem virtuellen Nutzer (VU) wiederholt ausgeführt wird, während die Konfiguration festlegt, wie viele virtuelle Nutzer gleichzeitig aktiv sind und wie sich diese Anzahl über die Zeit verändert. Über sogenannte Stufen (stages) lässt sich die Last schrittweise erhöhen, auf einem Plateau halten und wieder reduzieren, was ein realistischeres Lastprofil ergibt als eine sprunghafte, konstante Belastung von Beginn an.

Jede Iteration eines virtuellen Nutzers durchläuft dabei typischerweise eine Folge von HTTP-Anfragen, die einen echten Nutzerpfad abbilden, etwa das Aufrufen der Kategorieseite, das Hinzufügen eines Produkts zum Warenkorb und das Absenden der Bestellung, ergänzt um kurze, realistische Denkpausen zwischen den Schritten, damit die simulierte Last nicht künstlich dichter ausfällt als echtes Nutzerverhalten.


import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 50 },   // Hochfahren auf 50 VUs
    { duration: '5m', target: 50 },   // Plateau halten
    { duration: '2m', target: 200 },  // Lastspitze simulieren
    { duration: '3m', target: 200 },
    { duration: '2m', target: 0 },    // Abbau
  ],
};

export default function () {
  const res = http.get('https://shop.example.com/katalog/schuhe.html');
  check(res, {
    'Status ist 200': (r) => r.status === 200,
    'Antwort unter 1500ms': (r) => r.timings.duration < 1500,
  });
  sleep(Math.random() * 3 + 1);
}

3. Ein realistisches Checkout-Szenario als Skript

Der Checkout-Prozess ist für die meisten Magento-Shops das geschäftskritischste Lastziel, da er Datenbank-Schreibzugriffe, Session-Verwaltung und häufig externe Zahlungsdienstleister-Aufrufe kombiniert, also genau jene Komponenten, die unter gleichzeitiger Last am ehesten zum Flaschenhals werden. Ein Lasttest-Skript für den Checkout bildet deshalb typischerweise die vollständige Kette aus Warenkorb befüllen, Versandart wählen, Zahlungsart wählen und Bestellung abschließen ab, statt nur eine einzelne, isolierte Anfrage zu wiederholen.

Wichtig ist dabei, Session-Cookies und CSRF-Tokens korrekt zwischen den einzelnen Anfragen eines virtuellen Nutzers weiterzureichen, da Magento für viele Checkout-Schritte eine gültige, konsistente Session voraussetzt und ein Skript ohne korrekte Session-Weitergabe lediglich Fehlerantworten produziert, die die eigentliche Lastfähigkeit gar nicht abbilden.


import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  scenarios: {
    checkout: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '3m', target: 100 },
        { duration: '5m', target: 100 },
        { duration: '2m', target: 0 },
      ],
    },
  },
  thresholds: {
    http_req_duration: ['p(95)<2000'],
  },
};

export default function () {
  const jar = http.cookieJar();

  const cartPage = http.get('https://shop.example.com/checkout/cart/');
  check(cartPage, { 'Warenkorb geladen': (r) => r.status === 200 });
  sleep(1);

  const shippingRes = http.post(
    'https://shop.example.com/rest/V1/carts/mine/shipping-information',
    JSON.stringify({ addressInformation: { shipping_method_code: 'flatrate' } }),
    { headers: { 'Content-Type': 'application/json' } }
  );
  check(shippingRes, { 'Versand gesetzt': (r) => r.status === 200 });
  sleep(1);

  const orderRes = http.post(
    'https://shop.example.com/rest/V1/carts/mine/payment-information',
    JSON.stringify({ paymentMethod: { method: 'checkmo' } }),
    { headers: { 'Content-Type': 'application/json' } }
  );
  check(orderRes, { 'Bestellung abgeschlossen': (r) => r.status === 200 });
  sleep(2);
}

4. Schwellenwerte mit Thresholds objektiv definieren

Ohne klar definierte Schwellenwerte bleibt die Bewertung eines Lasttest-Ergebnisses subjektiv und angreifbar, da unklar ist, ab welchem Punkt eine gemessene Antwortzeit als "zu langsam" gilt. k6 löst dieses Problem über sogenannte Thresholds, die direkt in der Testkonfiguration festgelegte, objektive Erfolgskriterien darstellen, etwa dass 95 Prozent aller Anfragen unter zwei Sekunden bleiben müssen oder dass die Fehlerrate unter einem Prozent liegen muss.

Verletzt der Testlauf einen definierten Threshold, beendet k6 den Prozess mit einem von null verschiedenen Exit-Code, wodurch sich Lasttests genauso wie funktionale Tests automatisiert in eine CI-Pipeline einbinden lassen: Ein Build gilt erst dann als bestanden, wenn sowohl die funktionalen Tests als auch die definierten Lastschwellenwerte eingehalten wurden, statt Lasttests als reine, manuell interpretierte Zusatzinformation zu behandeln.

5. Integration in die CI-Pipeline

Ein vollständiger Lasttest mit hunderten virtuellen Nutzern über mehrere Minuten Laufzeit gehört selten in jeden einzelnen Pull-Request-Build, da er Zeit und Rechenkapazität beansprucht, die für schnelles Entwickler-Feedback ungeeignet sind. Stattdessen etabliert sich in der Praxis ein gestuftes Modell: Ein kleiner, schneller Smoke-Lasttest mit wenigen virtuellen Nutzern läuft bei jedem Merge in den Hauptzweig, während ein umfassenderer Lasttest mit realistischen Nutzerzahlen täglich oder vor jedem Produktiv-Deployment automatisiert ausgeführt wird.

Für die eigentliche Ausführung in der CI-Pipeline reicht ein einzelner Aufruf der k6-Binärdatei mit dem jeweiligen Skript, dessen Ergebnisse sich zusätzlich als strukturierte JSON- oder InfluxDB-Ausgabe an ein Monitoring-Dashboard weiterreichen lassen, wodurch sich Lasttrends über mehrere Releases hinweg nachvollziehen lassen, statt jedes Testergebnis isoliert zu betrachten.


# .gitlab-ci.yml Ausschnitt
load_test_smoke:
  stage: test
  image: grafana/k6:latest
  script:
    - k6 run --vus 10 --duration 30s tests/load/checkout-smoke.js
  only:
    - merge_requests

load_test_full:
  stage: test
  image: grafana/k6:latest
  script:
    - k6 run --out json=results.json tests/load/checkout-full.js
  artifacts:
    paths:
      - results.json
  only:
    - schedules

6. Typische Lastziele im Magento-Frontend

Neben dem Checkout gehören die Kategorieseiten mit ihrer Layered-Navigation und die Produktsuche zu den lasttechnisch anspruchsvollsten Bereichen eines Magento-Shops, da beide auf teure, dynamische Datenbank-Abfragen beziehungsweise Elasticsearch-Anfragen angewiesen sind, während statische Inhalte wie CMS-Seiten meist vollständig über den Full-Page-Cache oder ein CDN ausgeliefert werden und dadurch unter Last deutlich unkritischer sind.

Für ein Hyvä-Frontend gilt zusätzlich, dass ein Großteil des serverseitig gerenderten HTML bereits beim initialen Seitenaufruf vollständig vorliegt, wodurch sich Lasttests primär auf die Serverantwortzeit und weniger auf clientseitiges JavaScript-Rendering konzentrieren sollten, ein wichtiger Unterschied zu Frontend-Architekturen mit umfangreicher clientseitiger Hydration.

7. Ergebnisse richtig interpretieren

Ein häufiger Interpretationsfehler ist, ausschließlich auf den Durchschnittswert der Antwortzeit zu schauen, da ein guter Durchschnitt problemlos einzelne, aber für echte Nutzer durchaus spürbare Ausreißer verbergen kann. Aussagekräftiger sind Perzentilwerte wie p95 oder p99, die zeigen, wie schlecht die Antwortzeit für die langsamsten fünf beziehungsweise ein Prozent aller Anfragen tatsächlich ausfällt, denn genau diese langsamsten Anfragen prägen die tatsächlich wahrgenommene Nutzererfahrung am stärksten.

Ebenso wichtig ist der Blick auf die Fehlerrate im Zeitverlauf des gesamten Testlaufs: Ein plötzlicher, deutlicher Anstieg fehlgeschlagener Anfragen ab einer bestimmten Anzahl gleichzeitiger virtueller Nutzer markiert häufig den Punkt, an dem eine konkrete, einzelne Ressource, etwa der Datenbank-Connection-Pool oder die maximale Anzahl an PHP-FPM-Workern, tatsächlich ausgeschöpft ist, und liefert damit einen konkreten, umsetzbaren Ansatzpunkt für gezielte Kapazitätsplanung statt vager, schwer belegbarer Vermutungen über die eigentliche Ursache.

8. Verteilte Lastgenerierung für sehr große Nutzerzahlen

Ein einzelner k6-Prozess auf einer einzelnen Maschine stößt irgendwann an physische Grenzen, meist deutlich bevor die zu testende Anwendung selbst überlastet ist, da die Erzeugung tausender gleichzeitiger HTTP-Verbindungen selbst erhebliche CPU- und Netzwerkressourcen auf der Lastgenerator-Seite beansprucht. Für Lasttests mit mehreren tausend virtuellen Nutzern reicht eine einzelne Testmaschine deshalb häufig nicht mehr aus, ohne dass die gemessenen Ergebnisse durch die Kapazitätsgrenzen des Lastgenerators selbst verfälscht werden.

k6 löst dieses Problem über verteilte Ausführung, bei der mehrere k6-Instanzen auf unterschiedlichen Maschinen parallel dasselbe Skript ausführen und ihre Last gemeinsam gegen dieselbe Zielanwendung richten, entweder selbst orchestriert über mehrere Container-Instanzen oder über den kommerziellen k6-Cloud-Dienst, der diese Verteilung automatisch übernimmt. Für die meisten Magento-Shops reicht eine überschaubare Anzahl paralleler Lastgenerator-Instanzen bereits aus, um realistische, mehrere tausend gleichzeitige Nutzer umfassende Sale-Szenarien glaubwürdig nachzubilden, ohne die eigene Testinfrastruktur selbst zum Flaschenhals werden zu lassen.

9. k6-Testarten im Überblick

Die folgende Tabelle vergleicht gängige k6-Testkonfigurationen für unterschiedliche Zwecke.

Testart Typische Konfiguration Zweck
Smoke-Lasttest 5 bis 10 VUs, 30 Sekunden Schneller CI-Check bei jedem Merge
Standard-Lasttest 50 bis 100 VUs, mehrere Minuten Realistische Alltagslast prüfen
Stress-Test Ansteigend bis zum Fehlerpunkt Kapazitätsgrenze ermitteln
Spike-Test Plötzlicher Sprung auf hohe VU-Zahl Sale-Ansturm simulieren

Mironsoft

E2E-Teststrategie, CI-Integration und stabile Testsuiten

Testsuiten, die Bugs finden statt nur rot zu blinken?

Wir prüfen bestehende E2E-Testsuiten auf Flakiness, fehlende Testisolation und ineffiziente CI-Laufzeiten und bauen daraus eine Teststrategie, die tatsächlich Vertrauen schafft statt nur Haken zu setzen.

Test-Audit

Flaky Tests, Testpyramide und Coverage-Lücken systematisch aufdecken.

CI-Optimierung

Parallele Ausführung, Retry-Strategien und schnelle Feedback-Zyklen aufbauen.

Cypress/Playwright-Setup

Robuste E2E-Suiten für Magento-Frontends von Grund auf einrichten.

10. Zusammenfassung

Lasttests mit k6: Das Wichtigste auf einen Blick

Kernidee

k6 simuliert viele gleichzeitige virtuelle Nutzer und misst objektiv, ab wann Antwortzeiten kippen.

Wichtigstes Ziel

Der Magento-Checkout, weil er Datenbank-Schreibzugriffe und Session-Verwaltung kombiniert.

Objektivität

Thresholds definieren feste, automatisiert prüfbare Erfolgskriterien statt subjektiver Einschätzung.

CI-Einbindung

Gestuftes Modell aus schnellem Smoke-Lasttest pro Merge und umfassenderem Test täglich oder vor Deployments.

11. FAQ: Lasttests mit k6: Das Wichtigste auf einen Blick

1Wofür wird k6 typischerweise eingesetzt?
Für skriptbasierte Lasttests, die reale, gleichzeitige Nutzerlast auf eine Anwendung simulieren.
2In welcher Sprache werden k6-Skripte geschrieben?
In gewöhnlichem JavaScript, was die Integration in bestehende Entwicklungs-Workflows erleichtert.
3Was ist ein virtueller Nutzer in k6?
Ein simulierter Client, der wiederholt den im Skript definierten Ablauf durchläuft.
4Wofür dienen Thresholds in k6?
Sie definieren objektive, automatisiert prüfbare Erfolgskriterien wie maximale Antwortzeiten oder Fehlerraten.
5Sollte jeder Pull Request einen vollen Lasttest auslösen?
Nein, ein kleiner Smoke-Lasttest reicht dort, umfassendere Tests laufen täglich oder vor Deployments.
6Warum ist der Checkout das wichtigste Lastziel?
Weil er Datenbank-Schreibzugriffe, Session-Verwaltung und externe Zahlungsdienste kombiniert.
7Warum sind Perzentilwerte aussagekräftiger als der Durchschnitt?
Weil sie zeigen, wie schlecht die langsamsten Anfragen tatsächlich ausfallen, statt Ausreißer zu verbergen.
8Sind statische CMS-Seiten für Lasttests kritisch?
Meist weniger, da sie über Full-Page-Cache oder CDN ausgeliefert werden und Server kaum belasten.
9Was zeigt ein plötzlicher Anstieg der Fehlerrate an?
Häufig eine ausgeschöpfte konkrete Ressource wie den Datenbank-Connection-Pool oder PHP-FPM-Worker.
10Braucht k6 eine eigene, schwergewichtige Infrastruktur?
Nein, die Binärdatei läuft eigenständig und lässt sich direkt in CI-Umgebungen einsetzen.