Einleitung

In diesem Fachartikel wollen wir uns mit einer neuen Technologie zur webbasierten Anwendungsentwicklung auseinandersetzen. Konkret wollen wir das Potenzial von WebAssembly erforschen. Durch das Erproben neuer Technologien und Konzepte ist es für uns als Randstad Digital sowohl möglich, unsere Kunden mit modernen Lösungen zu beraten als auch bei der Umsetzung dieser zu unterstützen.

WASM ist eine von Hardware und Betriebssystem unabhängige Art, Software auszuführen. Dies schafft eine Vielzahl von Einsatzmöglichkeiten. Für uns stellt sich jedoch die Frage, wie ausgereift die Technologie bereits ist und vor allem, wie sich die Performance gegenüber nativen Anwendungen verhält.

Um hierüber eine genauere Aussage treffen zu können, haben wir uns in diesem Artikel tiefer mit der Technologie WASM auseinandergesetzt. Im Anschluss daran haben wir eine Server-Anwendung mit WASM und eine Vergleichsanwendung mit Go geschrieben. Diese haben wir dann abschließend dazu genutzt, um einen Performancevergleich zwischen WASM und Go-basierten Anwendungen ziehen zu können.

Technische Hintergründe

WASM
WASM

Was ist WASM und wie kann es genutzt werden?

WASM steht mittlerweile für eine große Auswahl an Programmiersprachen (Java, Javascript, Go, Python, C, Rust,...) als Kompilierungsziel zur Verfügung. Der Support ist aber nicht in jeder Sprache gleich gut ausgeprägt. In Rust sind neue Features zum Beispiel besonders schnell verfügbar, aber auch C/C++ oder Go eignen sich gut. Generell ist eine kompilierte Sprache hier die bessere Wahl.

WASM Binaries bieten einige Vorteile, sowohl im Browser als auch auf dem Server. Sie sind plattform-  und betriebssystemunabhängig, laufen isoliert in einer VM und bieten eine hohe Ausführungsgeschwindigkeit, letzteres insbesondere im Vergleich zu JavaScript.

Der beim Kompilieren zu WASM entstandene Bytecode kann von einer WASM-Runtime ausgeführt werden. Beispiele für eine WASM spezifische Runtime sind unter anderem Wasmtime oder die meisten Browser (z.B. Chrome, Firefox, Safari, Opera,...). Die Runtime läuft dann auf der jeweiligen Hardware, die das Programm ausführen soll.

Das beigefügte Diagramm zeigt den beispielhaften Verlauf vom Quellcode bis zur letztendlichen Ausführung des Programms auf einer Vielzahl von möglichen Endgeräten.

WASI

Das WebAssembly System Interface (WASI) ist eine Sammlung von API-Spezifikation für WebAssemblies, durch die die Software in gewissen Grenzen mit dem Host-System interagieren kann (https://wasi.dev/). Die Standardisierung der APIs ermöglicht es,  WASI-konforme Software auf allen kompatiblen Runtimes zu betreiben und sogar Quellcode auf Basis verschiedener Programmiersprachen zu erstellen.

WASI ist aktuell in den Versionen 0.1 und 0.2 verfügbar. Diese Versionen sind nur Preview-Versionen, da sich das Projekt aktuell noch in den Kinderschuhen und in aktiver Entwicklung befindet. WASI wird zum Beispiel vom Spin Framework unterstützt, welches vom US-amerikanischen Startup Fermyon entwickelt wird.

Spin-Framework

Das Open-Source Framework Spin ermöglicht es, WASM-basierte Web-Anwendungen zu entwickeln. Spin startet dazu einen Webserver, der als Host agiert und die Abarbeitung der Requests an WebAssembly-Routinen delegiert. Als Runtime dient dabei Wasmtime. Jede Routine ist dabei ein komplett eigenständiger Baustein, was die Wiederverwendung von Code stark erschwert. Daraus folgt auch, dass jeder dieser Bausteine separat kompiliert werden muss - auf langsamerer Hardware ein zäher Vorgang.



Dafür ist es aber wie bereits erwähnt möglich, WASM Anwendungen in zahlreichen Programmiersprachen zu schreiben und diese dann zu kombinieren. Das gilt dementsprechend auch für die Routinen in Spin. Wir nutzen zur bestmöglichen Vergleichbarkeit mit unserem nativ kompilierten Webserver allerdings nur Go.

Seit November 2024 ist die Version 3.0 von Spin verfügbar. Diese haben wir auch zur Umsetzung unserer Testanwendung verwendet. 

Testanwendung

Um die Einsatzgebiete von WASM testen zu können, haben wir uns dazu entschieden, eine kleine Anwendung in der Programmiersprache Go zu schreiben, mit der man simulierte Waren aus dem Einzelhandel abfragen kann. Go bietet sich für diese Anwendung an, da die Sprache offiziell Support für WASI anbietet. 

Darüber hinaus ist der Fokus von Go gegenüber Sprachen wie Java oder C# ein anderer. Bei Go liegt der Fokus auf Effizienz hinsichtlich Ressourcenverbrauch und  schneller Compiler- und Startzeiten von Anwendungen. Ein weiterer Vorteil ist, dass Go eine kompilierte Sprache ist, die keine VM braucht, wie zum Beispiel Java. Aufgrund dieser Punkte ist diese Sprache vor allem in der Cloud sehr beliebt.

Zusätzlich hat uns Go ermöglicht, schnell einen Prototyp zu schreiben, da die Syntax relativ einfach ist und die Compile-Zeiten gering sind.

Mit eingeflossen in unsere Entscheidung, eine Serveranwendung zu schreiben, ist die Tatsache, dass Webserver eine der am meisten nachgefragten Anwendungsarten unserer Kunden sind. Clientseitige Browser-Anwendungen, in denen WASM JavaScript ergänzt oder ersetzt, sind nicht Gegenstand der Betrachtung.

wasm-table-3
wasm-table-3

Die Anwendung kann sowohl nativ wie auch als WebAssemby ausgeführt werden. Im Quellcode gibt es hierbei nur sehr geringe, technologiespezifische Unterschiede bei der Implementierung.

Die Anwendungsversion auf WASM-Basis benötigt das Fermyon Spin Framework, da eine Umsetzung ohne Unterstützung des Frameworks nicht möglich ist. Laut unserem aktuellen Kenntnisstand ist es derzeit nicht möglich, einen Webserver in Go zu schreiben und direkt nach WASM zu kompilieren.

Im Spin Framework werden WebAssembly-Module für die Verarbeitung von Requests verwendet. Wir haben uns für Spin entschieden, da dadurch ein Webserver mit WASM basierend auf der WASI-Spezifikation entwickelt werden konnte. Außerdem ist das Framework noch aktiv in der Entwicklung und wird laufend um weitere Funktionalitäten erweitert. 

Es ist zu erwähnen, dass bei der Entwicklung mit dem Spin Framework TinyGo genutzt werden muss, wenn man mit Go entwickeln will. Es steht zu vermuten, dass TinyGo von Spin genutzt wird, da es zum Zeitpunkt unserer Entwicklung mehr Funktionalitäten des WASI Standards anbietet als der Standard Go-Compiler (GC). Dies führt dazu, dass die Compile Zeiten je nach Hardware deutlich länger sind, was vor allem bei der Entwicklung ein Störfaktor ist.

Benchmark

Testbeschreibung

Um unsere Anwendungen miteinander vergleichen zu können, haben wir eine Analyse der Performance durchgeführt. Mit dem Kommandozeilentool ApacheBench wurden  jeweils 100.000 Requests parallel gegen drei verschiedene Endpunkte der jeweiligen Testanwendung geschickt. Der Test ist darauf ausgelegt, die Ausführungsgeschwindigkeit zwischen nativer und WASM-basierter Anwendung zu vergleichen und ist nicht speicherlimitiert. Der Code ist beinahe exakt derselbe.

Die Endpunkte bieten folgende Funktionalität: Es wird jeweils ein 576 Artikel großer Datensatz aus Einzelhandelsartikeln durchsucht, die mit zufälligen Preisen versehen sind. Diese Artikel werden dann durchsucht. Der erste Endpunkt fordert von der Anwendung den billigsten Artikel an. Der zweite Endpunkt sucht aus den Artikeln den teuersten heraus. Der letzte Endpunkt ermöglicht eine Suche nach einem spezifischen Artikel anhand seines Namens.

Um den Test mit der nativen Go Anwendung durchführen zu können, wurde diese mit dem Standard Go-Compiler zu einer systemspezifischen Executable kompiliert und dann ausgeführt. Die WASM-Version der Anwendung wurde für den Test im Spin-Framework gestartet.

Die Tests haben wir sowohl auf einem Lenovo Thinkpad T490 (Intel Core i7-8565U, Linux Ubuntu) als auch auf einem Macbook Pro 2023 (M2 Pro, macOS) ausgeführt. Das dient dazu, die Ergebnisse auf verschiedenen Betriebssystemen und Prozessorarchitekturen vergleichen zu können. Die Tests wurden mehrfach durchgeführt, um Ausreißer identifizieren zu können.

Ergebnisse

Die folgende Grafik zeigt die Performance der beiden Anwendungen beim Aufrufen der drei verschiedenen Endpunkte. Die X-Achse gibt hierbei die Anzahl der erfolgreichen Anfragen pro Sekunde wieder. Auf der Y-Achse kann man die unterschiedlichen Endpunkte und die jeweilige ausführende Anwendung ablesen. Die Farben orange und blau stellen die verwendete Hardware dar.

wasm_table-new
wasm_table-new

Interessant ist zu sehen, dass je nach Hardware eine andere Anwendung im Vergleich besser abschneidet. Beim ThinkPad schafft die native Anwendung zwischen 1500-1750 erfolgreiche Anfragen pro Sekunde, die WASM Anwendung schafft hier im selben Testszenario nur ca. 500 Requests pro Sekunde. Man sieht also eine Steigerung von knapp 200% von nativ gegenüber WASM.

Vergleicht man die Ergebnisse jedoch beim Macbook, ist das Ergebnis ein anderes. Hier schafft WASM bei jedem Endpunkt mindestens 10% mehr Requests pro Sekunde. Darüber hinaus ist bei den Endpunkten “cheapest” und “most-expensive” eine Steigerung von knapp 20% zu erkennen.

Zusätzlich ist anzumerken, dass bei allen durchgeführten Tests die CPU primär ausgelastet wurde. Der Arbeitsspeicher wurde mit unter 70MB hingegen kaum belastet. Die native Anwendung benötigte sogar nur 12 MB (ThinkPad) bis 25 MB (Macbook) Arbeitsspeicher.

Fazit

Die Ergebnisse lassen im aktuellen Zustand keine Aussage darüber zu, welche Anwendung eine höhere Leistung ermöglicht. Die Tests waren hierzu zu gegensätzlich. Um das Testszenario in Zukunft weiter auszubauen, könnte man genauer erforschen, wie sich die Anwendungen bei komplexeren Anfragen verhalten. Dies könnte dazu führen, dass der Speicherbedarf eine größere Auswirkung auf die Performance hat.

Unabhängig von den Testergebnissen lässt die WASI-Spezifikation im Moment eine Menge Features vermissen, die für die Entwicklung eines eigenständigen Webservers nützlich sind. Mit einem höheren Aufwand mag es sicher möglich sein, einen prototypischen Webserver auf die Beine zu stellen, jedoch wird dieser höchstwahrscheinlich auch dann nicht so stabil, performant und sicher wie die gängigen, nativ kompilierten Lösungen sein.

Zu bedenken ist auch: Da sich WASM und auch WASI noch am Anfang ihrer Entwicklung befinden und noch nicht ausgereift sind, fällt es schwer abzuschätzen, ob die diversen darauf basierenden Projekte langfristig fertiggestellt und gewartet werden. Dies ist vor allem ein wichtiges Kriterium, wenn es um die Entscheidung geht, Serveranwendungen basierend auf WebAssembly für ein kommerzielles Projekt zu nutzen.

Die WASI Spezifikation ist zum jetzigen Stand nur in Preview Versionen nutzbar und auch die Liste der Features beinhaltet keines, welches bis jetzt komplett standardisiert wurde. Dies kann man auf der GitHub-Seite zum WASI Projekt verfolgen. 

(siehe https://github.com/WebAssembly/WASI/blob/main/Proposals.md)

Aus unserer Sicht ist zum jetzigen Zeitpunkt der Reifegrad der Technologie noch nicht so weit vorangeschritten, dass wir hierfür eine Nutzungsempfehlung geben könnten. Zu groß sind aktuell die Baustellen, um selbst kleinere Anwendungen damit zu entwickeln. Daher sehen wir hier noch keinen Bedarf, von der Entwicklung nativer Anwendungen abzuweichen. Es gilt zu beobachten, wie sich das Umfeld um WebAssembly und die WASI Spezifikation herum entwickelt. Sollte es einen deutlichen Fortschritt in der Erreichung der Meilensteine geben, kann die Technologie für den serverseitigen Einsatz neu evaluiert werden.

Autoren

Dominique Dorscheid, Michael Stadler

lead software engineers