Jenseits des Browsers: Erste Schritte mit serverlosem WebAssembly
Veröffentlicht: 2022-03-10Jetzt, da WebAssembly von allen gängigen Browsern und mehr als 85 % der Benutzer weltweit unterstützt wird, ist JavaScript nicht mehr die einzige Browsersprache in der Stadt. Falls Sie es noch nicht gehört haben: WebAssembly ist eine neue Low-Level-Sprache, die im Browser ausgeführt wird. Es ist auch ein Kompilierungsziel, was bedeutet, dass Sie vorhandene Programme, die in Sprachen wie C, C++ und Rust geschrieben wurden, in WebAssembly kompilieren und diese Programme im Browser ausführen können. Bisher wurde WebAssembly verwendet, um alle Arten von Anwendungen ins Web zu portieren, einschließlich Desktop-Anwendungen, Befehlszeilentools, Spiele und Data-Science-Tools.
Hinweis: Eine ausführliche Fallstudie darüber, wie WebAssembly im Browser verwendet werden kann, um Webanwendungen zu beschleunigen, finden Sie in meinem vorherigen Artikel.
WebAssembly außerhalb des Webs?
Obwohl die meisten WebAssembly-Anwendungen heute browserzentriert sind, wurde WebAssembly selbst ursprünglich nicht nur für das Web entwickelt, sondern wirklich für jede Sandbox-Umgebung. Tatsächlich gab es in letzter Zeit großes Interesse daran, zu untersuchen, wie WebAssembly außerhalb des Browsers als allgemeiner Ansatz zum Ausführen von Binärdateien auf jedem Betriebssystem oder jeder Computerarchitektur nützlich sein könnte, solange es eine WebAssembly-Laufzeitumgebung gibt, die dieses System unterstützt. In diesem Artikel sehen wir uns an, wie WebAssembly außerhalb des Browsers serverlos/Function-as-a-Service (FaaS) ausgeführt werden kann.
WebAssembly für serverlose Anwendungen
Kurz gesagt, serverlose Funktionen sind ein Computermodell, bei dem Sie Ihren Code an einen Cloud-Anbieter übergeben und ihn ausführen und die Skalierung dieses Codes für Sie verwalten lassen. Sie können beispielsweise verlangen, dass Ihre serverlose Funktion immer dann ausgeführt wird, wenn Sie einen API-Endpunkt aufrufen, oder dass sie von Ereignissen gesteuert wird, z. B. wenn eine Datei in Ihren Cloud-Bucket hochgeladen wird. Während der Begriff „serverlos“ wie eine Fehlbezeichnung erscheinen mag, da Server eindeutig irgendwo auf dem Weg beteiligt sind, ist es aus unserer Sicht serverlos, da wir uns keine Gedanken darüber machen müssen, wie diese Server verwaltet, bereitgestellt oder skaliert werden.
Obwohl diese Funktionen normalerweise in Sprachen wie Python und JavaScript (Node.js) geschrieben sind, gibt es eine Reihe von Gründen, warum Sie sich stattdessen für die Verwendung von WebAssembly entscheiden könnten:
- Schnellere Initialisierungszeiten
Serverlose Anbieter, die WebAssembly unterstützen (einschließlich Cloudflare und Fastly, berichten, dass sie Funktionen mindestens eine Größenordnung schneller starten können als die meisten Cloud-Anbieter mit anderen Sprachen. Sie erreichen dies, indem sie Zehntausende von WebAssembly-Modulen im selben Prozess ausführen, das heißt möglich, da die Sandbox-Natur von WebAssembly eine effizientere Möglichkeit bietet, die Isolierung zu erreichen, für die Container traditionell verwendet werden. - Keine Umschreibungen erforderlich
Einer der Hauptvorteile von WebAssembly im Browser ist die Möglichkeit, bestehenden Code ins Web zu portieren, ohne alles in JavaScript umschreiben zu müssen. Dieser Vorteil gilt auch im serverlosen Anwendungsfall, da Cloud-Anbieter einschränken, in welchen Sprachen Sie Ihre serverlosen Funktionen schreiben können. Normalerweise unterstützen sie Python, Node.js und vielleicht einige andere, aber sicherlich nicht C, C++ oder Rust . Durch die Unterstützung von WebAssembly können serverlose Anbieter indirekt viel mehr Sprachen unterstützen. - Leichter
Wenn wir WebAssembly im Browser ausführen, verlassen wir uns auf den Computer des Endbenutzers, um unsere Berechnungen durchzuführen. Wenn diese Berechnungen zu intensiv sind, werden unsere Benutzer nicht glücklich sein, wenn ihr Computerlüfter zu surren beginnt. Das Ausführen von WebAssembly außerhalb des Browsers bietet uns die Geschwindigkeits- und Portabilitätsvorteile von WebAssembly, während unsere Anwendung gleichzeitig leichtgewichtig bleibt. Da wir unseren WebAssembly-Code in einer besser vorhersagbaren Umgebung ausführen, können wir darüber hinaus potenziell intensivere Berechnungen durchführen.
Ein konkretes Beispiel
In meinem vorherigen Artikel hier im Smashing Magazine haben wir besprochen, wie wir eine Webanwendung beschleunigt haben, indem wir langsame JavaScript-Berechnungen durch C-Code ersetzt haben, der in WebAssembly kompiliert wurde. Die fragliche Web-App war fastq.bio, ein Tool zur Vorschau der Qualität von DNA-Sequenzierungsdaten.
Lassen Sie uns als konkretes Beispiel fastq.bio in eine Anwendung umschreiben, die serverloses WebAssembly verwendet, anstatt WebAssembly im Browser auszuführen. Für diesen Artikel verwenden wir Cloudflare Workers, einen serverlosen Anbieter, der WebAssembly unterstützt und auf der V8-Browser-Engine aufbaut. Ein anderer Cloud-Anbieter, Fastly, arbeitet an einem ähnlichen Angebot, jedoch basierend auf seiner Lucet-Laufzeit.
Lassen Sie uns zunächst etwas Rust-Code schreiben, um die Datenqualität von DNA-Sequenzierungsdaten zu analysieren. Der Einfachheit halber können wir die Rust-Bio-Bioinformatikbibliothek nutzen, um das Parsen der Eingabedaten zu handhaben, und die wasm-bindgen-Bibliothek, die uns hilft, unseren Rust-Code für WebAssembly zu kompilieren.
Hier ist ein Ausschnitt des Codes, der DNA-Sequenzierungsdaten einliest und einen JSON mit einer Zusammenfassung der Qualitätsmetriken ausgibt:
// Import packages extern crate wasm_bindgen; use bio::seq_analysis::gc; use bio::io::fastq; ... // This "wasm_bindgen" tag lets us denote the functions // we want to expose in our WebAssembly module #[wasm_bindgen] pub fn fastq_metrics(seq: String) -> String { ... // Loop through lines in the file let reader = fastq::Reader::new(seq.as_bytes()); for result in reader.records() { let record = result.unwrap(); let sequence = record.seq(); // Calculate simple statistics on each record n_reads += 1.0; let read_length = sequence.len(); let read_gc = gc::gc_content(sequence); // We want to draw histograms of these values // so we store their values for later plotting hist_gc.push(read_gc * 100.0); hist_len.push(read_length); ... } // Return statistics as a JSON blob json!({ "n": n_reads, "hist": { "gc": hist_gc, "len": hist_len }, ... }).to_string() }
Wir haben dann das Wrangler-Befehlszeilentool von Cloudflare verwendet, um die schwere Arbeit der Kompilierung in WebAssembly und der Bereitstellung in der Cloud zu erledigen. Sobald dies erledigt ist, erhalten wir einen API-Endpunkt, der Sequenzierungsdaten als Eingabe verwendet und ein JSON mit Datenqualitätsmetriken zurückgibt. Wir können diese API jetzt in unsere Anwendung integrieren.
Hier ist ein GIF der Anwendung in Aktion:
Der vollständige Code ist auf GitHub (Open Source) verfügbar.
Alles in Kontext setzen
Um den serverlosen WebAssembly-Ansatz in einen Kontext zu stellen, betrachten wir vier Hauptwege, auf denen wir Datenverarbeitungs-Webanwendungen erstellen können (d. h. Web-Apps, bei denen wir Analysen der vom Benutzer bereitgestellten Daten durchführen):
Wie oben dargestellt, kann die Datenverarbeitung an mehreren Stellen erfolgen:
- Serverseitig
Dies ist der Ansatz, der von den meisten Webanwendungen gewählt wird, bei denen API-Aufrufe im Front-End die Datenverarbeitung im Back-End starten. - Clientseitiges JavaScript
Bei diesem Ansatz ist der Datenverarbeitungscode in JavaScript geschrieben und wird im Browser ausgeführt. Der Nachteil ist, dass Ihre Leistung beeinträchtigt wird, und wenn Ihr ursprünglicher Code nicht in JavaScript war, müssen Sie ihn von Grund auf neu schreiben! - Clientseitige WebAssembly
Dazu muss Datenanalysecode für WebAssembly kompiliert und im Browser ausgeführt werden. Wenn der Analysecode in Sprachen wie C, C++ oder Rust geschrieben wurde (wie es in meinem Bereich der Genomik häufig der Fall ist), erübrigt sich das Umschreiben komplexer Algorithmen in JavaScript. Es bietet auch das Potenzial zur Beschleunigung unserer Anwendung (z. B. wie in einem früheren Artikel besprochen). - Serverloses WebAssembly
Dazu gehört das Ausführen des kompilierten WebAssembly in der Cloud unter Verwendung eines FaaS-ähnlichen Modells (z. B. dieser Artikel).
Warum also den serverlosen Ansatz den anderen vorziehen? Zum einen hat es im Vergleich zum ersten Ansatz die Vorteile, die mit der Verwendung von WebAssembly einhergehen, insbesondere die Möglichkeit, vorhandenen Code zu portieren, ohne ihn in JavaScript umschreiben zu müssen. Im Vergleich zum dritten Ansatz bedeutet serverloses WebAssembly auch, dass unsere App leichter ist, da wir die Ressourcen des Benutzers nicht für die Zahlenverarbeitung verwenden. Insbesondere wenn die Berechnungen ziemlich aufwendig sind oder die Daten bereits in der Cloud liegen, ist dieser Ansatz sinnvoller.
Auf der anderen Seite muss die App jetzt jedoch Netzwerkverbindungen herstellen, sodass die Anwendung wahrscheinlich langsamer sein wird. Darüber hinaus ist dieser Ansatz abhängig vom Umfang der Berechnung und davon, ob er in kleinere Analyseteile zerlegt werden kann, möglicherweise nicht geeignet, da die Anbieter von serverlosen Clouds die Laufzeit-, CPU- und RAM-Auslastung einschränken.
Fazit
Wie wir gesehen haben, ist es jetzt möglich, WebAssembly-Code serverlos auszuführen und die Vorteile sowohl von WebAssembly (Portabilität und Geschwindigkeit) als auch von Function-as-a-Service-Architekturen (Auto-Skalierung und nutzungsabhängige Preise) zu nutzen ). Bestimmte Arten von Anwendungen – wie Datenanalyse und Bildverarbeitung, um nur einige zu nennen – können von einem solchen Ansatz stark profitieren. Obwohl die Laufzeit aufgrund der zusätzlichen Roundtrips zum Netzwerk leidet, ermöglicht uns dieser Ansatz, mehr Daten gleichzeitig zu verarbeiten, ohne die Ressourcen der Benutzer zu belasten.