Lastprüfung mit Heuschrecke

Lasttests sind nicht so gefragt und weit verbreitet wie andere Testarten - es gibt nicht so viele Tools, mit denen Sie solche Tests durchführen können, aber einfache und bequeme Tests können im Allgemeinen an den Fingern einer Hand gezählt werden.

Wenn es um Leistungstests geht - zunächst einmal denkt jeder an JMeter -, bleibt es zweifellos das bekannteste Tool mit der größten Anzahl von Plugins. Ich habe JMeter wegen seiner nicht offensichtlichen Benutzeroberfläche und der hohen Einstiegsschwelle nie gemocht, sobald es notwendig wird, eine Nicht-Hello World-Anwendung zu testen.

Und jetzt, inspiriert vom Erfolg des Testens in zwei verschiedenen Projekten, beschloss ich, Informationen über eine relativ einfache und bequeme Software - Locust - auszutauschen

Für diejenigen, die zu faul sind, um unter den Schnitt zu gehen, habe ich ein Video aufgenommen:



Was ist das?


Open-Source-Tool, mit dem Sie Ladeszenarien mit Python-Code angeben können, der verteiltes Laden unterstützt und, wie die Autoren behaupten, für Lasttests von Battlelog für eine Reihe von Battlefild-Spielen verwendet wurde (sofort fesselnd)

Von den Profis:

  • einfache Dokumentation inklusive Copy-Paste-Beispiel. Sie können mit dem Testen beginnen, auch ohne Programmierkenntnisse.
  • "Under the Hood" verwendet die Anforderungsbibliothek (HTTP für Personen). Die Dokumentation kann als erweiterter Spickzettel und Lastschrifttest verwendet werden
  • Python-Unterstützung - Ich mag nur die Sprache
  • Der vorherige Absatz enthält eine plattformübergreifende Funktion zum Ausführen von Tests
  • Eigener Flask -Webserver zur Anzeige von Testergebnissen

Von den Minuspunkten:

  • Kein Capture & Replay - alle Hände
  • Das Ergebnis des vorherigen Absatzes - Sie brauchen ein Gehirn. Wie bei Postman müssen Sie verstehen, wie HTTP funktioniert.
  • Minimale Programmierkenntnisse erforderlich
  • Lineares Lastmodell - das die Fans sofort aufregt, Benutzer „nach Gauß“ zu generieren

Testprozess


Jedes Testen ist eine komplexe Aufgabe, die die Planung, Vorbereitung, Überwachung der Implementierung und Analyse der Ergebnisse erfordert. Wenn möglich, ist es bei Stresstests möglich und notwendig, alle möglichen Daten zu sammeln, die das Ergebnis beeinflussen können:

  • Serverhardware (CPU, RAM, ROM)
  • Serversoftware (Betriebssystem, Serverversion, JAVA, .NET usw., Datenbank und Datenmenge selbst, Server- und Testanwendungsprotokolle)
  • Netzwerkbandbreite
  • Das Vorhandensein von Proxyservern, Load Balancern und DDOS-Schutz
  • Testdaten laden (Anzahl der Benutzer, durchschnittliche Antwortzeit, Anzahl der Anforderungen pro Sekunde)

Die nachfolgend beschriebenen Beispiele können als Black-Box-Funktionslasttests klassifiziert werden. Auch ohne etwas über die zu testende Anwendung zu wissen und ohne Zugriff auf die Protokolle können wir deren Leistung messen.

Bevor Sie anfangen


Um Lasttests in der Praxis zu testen, habe ich einen lokal einfachen Webserver https://github.com/typicode/json-server bereitgestellt. Ich werde fast alle der folgenden Beispiele für ihn geben. Ich habe die Daten für den Server einem bereitgestellten Online-Beispiel entnommen - https://jsonplaceholder.typicode.com/
Zum Ausführen ist nodeJS erforderlich.

Offensichtlicher Spoiler : Wie bei Sicherheitstests ist es besser, Experimente mit Stresstests an Katzen vor Ort durchzuführen, ohne Online-Dienste zu laden, damit Sie nicht gebannt werden

Zum Starten ist auch Python erforderlich - in allen Beispielen verwende ich Version 3.6 sowie Locust selbst (zum Zeitpunkt des Schreibens Version 0.9.0). Es kann mit dem Befehl installiert werden

python -m pip install locustio 

Installationsdetails finden Sie in der offiziellen Dokumentation.

Ein Beispiel analysieren


Als nächstes brauchen wir eine Testdatei. Ich habe ein Beispiel aus der Dokumentation genommen, da es sehr einfach und unkompliziert ist:

 from locust import HttpLocust, TaskSet def login(l): l.client.post("/login", {"username":"ellen_key", "password":"education"}) def logout(l): l.client.post("/logout", {"username":"ellen_key", "password":"education"}) def index(l): l.client.get("/") def profile(l): l.client.get("/profile") class UserBehavior(TaskSet): tasks = {index: 2, profile: 1} def on_start(self): login(self) def on_stop(self): logout(self) class WebsiteUser(HttpLocust): task_set = UserBehavior min_wait = 5000 max_wait = 9000 

Das ist alles! Dies ist wirklich genug, um den Test zu starten! Schauen wir uns ein Beispiel an, bevor wir anfangen.

Beim Überspringen von Importen sehen wir ganz am Anfang zwei nahezu identische Anmelde- und Abmeldefunktionen, die aus einer Zeile bestehen. l.client - ein HTTP-Sitzungsobjekt, mit dem wir eine Last erstellen. Wir verwenden die POST-Methode, die fast identisch mit der in der Anforderungsbibliothek ist. Fast - weil wir in diesem Beispiel als erstes Argument keine vollständige URL, sondern nur einen Teil davon übergeben - einen bestimmten Dienst.

Das zweite Argument übergibt die Daten - und ich kann nicht anders, als zu bemerken, dass es sehr praktisch ist, Python-Wörterbücher zu verwenden, die automatisch in json konvertiert werden

Sie können auch feststellen, dass wir das Ergebnis der Anfrage in keiner Weise verarbeiten. Wenn dies erfolgreich ist, werden die Ergebnisse (z. B. Cookies) in dieser Sitzung gespeichert. Wenn ein Fehler auftritt, wird er aufgezeichnet und der Statistik über die Last hinzugefügt.

Wenn wir wissen möchten, ob wir die Anfrage richtig geschrieben haben, können wir sie jederzeit wie folgt überprüfen:

 import requests as r response=r.post(base_url+"/login",{"username":"ellen_key","password":"education"}) print(response.status_code) 

Ich habe nur die Variable base_url hinzugefügt, die die vollständige Adresse der zu testenden Ressource enthalten sollte.

Die nächsten Funktionen sind Abfragen, die eine Last erzeugen. Auch hier müssen wir die Serverantwort nicht verarbeiten - die Ergebnisse werden sofort in die Statistik übernommen.

Als nächstes folgt die UserBehavior- Klasse (der Name der Klasse kann beliebig sein). Wie der Name schon sagt, wird das Verhalten eines sphärischen Benutzers im Vakuum der zu testenden Anwendung beschrieben. Wir übergeben an die Task- Eigenschaft ein Wörterbuch mit Methoden, die der Benutzer aufruft, und deren Häufigkeit. Obwohl wir nicht wissen, welche Funktion und in welcher Reihenfolge jeder Benutzer aufruft - sie werden zufällig ausgewählt -, garantieren wir, dass die Indexfunktion im Durchschnitt zweimal häufiger aufgerufen wird als die Profilfunktion .

Zusätzlich zum Verhalten können Sie in der übergeordneten Klasse TaskSet 4 Funktionen angeben, die vor und nach den Tests ausgeführt werden können. Die Reihenfolge der Anrufe ist wie folgt:

  1. setup - wird zu Beginn von UserBehavior (TaskSet) einmal aufgerufen - ist nicht im Beispiel enthalten
  2. on_start - wird von jedem neuen Benutzer der Last beim Start einmal aufgerufen
  3. Aufgaben - Ausführung der Aufgaben selbst
  4. on_stop - wird von jedem Benutzer einmal aufgerufen, wenn der Test beendet ist
  5. Teardown - wird beim Beenden des TaskSet einmal aufgerufen - ist auch nicht im Beispiel enthalten

Erwähnenswert ist hier, dass es zwei Möglichkeiten gibt, das Benutzerverhalten zu deklarieren: Die erste ist bereits im obigen Beispiel angegeben - Funktionen werden im Voraus angekündigt. Die zweite Möglichkeit besteht darin, Methoden direkt in der UserBehavior- Klasse zu deklarieren:

 from locust import HttpLocust, TaskSet, task class UserBehavior(TaskSet): def on_start(self): self.client.post("/login", {"username":"ellen_key", "password":"education"}) def on_stop(self): self.client.post("/logout", {"username":"ellen_key", "password":"education"}) @task(2) def index(self): self.client.get("/") @task(1) def profile(self): self.client.get("/profile") class WebsiteUser(HttpLocust): task_set = UserBehavior min_wait = 5000 max_wait = 9000 

In diesem Beispiel werden Benutzerfunktionen und die Häufigkeit ihres Anrufs mithilfe der Aufgabenanmerkung festgelegt . Funktionell hat sich nichts geändert.

Die letzte Klasse aus dem Beispiel ist WebsiteUser (der Name der Klasse kann beliebig sein). In dieser Klasse definieren wir das Benutzerverhaltensmodell UserBehavior *** + sowie die minimalen und maximalen Wartezeiten zwischen Aufrufen einzelner Aufgaben durch jeden Benutzer. Um es klarer zu machen, gehen Sie wie folgt vor, um es zu visualisieren:



Erste Schritte


Führen Sie den Server aus, dessen Leistung wir testen werden:

 json-server --watch sample_server/db.json 

Wir ändern auch die Beispieldatei, damit sie den Dienst testen, die An- und Abmeldung entfernen und das Benutzerverhalten festlegen kann:

  1. Öffnen Sie die Hauptseite 1 Mal zu Beginn der Arbeit
  2. Holen Sie sich eine Liste aller x2 Beiträge
  3. Schreibe einen Kommentar zum ersten Beitrag x1

 from locust import HttpLocust, TaskSet, task class UserBehavior(TaskSet): def on_start(self): self.client.get("/") @task(2) def posts(self): self.client.get("/posts") @task(1) def comment(self): data = { "postId": 1, "name": "my comment", "email": "test@user.habr", "body": "Author is cool. Some text. Hello world!" } self.client.post("/comments", data) class WebsiteUser(HttpLocust): task_set = UserBehavior min_wait = 1000 max_wait = 2000 

Führen Sie den Befehl aus, um an der Eingabeaufforderung zu beginnen

 locust -f my_locust_file.py --host=http://localhost:3000 

Dabei ist Host die Adresse der getesteten Ressource. Ihm werden die im Test angegebenen Serviceadressen hinzugefügt.

Wenn der Test keine Fehler enthält, wird der Ladeserver gestartet und ist unter http: // localhost: 8089 / verfügbar.



Wie Sie sehen können, wird hier der Server angezeigt, den wir testen werden. Unter dieser URL werden die Adressen der Dienste aus der Testdatei hinzugefügt.

Auch hier können wir die Anzahl der Benutzer für die Last und deren Wachstum pro Sekunde angeben.
Auf den Button starten wir den Ladevorgang!



Ergebnisse


Nach einer gewissen Zeit beenden wir den Test und sehen uns die ersten Ergebnisse an:

  1. Wie erwartet ging jeder der 10 zu Beginn erstellten Benutzer zur Hauptseite
  2. Die Liste der Beiträge wurde im Durchschnitt zweimal häufiger geöffnet als ein Kommentar geschrieben wurde
  3. Es gibt eine durchschnittliche und mittlere Antwortzeit für jede Operation. Die Anzahl der Operationen pro Sekunde ist bereits ein nützliches Datenelement, obwohl Sie es jetzt nehmen und mit dem erwarteten Ergebnis aus den Anforderungen vergleichen

Auf der zweiten Registerkarte können Sie die Lastdiagramme in Echtzeit anzeigen. Wenn der Server bei einer bestimmten Last abstürzt oder sich sein Verhalten ändert, wird dies sofort in der Grafik angezeigt.



Auf der dritten Registerkarte sehen Sie die Fehler - in meinem Fall handelt es sich um einen Clientfehler. Wenn der Server jedoch einen 4XX- oder 5XX-Fehler zurückgibt, wird sein Text hier geschrieben
Wenn im Code Ihres Textes ein Fehler auftritt, fällt dieser in die Registerkarte Ausnahmen. Bisher habe ich den häufigsten Fehler im Zusammenhang mit der Verwendung des Befehls print () im Code - dies ist nicht die beste Methode zum Protokollieren :)

Auf der letzten Registerkarte können Sie alle Testergebnisse im CSV-Format herunterladen

Sind diese Ergebnisse relevant? Lass es uns herausfinden. In den meisten Fällen klingen die Leistungsanforderungen (falls überhaupt angegeben) ungefähr so: Die durchschnittliche Ladezeit der Seite (Serverantwort) sollte bei einer Last von M Benutzern weniger als N Sekunden betragen. Nicht wirklich spezifizieren, was Benutzer tun sollen. Und ich mag Locust dafür - es erzeugt Aktivitäten einer bestimmten Anzahl von Benutzern, die zufällig die erwarteten Aktionen ausführen, die sie von Benutzern erwarten.

Wenn wir einen Benchmark durchführen müssen, um das Verhalten des Systems bei verschiedenen Lasten zu messen, können wir mehrere Verhaltensklassen erstellen und mehrere Tests bei verschiedenen Lasten durchführen.

Das reicht für den Anfang. Wenn Ihnen der Artikel gefallen hat, habe ich vor, darüber zu schreiben:

  • komplexe Testszenarien, in denen die Ergebnisse eines Schritts im Folgenden verwendet werden
  • Serverantwortverarbeitung, as Es kann falsch sein, auch wenn HTTP 200 OK angekommen ist
  • nicht offensichtliche Schwierigkeiten, die auftreten können, und wie man sie umgeht
  • Testen ohne Verwendung der Benutzeroberfläche
  • verteilte Lasttests

Source: https://habr.com/ru/post/de430502/


All Articles