Ein Beispiel, warum Node.js schneller ist als PHP

Ich wollte mal überprüfen warum um Node.js ein solcher Wirbel veranstaltet wird, also habe ich mich entschlossen ein paar Kopf an Kopf Rennen, oder besser gesagt Belastungstests mit Ghost (Node.js) und WordPress (php) durchzuführen. Die Ergebnisse waren beeindruckend, wobei WordPress Ghost einfach nicht nachkommen konnte. Es war, als würde man ein Rennen zwischen einem Raumschiff und einem Flugzeug beobachten (naja, so stelle ich mir das jedenfalls vor).

Es gibt eine noch relativ neue Blogging-Plattform, die erst vor Kurzem der Öffentlichkeit vorgestellt wurde – Ghost. Was Ghost so interessant macht, ist, dass es auf der Node.js-Plattform aufgebaut wurde. Wenn ihr Node.js noch nicht kennt, lest gerne meinen Blog-Post darüber. Wenn euch jedoch Ghost noch nicht bekannt ist, könnt ihr auch hier über das Kickstarter-Projekt lesen.

Der Set-up

Als Hintergrund, Ghost ist eine Blogging-Plattform und nicht mehr, wobei WordPress ein vollwertiges CMS, also ein Content Management System ist. Ich wollte diesen Vergleich so gerecht wie nur möglich gestalten, also habe ich mein Skripting zum Belastungstest limitiert, sodass nur die Blogseiten verglichen werden. Ich wollte zudem auch noch die Erfahrung „out of the box“ testen, also habe ich keine Einstellungsänderungen bei diesen Plattformen vorgenommen (außer, dass ich beide mit meinem MySQL verbunden habe). Ich habe also eine einzelne 64-bit RHEL m1.large (Referenzen bezüglich der Server spezifischen Größenzuteilung im Bild unten) EC2-Instanz auf Amazon zusammengesponnen, um beide Blogging-Plattformen zu hosten.

Amazon Server Sizes

Ich wollte die am häufigsten vorkommenden Einstellungen testen, wofür ich NginX zum Frontend für Ghost und Apache zum Frontend für WordPress benutzt habe. Beide Plattformen nutzen dieselbe lokale MySQL Backend Datenbank (Ghost kommt mit SQLite als Standard, aber ich wollte sichergehen, dass die Testbedingungen vergleichbar waren).

Ich hatte beide, Ghost (auf Port 80) und WordPress (auf Port 8080) gleichzeitig laufen, belastete aber  jeweils immer nur eine Blogging-Plattform.

Das bringt mich zum Thema Belastungserzeugung für dieses kleine Experiment. Ich habe noch eine weitere EC2-Instanz (64-bit Ubuntu, Größe m1.medium – Referenzen bezüglich der Server spezifischen Größenzuteilung im Bild unten) in derselben Verfügbarkeitszone generiert um zu versuchen die Netzwerkbelastung auf die Testergebnisse zu minimalisieren. Dann habe ich meinen Kollegen @dustinwhittle gefragt, ob er mir eine Belastungstesteinstellung empfehlen könnte und er hat mich zu seinem Blog-Post über Belastungstestwerkzeuge geschickt und mir dazu empfohlen, eine Kombination aus Siege und Sproxy zu benutzen.

Nach der Installation und einem kurzen Funktionstest der Blog-Plattformen, habe ich einfach eine Blog-Reihe mit 8 Teilen in einfachem Text und ohne Bilder erstellt und alle  bisher existierenden Blogs entfernt. In WordPress behielt ich alle Standard-URL-Profile bei und habe KEINE Permalinks eingefügt, um das Ganze durch den Gebrauch dieser Funktion nicht zu verlangsamen. Es wurden ebenfalls keine Caching Technologien für WordPress eingestellt, da ich ja versuchen wollte, die „out of the Box“-Erfahrung zu messen. Ich habe also absolut kein Tuning oder Änderungen an den Plattformen vorgenommen.

Die andere wichtige Konfiguration, die ich erwähnen sollte, ist, dass ich den AppDynamics Machine Agent benutzt habe, um die OS-Metriken während dieser Belastungstests zu erfassen und aufzuzeichnen.

Die Tests

Damit ich Siege dazu benutzen konnte, die vielen mitlaufenden Verbindungen gegen die vielen URLs zu testen, musste ich zuerst diese URLs in einer Textdatei auflisten. Hierfür benutzte ich Sproxy. Referenz: Folien 20-23 der folgenden Präsentation über genauere Details, wie man Sproxy benutzt https://speakerdeck.com/dustinwhittle/agile-performance-testing-checklist

Ich ließ Sproxy durch beide, Ghost und WordPress laufen und bekam meine Liste an URLs. Diese Dateien habe ich dann modifiziert, sodass beide genau die gleichen Blog-Post Listen enthalten und die Belastungstests so ähnlich ablaufen können, wie möglich. Hier sind die verwendeten Dateien.

Ghost Load Test URLS

Wordpress Load Test URLS

Jetzt war ich dann endlich so weit, mit Siege loszulegen und anzufangen die Blogs zu belasten. Siege ist ein cooles Tool, das einem erlaubt, einige Parameter zu manipulieren. Die, mit denen ich am meisten experimentiert habe, waren die Anzahl der mitlaufenden Verbindungen (-c) und die Verzögerungen (-d in Sekunden) zwischen den Requests. Hier ist ein Befehl, den man zB benutzen kann … siege -v -c 100 -i -t 10M -f urls.txt -d 1

Die Ergebnisse

In einem Wort, Hammer! Siege ist für 10 Minuten mit 100 mitlaufenden Verbindungen und 1s Verzögerung zwischen den Requests gelaufen. Die Ergebnisse sieht man unten …

Ghost Performance Under Heavy Load

Siege Belastungs-Testergebnisse für Ghost mit Nginx unter schwerer Belastung.

Wordpress Siege Results

Siege Belastungs-Testergebnisse für WordPress und Apache unter schwerer Belastung.

Wie man in dem obigen Auszug ganz klar sehen kann, ist Ghost mit Nginx WordPress mit Apache um 678% ganz klar überlegen wenn man sich die Gesamtzahl aller Transaktions-Datendurchsätze während dieses 10-minütigen Tests ansieht. Beeindruckend ist, dass die längste Transaktions-Reaktionszeit von Ghost nur 2.62 Sekunden war, verglichen mit den miserablen 33.41 Sekunden von WordPress. Ich habe diese Tests mehrfach wiederholt und erhielt sehr ähnliche Ergebnisse, also zeige ich die restlichen Testergebnisse nicht auf, da sie überflüssig sind. Mein Ziel ist hier nicht, eine umfangreiche Analyse der Leistung mit verschiedenen Belastungen durchzuführen, sondern eher eine besonders große Belastung zu erzielen und zu sehen, wie die einzelnen Plattformen diese jeweils verarbeiten.

Man sollte ein paar andere Datenpunkte beachten. Während des Belastungstests lief Ghost nur mit 1 Prozess und Nginx hatte insgesamt 2 Prozesse. WordPress und Apache allerdings erzeugten insgesamt ~110 httpd-Prozesse, was Sinn macht, denn Siege bombardierte es mit 100 mitlaufenden Verbindungen. Sehr interessant sind die CPU-Daten des Belastungstests. Ich habe den Durchschnitt, die Minimum und Maximum CPU-Nutzung unten auf der Grafik aufgezeichnet. Man kann deutlich sehen, dass Ghost’s CPU-Verbrauch ungefähr bei 40% lag, während der Verbrauch von WordPress bei ungefähr 70% lag.

Ghost Heavy Load - AppDynamics

CPU-Verbrauch während des Ghost-Belastungstests zeigt die Durchschnitts-, Minimum- und Maximumwerte.

Wordpress Heavy Load - AppDynamics

CPU-Verbrauch während des WordPress-Belastungstests zeigt die Durchschnitts-, Minimum- und Maximumwerte.

Also, ich habe die normalen Belastungsmodelle natürlich nicht vergessen. Wie sehen die Dinge mit moderater Belastung, im Vergleich zu der sehr hohen Belastung der 100 mitlaufenden Verbindungen, aus? Um das herauszufinden, habe ich die Anzahl der mitlaufenden Verbindungen bis auf 10 gesenkt und die Verzögerung zwischen den Schüben auf 5 Sekunden erhöht. Die Ergebnisse seht ihr unten und diese sind immer noch unglaublich beeindruckend für Ghost. WordPress war erneut in allen Bereichen weit unterlegen. Ghost hatte höhere Durchläufe und viel wichtiger, die langsamste Transaktions-Reaktionszeit lag bei .18 Sekunden verglichen mit den 2.27 Sekunden bei WordPress. Vom CPU-Standpunkt aus verbrauchte Ghost durchschnittlich nur ~4% während des Tests, während WordPress durchschnittlich ~30% verbrauchte.

Siege load test results for Ghost with Nginx under light load.

Siege Belastungs-Testergebnisse für Ghost mit Nginx unter leichter Belastung.

Siege load test results for WordPress with Apache under light load.

Siege Belastungs-Testergebnisse für WordPress mit Apache unter leichter Belastung.

Update vom 18.10.2013 – Das ist unfair!!! Äpfel und Birnen!!!

Es wurde behauptet, dass ich Äpfel mit Birnen vergleiche. Dazu kann ich nur sagen, na klar! In diesem Post hatte ich mir vorgenommen, die allgemeinen Kombinationen von Nginx + Ghost und Apache + WordPress zu vergleichen. Ich hatte mir vorgenommen, diese in ihren einfachsten Grundformen zu vergleichen, ohne Einstellungen, ohne Tuning, ohne Caching, nur das, was man „aus der Box“ bekommt. Aber ich verstehe den Protest und habe mich entschlossen, das Spielfeld ein bisschen auszugleichen. Viele meinten, dass Apache einen Engpass darstellte, also habe ich mich hier dazu entschieden, Apache als Frontend Webserver für Ghost zu benutzen und meine Belastungstests noch einmal durchzuführen. Ich habe auch hier wieder mehrere Tests laufen lassen, aber sie waren alle sehr konsistent, daher hier ein Auszug der Ergebnisse (siehe unten).

Apache and Ghost Siege Results

Belastungs-Testergebnisse von Apache + Ghost.

Load test results for Nginx + Ghost for easy comparison with the results above.

Belastungs-Testergebnisse von Nginx + Ghost zum leichteren Vergleich mit den obigen Ergebnissen.

Die hier gezeigten Ergebnisse sind interessant. Apache + Ghost war sogar etwas SCHNELLER als Ghost mit Nginx. Ghost ist immer noch superschnell, egal ob es mit Apache oder Nginx als Webserver läuft.

Fazit

Ghost ist viel schneller und hält viel mehr Belastung aus als WordPress und konsumiert dabei viel weniger CPU-Ressourcen (Ghost hat wohlgemerkt auch deutlich weniger Funktionen als WordPress, aber das spielt für diesen Test keine Rolle). Es wäre interessant, Ghost in einem 2-Prozess Node.js-Cluster laufen zu lassen und zu sehen, ob es einen Unterschied beim Datendurchsatz und CPU-Verbrauch macht. Hmmmm, das klingt wie ein wirklich gutes Thema für einen weiteren Blog-Post …

Ein anderes interessantes Thema, welches ich hier gar nicht angesprochen habe, ist das Monitoring beider Plattformen. Meiner Meinung nach ist es nicht genug, nur das Verhalten dieser Plattformen von außen zu beobachten. Ich will auch wissen, was da drinnen vor sich geht. In einem zukünftigen Blog-Post werde ich Ghost mit Nodetime überwachen und WordPress mit AppDynamics. Ich kann es kaum erwarten zu sehen, wie die beiden von innen aussehen!

Update vom 14.11.2013: Aufgrund mehrerer Anfragen habe ich weitere Tests durchgeführt, diesmal mit einer Opcode-Cache für PHP. Man kann alles hier nachlesen:  Ein Beispiel, warum Node.js schneller ist als PHP – Teil 2

Anhang

Hier sind die Links mit den Informationen, die ich benutzt habe, um meine Blogging- und Testplattformen aufzubauen (Ich habe mich bei den Einstellungen an die Angaben im jeweiligen Artikel gehalten, da meine Einstellungen etwas anders sind):

Wie man Node.js installiert: https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager

Wie man Ghost installiert: http://docs.ghost.org/installation/

Wie man MySQL installiert: http://www.cyberciti.biz/faq/how-to-install-mysql-under-rhel/

Wie man NginX installiert und konfiguriert und MySQL benutzt: http://0v.org/installing-ghost-on-ubuntu-nginx-and-mysql/#.Ul26n2RATL4

Wo man Siege findet: http://www.joedog.org/siege-home/

Wo man Sproxy findet: http://www.joedog.org/sproxy-home/

Weitere gute Informationen über den Gebrauch von Siege und Sproxy: http://www.euperia.com/linux/tools-and-utilities/speed-testing-your-website-with-siege-part-two/771

Dieser Artikel wurde aus dem Englischen übersetzt. Den originalen Text finden Sie hier: blog.appdynamics.com/nodejs/an-example-of-how-node-js-is-faster-than-php