Aus Linux-Magazin 01/2012

Anfragen an Webserver schneller beantworten mit Node.js

© fl0wer, photocase.com

Die Javascript-basierte Programmierumgebung für Webentwicklung Node.js bändigt den Ressourcen-Hunger von Echtzeit-Webanwendungen wie Onlinespielen oder Chatservern. Dank eines ereignisorientierten Ansatzes kommt Node.js dabei mit einem Webserver-Thread pro Instanz aus.

Ein Webserver in Javascript? Manch erfahrener Webserver-Administrator oder Webprogrammierer mag bei dieser Vorstellung zunächst den Kopf schütteln. Doch genau das bringt das auf Googles V8-Javascript-Interpreter aufsetzende Node.js-Projekt [1] und glänzt dabei mit überraschend positiven Ergebnissen.

Schneller serviert

Seit der ersten Präsentation durch seinen Initiator Ryan Dahl auf der Jsconf Ende 2009 [2] hat Node.js viel Aufmerksamkeit auf sich gezogen. Das liegt primär sicherlich daran, weil das Projekt mit dem Anspruch antritt, den im flotten C programmierten Apache und andere Webserver bei der Performance zu schlagen. Die Software ermuntert Webanwendungen dazu, ihren Webserver einfach selbst mitzubringen. Admins und Programmierer können dann komplett auf Apache & Co. verzichten.

Seinen Geschwindigkeitsvorsprung erringt Node.js nicht etwa dadurch, dass der Webserver-Code schneller wäre, sondern weil es mit den Wartezeiten der CPU auf das langsamere Dateisystem oder die Datenbank anders umgeht als konventionelle Serversoftware.

Apache arbeitet mit mehreren Threads oder Prozessen. Braucht eine Instanz Daten von der Festplatte, so dreht sie Däumchen, bis diese vorliegen. Parallel ablaufende Serverinstanzen und der Scheduler des Kernels kompensieren das wieder teilweise. Node.js dagegen kümmert sich darum selbst: Es arbeitet nach dem Prinzip der ereignisorientierten Programmierung und benötigt nur einen Thread pro CPU, um die Rechenleistung des Servers voll auszunutzen.

Muss der Thread auf externe Daten warten, legt er seinen bisherigen Auftrag einfach beiseite und wendet sich neuen Aufgaben zu. Das macht er jedoch nicht, ohne vorher einen Eventhandler gesetzt zu haben, der den Fokus zurückholt, wenn das Dateisystem oder die Datenbank ihren Beitrag geleistet haben.

Schnellimbiss oder Restaurant?

Die Vorteile dieser Arbeitsweise erklärt am besten der Vergleich zwischen einem Schnellimbiss und einem konventionellen Restaurant. In der Burgerbude ist eine Bedienung so lange für einen Gast zuständig, bis dieser sein Essen erhalten hat. Da sie die Fleischklopse mit Brötchen in der Regel nur auf das Tablett legen muss, kommt es auch nur selten zu Leerlauf. In der konventionellen Gastronomie dagegen würde es zu exorbitanten Lohnkosten führen, bliebe jeder Kellner bis zum Eintreffen des Essens beim Gast. Die Küchenlatenz ist hier einfach zu groß.

Daher nimmt die Bedienung dort eine Bestellung auf, übermittelt sie der Küche und wendet sich dann dem nächsten Gast zu, statt zu warten, bis das Essen zubereitet ist. Sie arbeitet nach dem Prinzip der Event-Warteschlange. In wohlorganisierten Gaststätten schaut der Kellner auch nicht laufend in der Küche vorbei. Vielmehr macht ihn üblicherweise der Koch mit einem kleinen Glöckchen darauf aufmerksam, dass ein weiteres Gericht zum Servieren am Tisch bereitsteht, ähnlich einer Event-Notification.

In Javascript übernehmen Callbackfunktionen und Eventhandler die Rolle des Glöckchens. Das Javascript-Eventsystem funktioniert ohne Polling, also ohne ständiges Nachfragen in der Küche, ob das Essen vielleicht schon fertig sei. Im Betriebssystem kümmern sich überdies auch der Kernel und sein Scheduler um eine sinnvolle Aufgabenverteilung.

Javascript ist seit seinen Anfangsversionen dafür ausgelegt, auf Benutzereingaben zu reagieren. Jeder Webentwickler kennt auf Mausaktivitäten bezogene Events wie »onClick()« , an die sich nicht nur eine, sondern beliebig viele Aktionen andocken lassen. Das Node-Modul »Events« funktioniert ähnlich [3]. Auch das Observer-Design-Pattern (Abbildung 1, [4]), mit dem sich zur Laufzeit beliebig viele Funktionsaufrufe an ein Ereignis anbinden lassen, ist bereits eingebaut.

Abbildung 1: Beim Observer-Design-Pattern subskribieren sich mehrere Methoden für ein Event. Tritt es ein, dann ruft die Laufzeitumgebung sie auf, ohne dass sich der Entwickler weiter darum kümmern muss.

Abbildung 1: Beim Observer-Design-Pattern subskribieren sich mehrere Methoden für ein Event. Tritt es ein, dann ruft die Laufzeitumgebung sie auf, ohne dass sich der Entwickler weiter darum kümmern muss.

Ein weiteres Verfahren, mit dem sich Ereignisabfolgen verketten lassen, sind die Callbackfunktionen. Dabei erhält eine Funktion eine weitere als Parameter, die sie aufruft, sobald ein bestimmter Zustand erreicht ist. Callbackfunktionen lassen sich in der funktionalen Sprache Javascript elegant umsetzen, da der Entwickler Funktionen an Variablen binden oder Lambda-Funktionen direkt als Parameter übergeben darf. Umständliche Hilfs- konstrukte wie die Funktions-Pointer in C/C++ sind daher nicht mehr erforderlich.

Ein Beispiel für den Einsatz eines Eventhandlers zeigt der Code der Hello-World-Anwendung auf Nodejs.org (Listing 1), der sich ähnlich auch als Start- oder Bootcode in komplexen Node.js-Anwendungen findet. Die erste Zeile bindet das im Lieferumfang von Node.js enthaltene Modul »http« an die Variable »http« . Selbst geschriebene Module (einfache Javascript-Dateien) bindet der »require()« -Befehl ein. Der Aufruf von »http.createServer()« reicht bereits aus, um einen Webserver zu erzeugen (Abbildung 2).

Abbildung 2: Die virtuelle Maschine auf der DELUG-DVD zeigt die simple Beispielanwendung zur Latenzmessung aus <link href="#article_l2" class="listing" srcset=

Listing 2.” width=”300″ height=”174″ /> Abbildung 2: Die virtuelle Maschine auf der DELUG-DVD zeigt die simple Beispielanwendung zur Latenzmessung aus Listing 2.

Listing 1

helloworld.js

01 var http = require('http');
02 var handler = function (request, response) {
03   response.writeHead(200, {'Content-Type': 'text/plain'});
04   response.write('Hallo, Leser!');
05   response.end();
06 };
07 http.createServer(handler).listen(1337, "127.0.0.1");
08 console.log('Server running at http://127.0.0.1:1337/');

Listing 2

haltepunkt.js

01 var parallelRequests = 0; //globaler Zähler
02 var http = require("http"); //importiere Node-Modul http
03
04 //Callback beim Eintreffen eines Requests
05 var handler = function(request, response){
06     //Ausgabe auf der Konsole bestätigt Request
07     console.log("Request eingegangen bei " + new Date().getTime()/1000);
08     //Parallel-Request-Zähler erhöhen
09     parallelRequests++;
10     console.log(parallelRequests + " parallele Requests");
11
12     //Request wird erst in 1 Sekunde ausgeliefert (simuliert Datenbank-Latenz o.ä.)
13     setTimeout(EndRequest, 1000, parallelRequests, response);
14 }
15
16 //Wartezeit vorbei, Request kann ausgeliefert werden
17 var EndRequest = function(RequestCount, response){
18     response.writeHead(200, {"Content-Type": "text/plain"});
19     response.write("Parallele Requests: " + RequestCount );
20     response.end();
21     //fertig, ein laufender Request weniger
22     parallelRequests--;
23 }
24
25 //Server starten und auf Port 1337 scharf schalten
26 http.createServer(handler).listen(1337);

DELUG-DVD

Auf der DELUG-DVD finden sich alle Beispiele aus diesem Artikel als Javascript-Dateien. In einer virtuellen Maschine ist Node.js auf Ubuntu 11.10 Server vorinstalliert. Zwei Beispielanwendungen (der Latenztest und ein einfacher Chatroom) stehen dort zum Test bereit, sie liegen in »/srv/node« .

Der an das von »createServer()« zurückgegebene Serverobjekt direkt angeschlossene »listen()« -Aufruf schaltet den Webserver für den lokalen Rechner und Port 1337 scharf. Damit der Server bei einem eingehenden Request weiß, was er zu tun hat, erwartet er eine Callbackfunktion wie »handler(request, response)« , die er bei jeder eingehenden Anfrage aufruft.

Der Requesthandler erhält als Parameter das Requestobjekt, das die URL der Anfrage und vom Server gesendete (POST)-Daten enthält. Den Umgang damit erleichtert das Node.js-Modul »querystring« [6]. Die einfache Beispielanwendung ignoriert jedoch das Requestobjekt und sendet unabhängig von der Anfrage den Text »Hallo, Leser!« . Dazu benutzt sie »response« , also das zweite dem Requesthandler vom Server übergebene Objekt. Die aufgerufenen Methoden »writeHead()« , »write()« und »end()« erklären sich von selbst.

Gezieltes Warten

Stünde an der Stelle des statischen Textes »Hallo, Leser!« dynamisch aufbereiteter HTML-Code, so läge schon eine vollwertige Node.js-Webanwendung vor. Doch das Besondere an Node.js zeigt eine um einen Haltepunkt erweiterte Version des Requesthandlers (Listing 2). Bei ihr endet der Request in Zeile 13 erst einmal unverrichteter Dinge und gibt die Kontrolle an die Node-Laufzeitumgebung zurück, die auf weitere Anfragen wartet. Unabhängig davon ruft 1000 Millisekunden später der in Zeile 13 gesetzte Javascript-Timer ihn mit der Zahl der gerade aktiven Anfragen und vor allem mit dem »response« -Objekt als Parameter erneut auf.

Statt dieses Timeouts steht in einer realen Node-Anwendung normalerweise eine Datenbankabfrage oder ein Befehl, der eine größere Menge Daten vom Dateisystem einliest. Genau wie der Timer-Befehl würde dieser jedoch den Code, der die Daten weiterverarbeitet, per Callback aufrufen. Dieses »response« -Objekt zeigt immer noch auf die Anfrage zum Zeitpunkt des Aufrufs von »handler()« , egal wie viele weitere Requests inzwischen eingegangen sind. Das »EndRequest« -Callback gibt nun einen »Content-Type« -Header sowie einen kurzen Text aus und schickt ihn durch Aufruf der Methode »end()« an den richtigen Client.

Die Demoanwendung aus dem Listing 2 findet sich ebenfalls auf der DELUG-DVD dieses Magazins und lässt sich mit »node /srv/node/latency.js« starten. Ein Aufruf von »IP_der_virtuellen_Maschine:1337« im Browser zeigt die Anzahl der wartenden Request beim Eingang der Anfrage an (Abbildung 2). Dies werden pro Aufruf je zwei Anfragen sein, denn der Browser fordert vor der eigentlichen Seite auch die Datei »favicon.ico« für das Icon in der Adressenleiste an.

Last erzeugen mit Ab

Das wiederholte Betätigen der Taste [F5] im Browser sorgt nun für etwas Last auf dem Server. Bei jedem eingehenden Request meldet er sich an der Konsole mit Zeitstempel und der Anzahl der noch nicht abgearbeiteten Requests. Browser vermeiden es jedoch, zu viele Requests gleichzeitig an einen Server zu senden. Für ernsthafte Last sorgt erst ein Webserver-Benchmark wie das in praktisch jedem Indianerpaket enthaltene Apache-Benchmark-Binary »ab« [7].

Der Aufruf von »ab -n 10000 -c 1000 http://127.0.0.1:1337/« auf der Servermaschine sendet zehnmal nacheinander 1000 gleichzeitige Anfragen an die Node.js-Anwendung. Für Überblick über den Speicherbedarf von Node sorgt der Aufruf von »watch -n1 “ps u -C node”« in einer zweiten Konsole.

Abbildung 3 zeigt, wie spielend Node.js die bis zu 1000 gleichzeitigen Anfragen bewältigt. Der vom Node-Binary belegte Speicher erhöht sich von etwa 9 MByte auf maximal 52 MByte und geht nach dem Abarbeiten des letzten Requests wegen der Garbage Collection in der Javascript-Engine schlagartig wieder annähernd auf den Wert vor dem Bombardement zurück.

Abbildung 3: Mit 1000 Anfragen pro Sekunde feuert »ab« auf die Node.js-Anwendung aus dem <link href="#article_l2" class="listing" srcset=

Listing 2. Dabei bleibt die Speicherbelegung erfreulich niedrig und geht dank Garbage Collection auch schnell wieder zurück.” width=”300″ height=”187″ /> Abbildung 3: Mit 1000 Anfragen pro Sekunde feuert »ab« auf die Node.js-Anwendung aus dem Listing 2. Dabei bleibt die Speicherbelegung erfreulich niedrig und geht dank Garbage Collection auch schnell wieder zurück.

Im Vergleich zu mit Threads oder Prozessen arbeitenden Webservern sind die etwas mehr als 50 MByte Speicherkosten für 1000 aufgestaute Anfragen lächerlich gering, vor allem dann, wenn man bedenkt, dass es hier nicht um statische, sondern um mit einer Server-seitigen Skriptsprache erzeugte Seiten geht. Dass die einfache Beispielanwendung keine große CPU-Last erzeugt, liegt natürlich daran, dass sie außer zu warten keinerlei Arbeit verursacht. Muss ein konventioneller Webserver aber bei einer Anfrageflut viele neue Instanzen inklusive Skriptinterpreter starten, kostet dies einige Prozessorzeit.

Die Beispielanwendung demonstriert eindrucksvoll: Obwohl Node.js konstant in nur einem Thread abläuft, nimmt es dank seiner Event-gesteuerten Architektur sehr effizient neue Anfragen entgegen, bevor die alten abgearbeitet sind.

Ajax-Anwendungen

Das macht Node.js auch für die Admins von Ajax-Anwendungen interessant. Solche vom Browser initiierten, asynchronen Serveranfragen sorgen seit 2005 für immer komfortablere Webanwendungen. Die reagieren im Idealfall fast so flott auf Benutzereingaben wie Deskopprogramme. Schwieriger umzusetzen ist dagegen das Echtzeit-ähnliche Reagieren auf Server-seitige Statusänderungen, weil HTTP nämlich nicht für Server-Push-Verfahren taugt.

Nur mit zwei Workarounds können Webentwickler kontern: Entweder fragt der Client den Zustand des Servers in regelmäßigen Abständen ab oder der Server lässt den einmal geöffneten Polling-Request so lange unbeantwortet, bis eine Statusänderung oder ein Timeout eintritt (Long Polling Requests, Abbildung 4).

Abbildung 4: Comet-Anwendungen reagieren dank Long-Polling-Requests in Echtzeit auf Server-Ereignisse. Dabei beantwortet der Server die Polling-Anfrage des Clients so lange nicht, bis entweder eine bestimmte Laufzeit überschritten ist oder eine Nachricht für die Clients vorliegt.

Abbildung 4: Comet-Anwendungen reagieren dank Long-Polling-Requests in Echtzeit auf Server-Ereignisse. Dabei beantwortet der Server die Polling-Anfrage des Clients so lange nicht, bis entweder eine bestimmte Laufzeit überschritten ist oder eine Nachricht für die Clients vorliegt.

Kometenhaft

Nur das zweite Verfahren macht wirklich Echtzeit-nahe Reaktionen möglich. Das in Amerika nach Ajax am häufigsten verkaufte Putzmittel Comet hat den Autor eines Blogposts, der die Technik schon 2006 ausführlich beschrieben hat [8], zum Projektnamen Comet inspiriert. Aber auch die technisch genauere Bezeichnung Long polling requests findet sich häufiger in der Literatur.

Zwar funktioniert das Verfahren aus Sicht des Clients problemlos, doch es stellt den Server vor eine große Herausforderung: Jeder eingeloggte Benutzer hält eine Webserver-Instanz dauerhaft im Speicher, in der Regel inklusive Laufzeitumgebung für eine Programmiersprache. Der Zahl der Anwender, die ein Thread-basierter Server bedienen kann, sind damit klare Grenzen gesetzt.

Anders Node.js: Listing 2 zeigt nämlich auch, dass die ereignisorientierte Architektur sich gut für viele simultane, offengehaltene Anfragen eignet. Die Requests sind nicht an Threads oder Prozesse gebunden, sondern lediglich an ein Javascript-Objekt, das wenig RAM belegt.

Ein gangbarer Weg für einen Long-Polling-Server auf der Basis von Node.js ist es, jedem eingehenden Polling-Request zunächst einen Timer zuzuweisen, nach dessen Ablauf die Anwendung dem Client mitteilt, dass keine Statusänderungen vorliegen. Arrays speichern sowohl die Requestobjekte als auch die Zeiger auf aktive Timer. Tritt dann eine Statusänderung ein, löscht die Anwendung die Timer und nutzt die Requestobjekte, um alle wartenden Clients zu benachrichtigen. Weil in diesem Szenario typischerweise alle Pollingclients die gleiche Nachricht erhalten, weicht die Performance nicht allzu sehr von der der einfachen Demo aus dem Listing ab.

Auch die offizielle Beispielanwendung des Node.js-Projekts, ein Chatserver [9], demonstriert den effizienten Einsatz von Long Polling. Auch dieses Chatprogramm ist auf der Linux-Magazin-DVD enthalten, es startet mit »cd /srv/node; node node_chat/server.js« .

Das C10K-Problem

Doch auch konventionelle Webserver bieten inzwischen Lösungsansätze für das so genannte C10k-Problem (C10k steht für 10000 gleichzeitige Verbindungen). Seit Version 6 von Ende 2006 stellt Jetty [10] Webanwendung Methoden zur Verfügung, die Requests von Serverinstanzen trennt und in einen Speicher sparenden Schlafmodus versetzt. Für den ohnehin ereignisorientierten Webserver Nginx gibt es ein HTTP-Push-Modul, das Message-Queues direkt im Webserver umsetzt [11]. Anwendungen, die das nutzen, funktionieren allerdings nur in Nginx.

Auch der Platzhirsch Apache nimmt sich der Comet-Anwendung an: Das Multi-Processing Module »event« durchbricht die bisherige Koppelung einer Anfrage an einen Thread oder Prozess. Bisher kennzeichnen es die Apache-Entwickler noch als experimentell, doch offenbar wird sich dies spätestens mit der künftigen Apache-Version 2.3 ändern [12].

Spaghetticode?

Bei Event-gesteuerter Programmierung fällt unter Entwicklern oft das Schimpfwort “Spaghetticode”, das auf die oft unübersichtlichen Relationen zwischen Events und zugeordneten Handlern anspielt. Es ist auch nicht von der Hand zu weisen, dass das Auslagern von logisch direkt an die Datenbankabfrage anschließendem Code in eine Callbackfunktion die Struktur verkompliziert und die Wartung erschwert.

Zumindest wenn eine Comet-Anwendung identische Nachrichten an viele Clients versendet, gilt aber das Gegenteil: Beim klassischen Apache-Setup ohne MPM-Worker ist jedem wartenden Client ein Prozess zugeordnet. Tritt ein Ereignis ein, über das alle Clients zu benachrichtigen sind, müssen alle Forks identische Nachrichten absenden, was nur mit Hilfe der Interprozess-Kommunikation gelingt. In Node.js-Anwendung genügt dagegen eine Schleife, die über die zwischengespeicherten Anfrage-Objekte iteriert.

Unterschätzt: Javascript

Neben Vorbehalten gegen Event-gesteuerte Programmierung treffen Node.js auch die Vorurteile gegen die Programmiersprache Javascript, vor allem in Sachen Geschwindigkeit. Doch der Sprachen-Benchmark auf Debian-Alioth.org [13] beweist, dass Googles V8-Interpreter, den auch Node.js nutzt, verbreitete Server-seitige Skriptsprachen wie PHP, Perl oder Python bei vielen Tests mit Leichtigkeit in die Tasche steckt. Wenn Skripte in aktuellen Browsern immer noch langsam ablaufen, liegt dies daran, dass sie Manipulationen an einer HTML-Seite vornehmen. Auf das Konto des Javascript-Interpreters geht dabei nur ein geringer Bruchteil der Laufzeit, den Löwenanteil verschlingt die Rendering-Engine des Browsers.

Oft gilt Javascript auch als Sprache mit geringen Ausdrucksmöglichkeiten und schlechtem Design. Und tatsächlich belastet Javascript seine Entwickler mit Schwächen, die noch aus den übereilten Releases zu Beginn des Browser-Kriegs zwischen Netscape und Microsoft herrühren. Im Kern handelt es sich aber um eine flexible und mächtige Sprache, die für funktionale wie auch objektorientierte Programmierung taugt. Wer sich von ihrem Potenzial überzeuge möchte, sollte das freie Onlinebuch “Eloquent JavaScript” [14] konsultieren.

Einer der Gründe, Javascript als Sprache für Node.js zu wählen, war seinen Entwicklern zufolge, dass Javascript – ursprünglich aus Sicherheitsgründen – nie auf das Dateisystem zugreift. So ließ sich eine Laufzeitumgebung kreieren, deren Performance nicht von der I/O-Last des Systems abhängt.

Dabei dürfen die mit Node umgesetzten Anwendungen selbstverständlich auch auf Dateien zugreifen: Das Modul »file system« kapselt die üblichen Posix-Funktion. Praktisch alle seine Methoden akzeptieren eine Callbackfunktion als Parameter und laufen asynchron im Hintergrund ab. So erlauben sie die Umsetzung des Node-Credos: Der Codefluss endet an jeder Stelle, an der die Software auf externe Daten wartet. Erst eine Callbackfunktion holt den Fokus zurück, sobald das Einlesen abgeschlossen ist.

Weitere Node-Kernmodule sind das bereits vorgestellte Modul »Http« , das auch in einer Spielart für sichere Verbindungen vorliegt (»Https« ). »Net« öffnet TCP- oder Unix-Sockets, »TSL« Open-SSL-Verbindungen. DNS-Lookups sind mit »Dns« möglich. Es gibt einen Debugger, der Breakpoints setzt oder einen Einzelschritt-Modus aktiviert.

»Cluster« startet mehrere Node-Instanzen, um von Multiprozessorsystemen zu profitieren. Bisher ist dazu ein expliziter Aufruf im Programmcode erforderlich. Informationen über die Anzahl der Prozessoren liefert das Modul »Os« . Nach Aussage des Node.js-Initiators ist für künftige Node-Version auch ein Kommandozeilen-Parameter »–balance« geplant, der den Anwendungscode von dieser Aufgabe entbindet.

Wo sind die Tools?

Die Node.js-Pakete der meisten Distributionen bringen das grundlegende Handwerkszeug für des Erstellen von Webanwendungen inklusive Webserver mit. Viele Hilfsmittel, die Java-, PHP- oder Ruby-Entwickler als Selbstverständlichkeit betrachten, fehlen jedoch noch, zum Beispiel die Datenbankanbindung, ein Modell-View-Controller-Framework, ein Template-System oder eine Bibliothek für Standardaufgaben.

Wer sich jedoch im Github-Wiki des Node-Projekts die Liste der externen Module ansieht [15], stellt fest, dass in der kurzen Lebensdauer von Node.js bereits ein reiches Ökosystem an Erweiterungen herangewachsen ist. Dort sind mehrere Hundert Module gelistet, die viele Themenbereiche wie das Einbinden von MySQL, PostgreSQL oder SQLite und vieler No-SQL-Datenbanken, Erzeugen von Grafik- oder PDF-Dateien, Internationalisierung oder XML-Parsing abdecken.

Rails, Python, Ruby

Selbst größere Frameworks wie Railwayjs [16] oder Express-On-Railway [17], die beide einen Teil der Rails-Features nach Node.js portieren, gibt es bereits. Dafür, dass sich Module samt Abhängigkeiten bequem installieren lassen, sorgt der Paketmanager Npm [18], der sich als Quasi-Standard für Node.js etablierte.

Node.js ist nicht das einzige Webframework, das den so genannten Reactor-Design-Pattern für die Server-seitige Programmierung in einer Skriptsprache nutzbar macht. Bereits seit 2002 existiert das Python-Projekt Twisted [19], das wie Node.js eine Event-orientierte Architektur aufweist und wie dieses das Erstellen eines Webservers mit wenigen Zeilen Code erlaubt. Zu den Twisted-Nutzern zählen Canonical, das die Software für Launchpad und Ubuntu One einsetzt, und Lucasfilm, das damit die firmeneigene Render-Farm optimiert.

Auf Rubyforge gibt es seit April 2006 mit Eventmachine [20] eine Bibliothekskomponente mit ähnlicher Zielsetzung. Sowohl Twisted als auch Eventmachine eignen sich nicht nur für Server-, sondern auch für Client-Komponenten, doch laufen diese Python- oder Ruby-Anwendung nicht in einem Webbrowser.

Anwendungsbeispiel

Ein Anwendungsfall, bei dem es auch viel Arbeit spart, den gleichen Code auf dem Server und im Browser nutzen zu können, sind beispielsweise Client-seitige Plausibilitätschecks für Benutzereingaben. Hier prüft eine in Javascript geschriebene Programmlogik die Werte, die der Benutzer in ein Formular eingegeben hat, ohne sie vorher zum Server abzuschicken. So informiert sie den Anwender bei ungültigen Eingaben in Sekundenbruchteilen, ohne den Server zu beanspruchen. Aus Sicherheitsgründen muss der Server die Werte aber dennoch ein zweites Mal überprüfen. Mit Node.js ist es hier aber immerhin möglich, den Prüfcode beim Client und auf dem Server erneut zu verwenden.

Ein Nachteil von Node.js ist seine Jugend: Die Software bringt ein API, das sich nach Angaben der Entwickler “noch stark im Fluss” befindet. Dass im Moment existierende Anwendungen oft nicht mit der aktuellen Node.js-Version funktionieren, bekam auch der Autor des Linux-Magazins bei der Suche nach geeigneter Testsoftware zu spüren.

Hohe Performance trotz komplexer Struktur

Javascript und die hochperformante V8-Engine eignen sich allen Vorurteilen zum Trotz ausgezeichnet für die ereignisorientierte Server-seitige Programmierung. Bei Comet-Anwendungen bietet Node.js überragende Performance. Da diese Technik einen Echtzeit-nahen Server-Push erlaubt, lassen sich mit ihr Anwendungen für Online-Kooperation, -Kommunikation und -Spiele effizient umsetzen.

Die schiere Zahl der Bibliotheken und Frameworks, die seit 2009 aus dem Boden geschossen sind, überrascht und spiegelt das rege Interesse wieder, das Webentwickler der interessanten neuen Technik entgegenbringen. Bausätze mit einem Umfang wie Spring, Symfony, Rails oder Django sind allerdings noch nicht darunter.

Node.js wird es kaum gelingen, Platzhirsche wie Java, PHP, Ruby, Python oder Perl aus dem Feld zu schlagen, denn als Manko bleibt die durch die Ereignisorientierung verursachte komplizierte Codestruktur. Dafür kann die junge, aufstrebende Entwicklungsumgebung als Alleinstellungsmerkmal für sich verbuchen, dass sie viele Tausend Long-Polling-Requests ohne großen Speicherverbrauch verkraftet.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben