Blog
Wie man ein hochleistungsfähiges, serverloses Abstimmungssystem für weniger als 100 $ erstellt und betreibt

Als frisch zertifizierter AWS Software Developer Associate konnte ich es kaum erwarten, meine neu erworbenen Fähigkeiten in die Praxis umzusetzen. Ich musste nicht lange auf eine Gelegenheit warten. Kurz nachdem ich die Zertifizierungsprüfung bestanden hatte, bat einer meiner Kollegen meinen Freund und mich, an einem kleinen AWS Cloud-Projekt zu arbeiten.
Die Anforderungen schienen einfach. Wir mussten ein hochleistungsfähiges Abstimmungssystem implementieren, das auf den in der AWS Cloud verfügbaren Serverless Services basiert.
Die Herausforderung
Wie bei den meisten dieser Art von Systemen bestand die eigentliche Herausforderung in der "hohen Leistung". Aber was bedeutet es wirklich, dass ein System leistungsstark ist? Nun, das hängt vor allem vom Benutzerverkehr ab, aber auch von der Komplexität des Systems oder dem Budget, das ein Unternehmen ausgeben kann. Lassen Sie uns vor diesem Hintergrund einige der Anforderungen an unsere Lösung definieren. Der Anwendungsfall besteht darin, eine Online-Umfrage vorzubereiten, die in einem bestimmten Abstimmungsfenster verfügbar ist. Die Lösung sollte in der Lage sein, ein hohes Nutzeraufkommen zu bewältigen. In Ihrer Lieblings-Live-Fernsehsendung können die Zuschauer beispielsweise eine bestimmte Zeit lang abstimmen (z.B. 10 Minuten) und nach der Werbepause werden die Ergebnisse präsentiert (siehe Zeitleiste unten).
In Anbetracht all dessen wissen wir jetzt, dass unser System eine große Menge an unregelmäßigem Benutzerverkehr in sehr kurzer Zeit bewältigen muss. In einem solchen Fall wäre eine Vor-Ort-Lösung eine enorme Geldverschwendung, da sie bei geringem Datenverkehr meist ungenutzt bleibt. Lassen Sie uns also überlegen, wie wir dieses Problem mit einem Serverless-Ansatz lösen können.
Architektur
Zunächst müssen wir festlegen, welche Art von Komponenten für das System benötigt werden. Unsere Aufgabe war es, es mit nativen AWS-Komponenten zu bauen, aber in den meisten Fällen gibt es Open-Source-Äquivalente.
Frontend
Aus der Sicht des Benutzers wäre es schön, eine benutzerfreundliche Oberfläche zu haben. Dieser Teil war dank S3 und seiner Funktion, die Bucket als statische Website dient, ziemlich einfach. Laut AWS sollte die Skalierung auch bei hoher Last nahtlos erfolgen. Außerdem zahlen Sie nur für den tatsächlichen Datenverkehr, was bedeutet, dass der Entwicklungsprozess sehr günstig ist. Mit dem Zugang zu allen Gütern der modernen Frontend-Entwicklung hat einer meiner Freunde dann schnell eine einfache einseitige Anwendung in Vue.js erstellt. Lassen Sie mich beschreiben, was diese Anwendung ihren Nutzern zu bieten hat.
Die URL der Anwendung begrüßt den Benutzer mit einem Eingabeformular. Die Ansicht besteht aus dem Logo des Umfrageanbieters, einem Eingabefeld für die eindeutige Benutzerkennung, einer Schaltfläche zum Absenden und einer Countdown-Uhr.
Nach dem Absenden des Formulars leitet die Anwendung den Benutzer zur Frageansicht weiter, die aus demselben Logo wie in der vorherigen Ansicht, einem Fragentext, einer Liste von Antworten und einer weiteren Schaltfläche Absenden besteht. Wenn der Benutzer auf die Schaltfläche Absenden klickt, wird er zu den Ergebnissen der Umfrage weitergeleitet, die alle fünf Sekunden aktualisiert werden, so dass der Benutzer den Status der Umfrage verfolgen kann (Live-Updates werden in einem anderen Teil dieses Artikels behandelt). In unserem Beispiel dauert die Umfrage 10 Minuten, und wir haben zusätzliche 120 Sekunden für die Verarbeitung der nachgereichten Stimmen vorgesehen.
Backend
An dieser Stelle haben wir das Hosting einer Frontend-Anwendung beschrieben. Eine statische Anwendung reicht jedoch für eine Wahlplattform nicht aus.
Das Herzstück des Systems verbirgt sich hinter einem API-Gateway-Dienst. Das API Gateway dient als Proxy für eine der Lambda-Funktionen, die in unserer Lösung verwendet werden (nämlich für eine Lambda-Funktion, die für die Validierung der Stimmen und die Übertragung der Stimmen an den SQS-Dienst zuständig ist). Die Daten-Pipeline-Warteschlange ist aufgrund der Grenzen von DynamoDB entscheidend. Der DynamoDB-Dienst hat einen begrenzten Durchsatz, sowohl beim Lesen als auch beim Schreiben. Glücklicherweise kann der Durchsatz jederzeit geändert werden (z.B. mithilfe des SDK).
Vor diesem Hintergrund haben wir eine Lambda-Funktion namens Orchestrator eingeführt, die für die Überprüfung des aktuellen Warteschlangenstatus und die Skalierung des Datenbankdurchsatzes proportional zur Anzahl der Nachrichten in der Warteschlange verantwortlich ist. Außerdem ist der Orchestrator nach der erfolgreichen Skalierung von DynamoDB dafür verantwortlich, Kindprozesse in Form von Worker-Lambda-Funktionen zu erzeugen. Die Anzahl dieser Prozesse sollte ebenfalls proportional zur Anzahl der aktuell in der Warteschlange verfügbaren Nachrichten sein, um alle Abstimmungen so schnell wie möglich zu verarbeiten. Die Logik der Worker-Lambda-Funktionen ist einfach. Wenn der Prozess erstellt wird, holt er Nachrichten aus SQS, versucht, sie an DynamoDB zu übertragen und entfernt sie im Erfolgsfall aus der Warteschlange. Wenn die Übertragung der Nachrichten an die Datenbank fehlschlägt, schlägt auch die Lambda-Funktion fehl und die Nachrichten kehren in die Warteschlange zurück - bereit, von einem anderen Worker verarbeitet zu werden. Das folgende Diagramm zeigt dieses System.
Das Diagramm zeigt ein Element des Systems, das noch nicht besprochen wurde. Es gibt noch eine weitere Lambda-Funktion zwischen DynamoDB und S3-Bucket. Diese Funktion ist für die bereits erwähnten Live-Aktualisierungen der Umfrageergebnisse verantwortlich. Sie fragt DynamoDB in einer Schleife ab und überträgt die Ergebnisse an den S3-Bucket. Dann liest ein Ajax-Aufruf die Ergebnisse aus dem Bucket und aktualisiert das Diagramm.
Natürlich müssen der Orchestrator-Lambda und der oben erwähnte Lambda durch irgendetwas ausgelöst werden, damit sie Ergebnisse abrufen können. Der Einfachheit halber haben wir uns für Amazon CloudWatch entschieden - es löst jede Minute Lambda-Funktionen aus.
Testen Sie
Okay, an diesem Punkt haben wir also unser Abstimmungssystem implementiert und in der AWS Cloud verfügbar. Jetzt müssen wir nur noch prüfen, ob es als hochleistungsfähig angesehen werden kann.
Es ist auch erwähnenswert, dass uns der Entwicklungsprozess bis zu diesem Moment weniger als 1,00 $ gekostet hat!
Um den Datenverkehr zu simulieren, haben wir die Locust-Performance-Testing-Bibliothek verwendet, da sie über eine benutzerfreundliche Python-API verfügt. Eine einzelne t2.micro EC2 mit einer CPU und 1 GB Arbeitsspeicher war in der Lage, mehr als 250.000 Anfragen in einem 10-Minuten-Fenster zu senden. Wir beschlossen, ein AMI mit einem zuvor vorbereiteten Testskript zu erstellen. Das Skript arbeitete als Daemon und sendete ständig vordefinierte Anfragen an die angegebene URL des API Gateway. Mit dem AMI konnten wir die Lösung einem Stresstest unterziehen, indem wir mehrere Instanzen von EC2-Maschinen starteten. Wir waren bereit zum Testen!
Wir begannen mit einem einzigen Rechner. In der ersten Iteration wollten wir eine Autoskalierungsfunktion von DynamoDB nutzen. Das hat jedoch nicht funktioniert. Eine massive Durchsatzspitze wurde gedrosselt und nach einer Weile erhielten wir eine Provisioned Throughput Exception. Dann, nach etwa 10 Minuten, stellten wir fest, dass die Datenbank skaliert wurde. Siehe den Screenshot unten.
Dieses Problem muss auf jeden Fall genauer untersucht werden, aber wir haben beschlossen, die automatische Skalierung zu überspringen und den Lambda-Orchestrator mit einer manuellen Skalierung zu versehen. Auf diese Weise konnten wir mit den Tests fortfahren.
Nachdem wir das Skalierungsproblem gelöst hatten, schienen die DynamoDB-Tests mit einem einzigen Rechner in Ordnung zu sein. Wir entschieden uns für den großen Wurf! Zehn EC2-Instanzen, die 4.000 Anfragen pro Sekunde senden. Und dann stießen wir auf ein weiteres Hindernis... Genauer gesagt, auf das Limit der gleichzeitigen Lambda-Funktionen in der AWS-Region. Der Standardwert ist 1000, was bedeutet, dass wir nur 1000 gleichzeitig laufende Lambda-Funktionen in einer einzigen AWS-Region haben können. Dieses Limit kann jedoch erhöht werden. Alles, was Sie tun müssen, ist, einen AWS Cloud-Anbieter zu kontaktieren, Ihr Vorhaben zu beschreiben und zu warten. Wir haben eine Anfrage gestellt und wurden am nächsten Tag gebeten, einige zusätzliche Informationen wie die durchschnittliche Zeit eines Lambda-Laufs oder Informationen über die durchschnittliche Speichernutzung zu liefern. Wir schickten eine weitere Anfrage, aber gleichzeitig beschlossen wir, das System mit zwei EC2-Instanzen zu testen.
Das offene Abstimmungsfenster schien zu Beginn in Ordnung zu sein. Das Interessante passiert etwa 5 Minuten später - alle Umfrageleisten frieren ein. Das Problem ist die bereits erwähnte Begrenzung der gleichzeitigen Lambda-Funktionen. Die Funktion, die für die Aktualisierung der Ergebnisse zuständig ist, kann nicht starten, da eine Reihe von Lambda-Funktionen gleichzeitig ausgeführt werden. Nach einiger Zeit werden die Ergebnisse schließlich aktualisiert, aber das ruiniert das Erlebnis. Darüber hinaus schafft es das System aufgrund einer begrenzten Anzahl von laufenden Workern kaum, alle Stimmen rechtzeitig zu zählen. Der größte Teil dieses Limits wird von Lambda-Funktionen genutzt, die direkt mit dem API Gateway verbunden sind. Eine eingehende Anfrage bedeutet einen Lambda-Aufruf. An diesem Punkt sind weitere Tests also sinnlos, es sei denn, das Limit wird erhöht. Ich will damit nicht sagen, dass wir die Lösung nicht verbessern können; aber dazu später mehr.
Kosten
Wie bereits erwähnt, kostet der Entwicklungsprozess weniger als 1 $. Die Kosten für den Betrieb von EC2-Instanzen für Tests sind ebenfalls vernachlässigbar. Die Gesamtkosten beliefen sich auf $76. Um zu analysieren, woher diese Zahl stammt, muss man wissen, dass wir mehrere Millionen Anfragen gesendet haben. Das API Gateway erwies sich als der teuerste Teil des Systems, denn es kostete 32 $. DynamoDB lag mit 12 $ an zweiter Stelle und AWS Lambda mit 8 $ an dritter Stelle.
Gelernte Lektionen
Wie immer, wenn man etwas fertiggestellt hat, kann man leicht auf die Teile hinweisen, die man hätte verbessern können. Dieses Projekt bildet da keine Ausnahme. Uns ist aufgefallen, dass es eine gute Idee gewesen wäre, das API Gateway zu entfernen und die Validierung der Stimmabgabe in die Worker zu verlagern. Die Stimmabgabe hätte von einer statischen Website direkt an SQS gesendet werden können. Bestimmte Berechtigungen hätten über den Cognito-Dienst eingeholt werden können. Auf diese Weise wären wir in der Lage gewesen, die meisten Lambda-Funktionen als Worker zu verwenden. Es ist jedoch nicht auszuschließen, dass wir alle oben genannten Verbesserungen durchführen und in naher Zukunft einen Folgeartikel veröffentlichen werden.
Fazit
Die AWS-Plattform ist eine sehr entwicklerfreundliche Arbeitsumgebung. Sie bietet eine große Anzahl von Diensten, die sich problemlos in verschiedene Lösungen integrieren lassen. Die serverlose Architektur ist definitiv einen Versuch wert. Sie zahlen nur für das, was Sie tatsächlich nutzen, was bedeutet, dass der Entwicklungsprozess wirklich kostengünstig ist. Sie können ganz einfach klein anfangen und wenn das Projekt und die Zahl der Kunden wächst, werden Ihre Rechnungen proportional dazu steigen.
Der Serverless-Ansatz hat allerdings auch einige Nachteile. Lösungsarchitekten müssen mit den Diensten, die sie übernehmen wollen, vertraut sein. Dieses Wissen ist entscheidend, um unerwartete Blockaden in der Mitte des Implementierungsprozesses zu vermeiden. Außerdem ist es schwierig, eine solche Lösung so zu entwickeln, dass sie völlig unabhängig von einem bestimmten Cloud-Plattform-Anbieter ist - und die Entwicklung von Lösungen, die auf mehr als einer Cloud-Plattform eingesetzt werden können, ist keine leichte Aufgabe.
Zusammenfassend lässt sich sagen, dass die Wahl einer Serverless-Architektur für das Wahlsystem die beste Lösung zu sein scheint - Sie müssen nicht in teure Hardware investieren, die Systeme skalieren automatisch und der Entwicklungsprozess ist kostengünstig, da Sie nur für das bezahlen, was Sie tatsächlich nutzen.
Unsere Ideen
Weitere Blogs
Contact



