Seit Jahren löst WebAssembly ein genau definiertes Problem: das Ausführen von Code aus kompilierten Sprachen im Browser mit nahezu nativer Leistung. Aber es gab eine frustrierende Grenze. Jedes Wasm-Modul war eine Insel. Sie könnten Rust zu Wasm kompilieren, Funktionen verfügbar machen und sie über JavaScript aufrufen, aber wenn Sie wollten, dass ein Python-Modul mit einem Rust-Modul kommuniziert, mussten Sie manuellen Glue-Code schreiben, der Daten auf beiden Seiten serialisiert und deserialisiert, genau wie ein Low-Level-FFI. Das Versprechen einer echten Portabilität hielt die Komposition nicht ein.
Das Komponentenmodell ist das fehlende Teil, und mit WASI 0.2 Anfang 2024 ging es an den Start und wurde zu einer Produktionsbasis.
Das Problem, das das Komponentenmodell löst
Ein herkömmliches Wasm-Modul stellt Funktionen mit primitiven Typen bereit und nutzt sie: Ganzzahlen, Gleitkommazahlen, Zeiger auf den linearen Speicher. Im öffentlichen Auftrag gibt es keine native Vorstellung von Zeichenfolgen, Datensätzen oder Listen. Wenn zwei Module Daten austauschen mussten, lag es in der Verantwortung des Entwicklers, Serialisierungskonventionen zu definieren, Zeiger auf gemeinsam genutzte Puffer zu übergeben und sicherzustellen, dass sich beide Seiten auf das Format einigten.
Dies funktioniert innerhalb einer Sprache. Ein Rust-Modul, das ein anderes Rust aufruft, kann Konventionen festlegen, da beide Seiten die gleichen Abstraktionen verstehen. In einem mehrsprachigen Szenario wird diese Anordnung zu Klebercode, den Sie auf subtile Weise schreiben, verwalten und schließlich brechen.
WIT: der Vertrag zwischen Komponenten
Die Kernlösung des Komponentenmodells ist WIT, Wasm Interface Types, ein sprachunabhängiges IDL, das beschreibt, was eine Komponente verfügbar macht und was sie konsumieren muss. Sie schreiben die Schnittstelle einmal und die Tools jeder Sprache generieren automatisch den Code, der für die Implementierung oder den Aufruf erforderlich ist.
Stellen Sie sich WIT wie Protobuf vor, aber für die Komposition innerhalb desselben Prozesses und nicht für Nachrichten über das Netzwerk. Der Vertrag beschreibt Funktionen mit Rich Types, Strings, Listen, benannten Datensätzen und Ergebnissen, die fehlerhaft sein können, und die Tools kümmern sich um die Übersetzung zwischen der Darstellung jeder Sprache und dem kanonischen Format der Komponente.
Das praktische Ergebnis ist, dass eine Rust-Komponente, die Strings verarbeitet, von einer Python-Komponente mit Geschäftslogik aufgerufen werden kann, die eine JavaScript-Serialisierungskomponente speist. Keine manuelle Serialisierung, kein Netzwerk-Hopping, mit Glue-Code, der aus WIT generiert und nicht von Hand geschrieben wird.
WASI 0.2 und die Wende zur Produktion
WASI 0.2, veröffentlicht im Februar 2024, war der Meilenstein, der die Komponentenkomposition zu etwas machte, das echte Teams übernehmen können. Die vorherige Version von WASI definierte, wie Wasm-Module auf das Betriebssystem zugreifen, war jedoch älter als das Komponentenmodell und verwendete das alte Modell für flache Module. WASI 0.2 wurde auf Basis des Komponentenmodells neu geschrieben: Alle Systemschnittstellen, Dateilesen, Netzwerk, Uhr, Zufälligkeit sind jetzt WIT-Verträge.
Die konkrete Konsequenz besteht darin, dass eine Komponente, die für I/O auf WASI angewiesen ist, auf einer standardisierten WIT-Schnittstelle und nicht auf einer bestimmten Implementierung angewiesen ist. Die Laufzeit kann diese Abhängigkeit auf unterschiedliche Weise in verschiedenen Umgebungen erfüllen, auf dem Server, am Edge, im Browser per Polyfill, ohne dass die Komponente neu kompiliert werden muss. Portabilität ist kein Anspruch mehr, sondern eine überprüfbare Eigenschaft.
Die begleitende Toolchain umfasst wasmtime als Referenzlaufzeit, wasm-tools für die Komponentenkomposition und jco für das JavaScript-Ökosystem, das Wasm-Komponenten aus WIT-Definitionen in native ES-Module umwandelt.
Wer nutzt es und wo
Das am weitesten ausgereifte Einführungsszenario sind Wasm-basierte serverlose Plattformen. Fermyon mit Spin und Fastly mit Compute behandeln das Komponentenmodell als native Bereitstellungseinheit. Entwickler schreiben Komponenten in Rust, kompilieren, stellen sie bereit, und die Laufzeit übernimmt die Komposition mit WASI-Schnittstellen für HTTP, Schlüsselwertdatenbanken und anderen Plattformdiensten.
Zur ByteCode Alliance, dem Konsortium, das das Komponentenmodell spezifiziert, gehören Fastly, Intel, Mozilla und Microsoft, was dem Projekt institutionelle Stabilität verleiht, die Spezifikationsprojekten manchmal fehlt.
Was es noch nicht in großem Umfang gibt, sind Bibliotheken und Frameworks, die nativ als Wasm-Komponenten verpackt sind. Man kann heute viele Dinge zu Komponenten kompilieren, aber das Repository veröffentlichter und wiederverwendbarer Komponenten ist im Vergleich zu dem von npm-Paketen oder Rust-Kisten klein. Der Aufbau funktioniert technisch, der Teilekatalog befindet sich jedoch noch im Aufbau.
Was noch ungelöst ist
Rust bietet heute die umfassendste Komponentenmodellunterstützung. Go und Python verfügen über funktionierende Tools, aber das Kompilieren von Komponenten mit vollständiger Unterstützung für WIT-Typen führt immer noch zu Problemen. Es geht nicht ums Blocken, aber es ist eine Stack-Entscheidung, die zählt: Teams, die Rust nicht verwenden, werden auf Ecken und Kanten stoßen.
Das Debuggen eines polyglotten Komponentendiagramms ist tatsächlich schwieriger als das Debuggen eines monolith. Es gibt Sprachgrenzen, Speicherisolation zwischen Komponenten und Stack-Traces, die diese Grenzen nicht transparent überschreiten. Die Tools verbessern sich, aber diese Art von Problemen treten meist erst spät im Entwicklungszyklus auf.
Es gibt auch Overhead bei Queraufrufen zwischen Komponenten. Dabei handelt es sich nicht um die Kosten eines Netzwerk-Hops, sie sind jedoch im Vergleich zu Aufrufen innerhalb desselben Prozesses messbar. In den meisten Fällen verschwinden diese Kosten im Lärm der tatsächlichen Arbeit der Komponente. Bei hochfrequenten heißen Pfaden muss die Granularität der Zusammensetzung sorgfältig durchdacht werden.
Die architektonische Entscheidung für diejenigen, die führen
Für ein Team, das heute das Komponentenmodell evaluiert, lautet die nützlichste Frage nicht: „Ist das fertig?“ aber „bereit für was?“. Für Rust lautet die Antwort „Ja“, mit Vorbehalten gegenüber Debug-Tools. Für Go- oder Python-Teams lautet die Antwort: „Es funktioniert, aber Sie müssen mindestens einen Ingenieur haben, der sich mit dem Platz auskennt, bevor Sie sich verpflichten.“
Das Komponentenmodell löst ein Problem, für das es keine gute Lösung gab: Software über Sprachgrenzen hinweg zu komponieren, ohne die Kosten einer Netzwerkgrenze zu bezahlen. Wenn Sie eine Erweiterbarkeitsplattform erstellen, garantiert das Modell einen überprüfbaren WIT-Vertrag und keinen uneingeschränkten nativen Code. Wenn Sie Teams in verschiedenen Sprachen haben, die umfangreiche Rechenlogik gemeinsam nutzen müssen, sind Wasm-Komponenten mit WIT-Schnittstellen die sauberste Alternative, die heute verfügbar ist.
Für diejenigen, die sich nicht in dieser Situation befinden, reicht es vorerst aus, das Modell konzeptionell zu kennen. Die Entscheidung, die im Jahr 2025 sinnvoll ist, wird im Jahr 2027 offensichtlicher, wenn der Komponentenkatalog und die Sprachunterstützung ausgereift sind.
Lesen Sie auch
- WebAssembly für Führungskräfte: Wenn sich die Architekturentscheidung lohnt
- WebAssembly jenseits des Browsers: die fehlende universelle Ausführungsebene
- WebAssembly am Rande: Warum ein schneller und isolierter Start wichtig ist
- Edge Computing: Warum verteilte Verarbeitung Ihre Architektur neu definieren wird
- Wasm für Plugins und Sandbox: Code von Drittanbietern sicher ausführen
- Das Wachstum der Suchanfragen nach Rust und WebAssembly in Brasilien: Analyse eines technologischen Trends