Denial-of-Service-Angriffe sind eine häufige Ursache für den Ausfall von Onlinediensten. Aber auch Dienste, die nicht Opfer eines gezielten Angriffs sind, können unter der Last zu vieler Anfragen zusammenbrechen. Ein Last- oder Stresstest der von Ihnen administrierten Anwendungen bietet sich an, um eine belastbare Einschätzung zu erhalten, wie widerstandsfähig Ihre Infrastruktur gegen eine Flut von Anfragen ist. Der Security-Tipp stellt mit Locust ein Werkzeug vor, um einen Stresstest für Ihre Dienste in Python zu erstellen.
Verfügbarkeit ist eines der drei prominentesten Schutzziele der IT-Sicherheit. Im Gegensatz zur Verschlüsselung und Integrität, die sich beide mit kryptografischen Verfahren sicherstellen lassen, wird die Verfügbarkeit häufig durch Zugriffskontrolle und Redundanz sichergestellt. Insbesondere die Zugriffskontrolle gestaltet sich für grundsätzlich öffentlich erreichbare Ressourcen jedoch eher schwierig.
Um für den Ernstfall gerüstet zu sein, gilt es, die Leistungsfähigkeit der eigenen Systeme zu ermitteln. So erhalten Sie belastbare Zahlen, wie viele Anfragen Ihre Dienste gut verarbeiten können und ab wann eine Überlastsituation auftritt. Es gibt unterschiedliche Werkzeuge zur Lasterzeugung und in diesem Artikel stellen wir Ihnen mit Locust [1] ein übersichtliches wie mächtiges Werkzeug vor, mit dem Sie eine unglaublich große Menge an Benutzern simulieren können.
Der richtige Zeitpunkt
Natürlich sollten Sie einen Lasttest möglichst nicht gegen ein Produktivsystem einsetzen. Es bietet sich also an, dafür ein Schattensystem mit gleichen Ressourcen, Anbindungen und denselben Softwareversionen laufen zu lassen wie beim Produktivsystem. Wenn Sie bisher kein Schattensystem im Einsatz haben, können Sie bei dessen Erstellung auch gleich die Wiederherstellung aus Ihren aktuellen Backups testen. Bestenfalls erhalten Sie damit in kurzer Zeit ein lauffähiges System und den Beleg, dass Ihre Backups umfassend und schnell verfügbar sind.
Verfügbarkeit ist eines der drei prominentesten Schutzziele der IT-Sicherheit. Im Gegensatz zur Verschlüsselung und Integrität, die sich beide mit kryptografischen Verfahren sicherstellen lassen, wird die Verfügbarkeit häufig durch Zugriffskontrolle und Redundanz sichergestellt. Insbesondere die Zugriffskontrolle gestaltet sich für grundsätzlich öffentlich erreichbare Ressourcen jedoch eher schwierig.
Um für den Ernstfall gerüstet zu sein, gilt es, die Leistungsfähigkeit der eigenen Systeme zu ermitteln. So erhalten Sie belastbare Zahlen, wie viele Anfragen Ihre Dienste gut verarbeiten können und ab wann eine Überlastsituation auftritt. Es gibt unterschiedliche Werkzeuge zur Lasterzeugung und in diesem Artikel stellen wir Ihnen mit Locust [1] ein übersichtliches wie mächtiges Werkzeug vor, mit dem Sie eine unglaublich große Menge an Benutzern simulieren können.
Der richtige Zeitpunkt
Natürlich sollten Sie einen Lasttest möglichst nicht gegen ein Produktivsystem einsetzen. Es bietet sich also an, dafür ein Schattensystem mit gleichen Ressourcen, Anbindungen und denselben Softwareversionen laufen zu lassen wie beim Produktivsystem. Wenn Sie bisher kein Schattensystem im Einsatz haben, können Sie bei dessen Erstellung auch gleich die Wiederherstellung aus Ihren aktuellen Backups testen. Bestenfalls erhalten Sie damit in kurzer Zeit ein lauffähiges System und den Beleg, dass Ihre Backups umfassend und schnell verfügbar sind.
Sollten Sie einen Lasttest gegen ein produktiv eingesetztes System durchführen müssen, eignen sich natürlich besonders die Zeiten, an denen die Anzahl regulärer Anfragen gering ist und möglichst keine Kunden oder Mitarbeiter beeinträchtigt werden. Bereiten Sie Ihren Test bestmöglich vor, so kann er kurz gehalten werden. Reguläre Nutzer sollten Sie so lange auf ein anderes System mit einem Hinweis auf Wartungsarbeiten umleiten. Am einfachsten können Sie dafür DNS verwenden.
Setzen Sie die Time to Live (TTL) Ihrer DNS-Einträge ein bis zwei Tage auf einen sehr kleinen Wert, etwa im einstelligen Minutenbereich, und hinterlegen dann für die Dauer des Tests eine IP-Adresse eines anderen Servers, der entsprechende Informationen für die Benutzer Ihres Dienstes bereitstellt. Nach dem Lasttest überprüfen Sie, dass der Dienst wieder fehlerfrei zur Verfügung steht, und setzen den TTL-Wert wieder zurück.
Locust vorbereiten
Mit Locust (deutsch: Heuschrecke) erhalten Sie ein Werkzeug, das selbst in Python geschrieben ist und sich mit ein wenig Python-Code gut an Ihre Anwendung anpassen lässt. Installieren Sie Locust mit dem folgenden Kommando:
pip3 install locust
Für den ersten Testlauf können Sie nun die Datei "locustfile.py" anlegen und wie in Listing 1 dargestellt vorbereiten. Sie importieren die notwendigen Module "HttpUser" für einen Benutzer, der mittels HTTP auf Ihren Dienst zugreift, und "task" für die Angabe Ihrer definierten Funktionen als durchzuführende Aufgabe beim Lasttest. Erstellen Sie Ihre eigene Klasse "ItaTestUser", die von "HttpUser" erbt, und verwenden Sie in der Funktion "simple_task" die Funktion "get" des HTTP-Clients zum Abfragen der Indexseite eines Dienstes.
Listing 1: locustfile.py
from locust import HttpUser, task
class ItaTestUser(HttpUser):
def simple_task(self):
self.client.get("/")
Hier können Sie beliebige andere Unterseiten Ihres Dienstes hinzufügen. Für unterschiedliche User-Stories sollten Sie unterschiedliche Funktionen anlegen, alle mit dem task-Dekorator. Diese werden im Rahmen des Lasttests zufällig ausgewählt und ausgeführt. Mit "locustfile.py" können Sie nun schon loslegen und den ersten Test beginnen.
Starten Sie nun also mit dem Kommando locust den Locust-Server und verbinden sich mit Ihrem Browser zu der angegebenen Adresse, üblicherweise "http://localhost:8089/". Geben Sie in dem Dialog entsprechend der Abbildung die Parameter für Ihren ersten Test ein. Insbesondere sollten Sie die URL des Dienstes an Ihren eigenen Dienst anpassen.
Klicken Sie nun auf "Start swarming" und schicken Sie Ihren sinnbildlichen Heuschreckenschwarm auf den zu testenden Dienst. Die Webansicht von Locust bietet Statistiken zu den getätigten Aufrufen und unter "Charts" eine fortlaufende Darstellung der Anzahl aktiver User, gleichzeitiger Anfragen und auftretender Fehler. Während Ihre Tests laufen, können Sie die Anzahl der gleichzeitigen User und der neu erstellten User pro Sekunde anpassen und so im Finetuning an die Lastgrenzen Ihrer Systeme gelangen.
Locust verwaltet einen HTTP-Client für jeden gestarteten User. Neben "get" für die Anfrage von Webseiten lässt sich die Funktion "post", wie in Listing 2 gezeigt, verwenden, um etwa eine Registrierung oder einen Login durchzuführen, bevor im Anschluss weitere Anfragen in gültigen Sitzungen angemeldeter Benutzer durchgeführt werden. Steht dieser Login in der Funktion "on_start" Ihrer ItaTest-User-Klasse, wird sie beim Anlegen des Users direkt ausgeführt und fortan alle Anfragen des Users mit der erstellten Sitzung durchgeführt. Die Funktion "on_stop" lässt sich im Gegensatz dazu etwa für das Ausloggen oder den Kassenvorgang des Benutzers eines Shopsystems verwenden. Locust kümmert sich hierbei eigenständig um die Verwaltung der Sitzungs-Cookies.
Damit sich während Ihrer Tests unterschiedliche Benutzer einloggen, können Sie hier etwa mit Pythons Random-Modulen auch ein Array mit Loginkombinationen hinterlegen und zufällig Einträge auswählen.
Gibt es Funktionen in Ihren Anwendungen, die häufiger als andere aufgerufen werden, in einem Shopsystem etwa die Ansicht unterschiedlicher Produkte im Vergleich zum Checkout-Prozess, können Sie dem "@task"-Dekorator ein Gewicht mitgeben. Je höher dieses Gewicht ist, umso häufiger wird die Funktion aufgerufen. Mit dem "@tag"-Dekorator weisen Sie einzelnen Funktionen Tags zu, die Sie beim Start von Locust aus- oder abwählen können. Das erlaubt Ihnen das Erstellen allgemeiner Locust-Konfigurationen für alle Ihre Dienste und die entsprechende Auswahl je nach getestetem Dienst oder Host.
Verteilte Anfragen
Locust erlaubt das Aufteilen der Arbeit auf eine Master- und mehrere Worker-Instanzen. Einem Master werden dabei mehrere Worker-Instanzen zugeordnet. Steht eine gewisse Anzahl an Workern zur Verfügung, startet der Master die vorbereiteten Tasks. Das erlaubt das Einbinden unterschiedlicher Systeme zur Lasterzeugung, die selbst über das Netzwerk miteinander kommunizieren. So können Sie Ihre Loadbalancer sehr einfach aus unterschiedlichen Rechenzentren und damit etwa über unterschiedliche Upstream-Provider unter Last setzen.
Fazit
Mit Locust erstellen Sie in kurzer Zeit Lasttests für Ihre Dienste. Das Erzeugen der Tests in Python erlaubt den Zugriff auf die volle Funktionalität und damit maximale Flexibilität. Sind Ihre eigenen Dienste ebenfalls in Python entwickelt, können Sie auf bestehende Strukturen, Modelle und Funktionen zurückgreifen und Tests noch schneller und umfangreicher durchführen.