WebAssembly, WASI und Rust: Dreamteam für Microservices​

Das WebAssembly System Interface standardisiert das Zusammenspiel von Wasm-Modulen in unterschiedlichen Programmiersprachen, und Rust ist bestens aufgestellt.​

In Pocket speichern vorlesen Druckansicht 22 Kommentare lesen
Ein Computer, der auf einer Box steht, die mit WASI beschriftet ist

(Bild: Erstellt mit KI (Dall-E) von iX-Redaktion)

Lesezeit: 13 Min.
Von
  • Rainer Stropek
Inhaltsverzeichnis

Viele Projekte beginnen klein und überschaubar als elegante, homogene Monolithen, bei denen alle Komponenten auf einer gemeinsamen technischen Basis entwickelt werden. Mit steigender Größe und Komplexität des Projekts bilden sich aber Teilbereiche heraus, die sich in ihrer technischen Basis unterscheiden. Gründe dafür können geänderte Anforderungen, Vorlieben von Entwicklungsteams oder die Integration von Fremdsoftware sein.

Microservices sollen häufig die Erlösung bringen: Man gliedert die Software in überschaubare, unabhängige Einheiten, die über plattformunabhängige Netzwerkprotokolle miteinander kommunizieren. Jeder Microservice kann in einer eigenen Programmiersprache geschrieben sein und für ihn passende Bibliotheken und Drittanbieterkomponenten verwenden. Das löst zwar die technische Heterogenität auf, steigert aber die Gesamtkomplexität spürbar. Der simple Aufruf einer Funktion in einem anderen Microservice wird zu einem Abenteuer.

Schön wäre, wenn es eine Technologie gäbe, die es ermöglicht, in unterschiedlichen Programmiersprachen geschriebene Komponenten ohne Microservices zu verbinden und keine Kompromisse in Sachen Sicherheit, Performance und Portabilität einzugehen. Genau das ist das Ziel von der Kombination aus WebAssembly und WASI, dem Web Assembly System Interface.

WebAssembly (Wasm) ist eine binäre Instruktionssprache für eine Stack-basierte virtuelle Maschine, die ursprünglich entwickelt wurde, um Anwendungen mit nahezu nativer Geschwindigkeit im Browser auszuführen. Wasm ist jedoch weit mehr als nur eine Browsertechnologie: Im Kern bietet es eine standardisierte Möglichkeit, Code in eine kompakte und plattformunabhängige Form zu kompilieren, sodass sich das Ergebnis auf zahlreichen Laufzeitumgebungen auch jenseits des Browsers ausführen lässt. Ein entscheidender Vorteil von WebAssembly ist, dass es als Assembler-Sprache für die Cloud und das Web entworfen wurde, die sicher in einer Sandbox läuft. Die Sandbox-Isolation stellt sicher, dass Code keinen unkontrollierten Zugriff auf Systemressourcen oder andere, verbundene Komponenten erhält.

Entwicklerinnen und Entwickler können Wasm-Module in zahlreichen Programmiersprachen schreiben. Der entstandene Bytecode ist unabhängig von der Quellsprache und läuft mithilfe von Wasm-Laufzeitumgebungen wie Wasmtime oder Wasmer auf allen gängigen Plattformen. In der Praxis ist die Implementierung von Wasm in verschiedenen Programmiersprachen jedoch unterschiedlich gut ausgeprägt. Manche sind am Puls der Zeit und unterstützen die neuesten Entwicklungen, andere hinken etwas hinterher. Die wohl beste Programmiersprache für WebAssembly ist Rust. Fast alle wichtigen Wasm-Tools und Bibliotheken sind in Rust geschrieben und die Sprache bietet hervorragende Funktionen, um Wasm-Module zu erstellen. Rusts Fokus auf Sicherheit, Performance und Portabilität passt gut zu den Anforderungen von WebAssembly.

Neben Wasm als Grundlage für plattformunabhängigen, sicheren und performanten Code ist eine Schnittstelle erforderlich, mit der dieser Code sicher mit dem Host in Form des Betriebssystems, Browsers oder der Cloud-Umgebung und den vom Host bereitgestellten Ressourcen interagieren kann. Hier kommt das WebAssembly System Interface (WASI) ins Spiel. WASI definiert eine standardisierte API für Systemaufrufe, die es Wasm-Modulen ermöglicht, grundlegende Funktionen wie Dateisystemzugriffe oder Netzwerkkommunikation zu nutzen, ohne die Sandbox-Sicherheit aufzugeben.

Während Wasm bereits seit Längerem in einer stabilen Version vorliegt, ist WASI noch in der Entwicklung. Die Versionen preview 0 und preview 1 ermöglichten bereits grundlegende Systemaufrufe wie Dateizugriffe. Die Herausforderung für WASI ist, dass das Interface nich auf einem robusten Komponentenmodell aufbauen konnte. Wasm kennt auf unterster Ebene nur grundlegende Datentypen wie Zahlen und Zeiger, aber keine Elemente wie strukturierte Datentypen oder Strings. Um solche Datentypen über die Grenzen von Wasm-Modulen hinweg oder mit WASI auszutauschen, müssen die entsprechenden Daten im linearen Speicher von Wasm abgelegt und Zeiger ausgetauscht werden. Aufrufer und Aufgerufener müssen sich dabei auf ein gemeinsames Datenlayout einigen. Wasm enthält im Kern keine Mechanismen, um solche Datenstrukturen und die Schnittstellen zwischen Wasm-Modulen zu beschreiben.

Um das zu ändern, entstand das Wasm-Komponentenmodel als Teilprojekt. Dessen Ziel ist es, einen Standard mit zugehörigen Werkzeugen für das effiziente Zusammenspiel getrennt kompilierter Wasm-Module zu schaffen, die in unterschiedlichen Programmiersprachen geschrieben sein können. Die Sprache (Wasm Interface Types (kurz WIT) dient dazu, die Schnittstellen zwischen den Komponenten (Exporte und Importe) zu beschreiben.

Anfang des Jahres erreichte WASI mit der Version 0.2 einen wichtigen Meilenstein. Im August folgte das Update 0.2.1. Die wichtigste Eigenschaft der neuen Preview-Version 0.2 ist, dass sie auf dem Component Model aufbaut. WASI veröffentlicht also Wasm Components, mit denen man auf Funktionen des jeweiligen Hosts zugreifen kann. WASI 0.2 enthält aktuell zwei Kategorien von Komponenten (man bezeichnet solche Kategorien in WIT als Worlds):

  1. wasi-cli (Command-Line Interface): Diese World bietet Inhalte für CLI-Programme wie Dateizugriffe, Umgebungsvariablen, Zufallszahlen und Sockets.
  2. wasi-http: Diese World enthält Funktionen für HTTP rund um Requests und Responses.

Weitere Worlds werden folgen. Die kommende Version 0.3 von WASI steht unter dem Motto async, soll also asynchrone Operationen ermöglichen.

Wenn Go die Sprache in der Welt der Container ist, dann ist Rust die Sprache in der Welt von Wasm-Modulen. Insofern ist es kein Wunder, dass es nicht lange dauerte, bis Rust erste Schritte zur Unterstützung für WASI 0.2 gemacht hat. Anfang Mai erschien die Rust-Version 1.78 mit wichtigen Neuerungen im Zusammenspiel mit WASI.

Die erste Neuerung ist das Umbenennen des Compile-Targets von wasm32-wasi in wasm32-wasip1. Das p1 steht für Preview 1 und zeigt an, dass es sich um die WASI-Version 0.1 handelt. Wer also bereits Wasm-Module mit Rust und WASI 0.1 entwickelt hat, muss seine Projekte anpassen. Dafür ist Zeit bis zum Release der Rust-Version 1.84 im Januar 2025. Bis dahin erfolgt schrittweise der Abschied von wasm32-wasi mit Warnungen ab der stabilen Version von Rust 1.81. In der Nightly-Version erscheinen Warnungen beziehungsweise Fehler bereits früher. Details finden sich im Rust-Blog.

Ein Rust-Target wasm32-wasip2, um Wasm-Komponenten für beziehungsweise mit WASI 0.2 zu erstellen, existiert noch nicht. Es gibt jedoch den Cargo-Parameter cargo component ), der diese Lücke temporär füllt. Er ermöglicht bereits, Wasm-Komponenten in Cargo.toml ähnlich wie externe Crates zu referenzieren.

cargo component erstellt Rust-Bindings automatisch auf Basis der Definition des Interfaces. Der Befehl ist ein Zwischenschritt hin zur vollständigen Integration von Wasm-Komponenten in Rust, bis Cargo selbst damit arbeitet.