{"id":1001,"date":"2016-08-01T15:41:46","date_gmt":"2016-08-01T13:41:46","guid":{"rendered":"https:\/\/launix.de\/launix\/?p=1001"},"modified":"2023-07-11T12:21:56","modified_gmt":"2023-07-11T10:21:56","slug":"node-js-vs-phpapache","status":"publish","type":"post","link":"https:\/\/launix.de\/launix\/node-js-vs-phpapache\/","title":{"rendered":"Node.js vs PHP+Apache"},"content":{"rendered":"<p>PHP und Apache &#8211; die verbreitetste Technologie, um Web-Anwendungen umzusetzen. Nicht selten stecken beide Tools viel Kritik bez\u00fcglich ihrer Performance ein. Doch auch bez\u00fcglich des Sprachendesigns muss vor allem PHP viel hinnehmen. In diesem <a title=\"Blog-Eintrag \u00fcber das Design von PHP\" href=\"http:\/\/me.veekun.com\/blog\/2012\/04\/09\/php-a-fractal-of-bad-design\/\">Blog-Eintrag<\/a> werden die Hauptkritikpunkte zusammengefasst. Im gro\u00dfen und ganzen kann man das \u00d6kosystem um PHP als eine Sammlung von inkonsistenten 1:1-Wrappern zu C-Bibliotheken bezeichnen.<!--more--><\/p>\n<p>Dem entgegen stellt sich Node.js auf. Node.js ist ein asynchrones Kommunikations-Framework, das auf der JavaScript-Engine V8 von Google aufbaut, das oft f\u00fcr seine gute Performance und das gute Design gelobt wird.<\/p>\n<script async src=\"\/\/pagead2.googlesyndication.com\/pagead\/js\/adsbygoogle.js\"><\/script>\r\n<!-- responsive -->\r\n<ins class=\"adsbygoogle\"\r\n     style=\"display:block\"\r\n     data-ad-client=\"ca-pub-8447808153780075\"\r\n     data-ad-slot=\"6876660058\"\r\n     data-ad-format=\"auto\"><\/ins>\r\n<script>\r\n(adsbygoogle = window.adsbygoogle || []).push({});\r\n<\/script>\n<h2>Synchron vs Asynchron<\/h2>\n<p>Doch um den Unterschied zwischen den Kommunikationsmodellen von PHP und Node.js zu erl\u00e4utern, muss man etwas tiefer einsteigen: <em>was ist der Unterschied zwischen synchroner und asynchroner I\/O<\/em>?<\/p>\n<p>Bei synchroner oder auch blockierender I\/O bewirkt ein lesender Befehl, dass das Programm so lange einfriert, bis die zu lesenden Daten da sind. Die CPU verbringt also die meiste Zeit mit dem Warten auf Daten, aber nicht mit dem Rechnen, obwohl vielleicht einige Sachen noch gerechnet werden k\u00f6nnten. Damit ein Webserver trotz blockierender I\/O auch noch andere Anfragen beantworten kann, startet der Server einfach f\u00fcr jede Anfrage einen eigenen Thread. Es wird viel Arbeitsspeicher mit auf Daten wartenden Programmen belegt.<\/p>\n<p>Asynchrone Kommunikation dagegen verspricht eine bessere Nutzung der Ressourcen: Nach einem Lesebefehl sind die Daten noch nicht da, aber das Programm l\u00e4uft weiter. Es k\u00f6nnen weitere Lesebefehle abgesetzt werden. Erst, wenn alles getan wurde, was getan werden muss, wird gewartet. Im g\u00fcnstigsten Fall sind zu diesem Augenblick sogar schon die ersten Daten da und es kann mit dem Verarbeiten angefangen werden. Des weiteren k\u00f6nnen mehrere gleichzeitig ankommende Lesebefehle vom Betriebssystem besser verarbeitet werden, da zum Beispiel Linux Zugriffe auf Festplatten umsortiert, um den Lesekopf der Festplatte so wenig wie m\u00f6glich zu bewegen.<\/p>\n<script async src=\"\/\/pagead2.googlesyndication.com\/pagead\/js\/adsbygoogle.js\"><\/script>\r\n<!-- responsive -->\r\n<ins class=\"adsbygoogle\"\r\n     style=\"display:block\"\r\n     data-ad-client=\"ca-pub-8447808153780075\"\r\n     data-ad-slot=\"6876660058\"\r\n     data-ad-format=\"auto\"><\/ins>\r\n<script>\r\n(adsbygoogle = window.adsbygoogle || []).push({});\r\n<\/script>\n<p>In Node.js sieht das ganze derart aus, dass man zu einem lesenden Befehl eine Callback-Funktion angibt, die bei Ankunft der Daten ausgel\u00f6st werden soll. \u00dcber dieses Kommunikationsparadigma lassen sich asynchrone Programme entwickeln, die so viel I\/O wie m\u00f6glich losfeuern, anstatt jeweils auf Daten zu warten.<\/p>\n<h2>Der Benchmark<\/h2>\n<p>Vom Prinzip her ist das asynchrone I\/O-Konzept der synchronen Kommunikation \u00fcberlegen. Auch der in Node.js verwendeten V8-Engine bescheinigt man die 50-fache Verarbeitungsgeschwindigkeit von JavaScript gegen\u00fcber PHP.<\/p>\n<p>Doch abgesehen von diesen punktuellen Messungen und theoretischen \u00dcberlegungen &#8211; wieviel Vorteil bringt Node.js wirklich? Dazu folgender Versuchsaufbau:<\/p>\n<ul>\n<li>Eine Beispieldatenbank enth\u00e4lt 2 Tabellen mit jeweils 300 Eintr\u00e4gen, die abgefragt wird<\/li>\n<li>Ein Script soll zwei SQL-Abfragen losfeuern, alle Daten ausw\u00e4hlen und anschlie\u00dfend in HTML-Tabellen rendern<\/li>\n<li>Im ersten Versuchslauf wird die reine Rechenzeit des Standalone-Scripts mit dem Unix-Befehl time gemessen. Um die Startupzeit des Programms vernachl\u00e4ssigbar klein zu halten, wird der Code 1000 mal in einem Programmaufruf ausgef\u00fchrt<\/li>\n<li>Im zweiten Versuchsdurchlauf wird das Script in einem Webserver ausgef\u00fchrt und dieser Server wird mit Anfragen bombardiert<\/li>\n<\/ul>\n<h2>Der Code<\/h2>\n<p><a title=\"Code des PHP-Benchmarks\" href=\"http:\/\/launix.de\/ablage\/bench_php.php.html\" target=\"_blank\" rel=\"noopener\">Ansehen f\u00fcr PHP<\/a><\/p>\n<p><a title=\"Code des Node.js-Benchmarks\" href=\"http:\/\/launix.de\/ablage\/bench_node.js.html\" target=\"_blank\" rel=\"noopener\">Ansehen f\u00fcr Node.js<\/a><\/p>\n<p><a title=\"Code des Node.js-Benchmarks mit mysql-native-Adapter\" href=\"http:\/\/launix.de\/ablage\/bench_native.js.html\" target=\"_blank\" rel=\"noopener\">Ansehen f\u00fcr Node.js mit mysql-native (bessere Code-lesbarkeit)<\/a><\/p>\n<p>Die dazugeh\u00f6rige Beispieldatenbank kann man sich ebenfalls <a href=\"http:\/\/launix.de\/ablage\/mysqlsampledatabase.sql\" title=\"Beispieldatenbank\" target=\"_blank\" rel=\"noopener\">herunterladen<\/a>.<\/p>\n<h2>Die Ergebnisse<\/h2>\n<p>Im ersten Versuchsaufbau gibt es schon ein \u00fcberraschendes Ergebnis:<\/p>\n<table>\n<tbody>\n<tr>\n<th>PHP<\/th>\n<th>Node.js mit mysql<\/th>\n<th>Node.js mit mysql-native<\/th>\n<\/tr>\n<tr>\n<td>\n<pre>real 0m7.410s\r\nuser 0m3.653s\r\nsys 0m2.107s<\/pre>\n<\/td>\n<td>\n<pre>real 0m9.771s\r\nuser 0m6.707s\r\nsys 0m1.399s<\/pre>\n<\/td>\n<td>\n<pre>real\t0m7.533s\r\nuser\t0m5.249s\r\nsys\t0m0.984s<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Wie man sieht, ist PHP 2 Sekunden eher fertig und hat auch nur halb so viel CPU-Zeit &#8220;verbraten&#8221;. Nach einem Wechsel des MySQL-Adapters kommt man auf etwa die gleiche Laufzeit wie PHP, allerdings immer noch mit signifikant mehr vergeudeter Rechenzeit.<\/p>\n<p>Der zweite Versuchsaufbau gibt ein noch ersch\u00fctternderes Bild ab. Mit dem Benchmarktool &#8220;ab&#8221; von Apache wurde ein Anfragesturm auf die mit dem Versuchsprogramm eingerichteten Webserver losgelassen. Gearbeitet wurde einerseits mit den Parametern &#8220;ab -c 200 -n 20000&#8221; und mit &#8220;ab -c 20 -n 2000&#8221;. Der Parameter -c steht f\u00fcr die Anzahl gleichzeitiger Anfragen und -n steht f\u00fcr die Anzahl der GET-Requests, die insgesamt gefeuert werden sollen.<\/p>\n<p>Hier performt PHP+Apache 10 mal so schnell wie Node.js. Der Einsatz des mysql-native-Adapters in Node.js verschlechterte das Ergebnis hier sogar noch. Hier das ern\u00fcchternde Ergebnis:<\/p>\n<table style=\"width: 100%\" border=\"1\">\n<tbody>\n<tr>\n<th rowspan=\"2\">Wert<\/th>\n<th colspan=\"2\">PHP+Apache<\/th>\n<th colspan=\"2\">Node.js<\/th>\n<\/tr>\n<tr>\n<th>-c 20<\/th>\n<th>-c 200<\/th>\n<th>-c 20<\/th>\n<th>-c 200<\/th>\n<\/tr>\n<tr>\n<td>Anfragen\/s<\/td>\n<td style=\"text-align: right\">1173<\/td>\n<td style=\"text-align: right\">1146<\/td>\n<td style=\"text-align: right\">119<\/td>\n<td style=\"text-align: right\">114<\/td>\n<\/tr>\n<tr>\n<td>Antwortzeit in ms<\/td>\n<td style=\"text-align: right\">17<\/td>\n<td style=\"text-align: right\">174<\/td>\n<td style=\"text-align: right\">167<\/td>\n<td style=\"text-align: right\">1750<\/td>\n<\/tr>\n<tr>\n<td>Durchsatz in MiB\/s<\/td>\n<td style=\"text-align: right\">21<\/td>\n<td style=\"text-align: right\">20<\/td>\n<td style=\"text-align: right\">2<\/td>\n<td style=\"text-align: right\">2<\/td>\n<\/tr>\n<tr>\n<td>CPU-Auslastung<\/td>\n<td style=\"text-align: center\" colspan=\"2\">100%<br \/>\nauf allen<br \/>\n4 Kernen<\/td>\n<td style=\"text-align: center\" colspan=\"2\">80% Node.js<br \/>\n16% MySQL<br \/>\n16% MySQL<\/td>\n<\/tr>\n<tr>\n<td>Antwortzeit -c 1<\/td>\n<td style=\"text-align: center\" colspan=\"2\">9.4 ms<\/td>\n<td style=\"text-align: center\" colspan=\"2\">8.9 ms<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Wie man sieht, haben beide Server etwa gleichbleibenden Durchsatz, egal wieviel Anfragen gleichzeitig ankommen. Ein bisschen merkt man ihnen die Last allerdings an. Die Antwortzeit steigt ebenfalls bei beiden Servern proportional mit der Auslastung.<\/p>\n<p>Da Apache f\u00fcr jede Anfrage einen neuen PHP-Prozess startet, k\u00f6nnen alle 4 Kerne ausgelastet werden. Node.js hingegen arbeitet den Code nur auf einem Kern ab und benutzt mehrere Threads nur, um blockierende IO-Operationen abzufangen. PHP kann also bis zu 4 mal mehr Ressourcen auslasten als Node.js. Hinzu kommt, dass PHP im ersten Benchmark nur etwa halb so viel CPU-Zeit verbraucht hat bei etwa gleicher Ausf\u00fchrungszeit. <strong>Alles in allem erreicht Node.js somit nur ein Zehntel des Durchsatzes von PHP+Apache.<\/strong><\/p>\n<h2>Fazit<\/h2>\n<p>Der Faktor 10 ist kein endg\u00fcltiges Kriterium. W\u00fcrde man den Node.js-Server replizieren und die Lasten ausbalancieren, k\u00f6nnte man zumindest alle 4 Kerne des Servers auslasten und &#8220;nur noch&#8221; 2.5 mal langsamer als PHP+Apache sein. Stecken die Node.js-Entwickler jetzt noch ein bisschen Arbeit in die Mikrooptimierung des Frameworks, lassen sich bestimmt noch bessere Ergebnisse erzielen. Denn ein gro\u00dfer Teil der CPU-Zeit d\u00fcrfte Node.js f\u00fcr die Umrechnung von Strings in Buffer zu verwenden.<\/p>\n<p>F\u00fcr praktische Einsatzzwecke, wo es auf den Datendurchsatz ankommt, sollte man allerdings beim bereits bew\u00e4hrten und optimierten PHP bleiben. Vielleicht wendet sich das Blatt, aber bisdahin wird noch viel Wasser die Spree hinunterflie\u00dfen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>PHP und Apache &#8211; die verbreitetste Technologie, um Web-Anwendungen umzusetzen. Nicht selten stecken beide Tools viel Kritik bez\u00fcglich ihrer Performance ein. Doch auch bez\u00fcglich des Sprachendesigns muss vor allem PHP viel hinnehmen. In diesem Blog-Eintrag werden die Hauptkritikpunkte zusammengefasst. Im gro\u00dfen und ganzen kann man das \u00d6kosystem um PHP als eine Sammlung von inkonsistenten 1:1-Wrappern&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","_uag_custom_page_level_css":"","footnotes":""},"categories":[128],"tags":[72],"class_list":["post-1001","post","type-post","status-publish","format-standard","hentry","category-programming","tag-programmieren","single-item"],"featured_image_urls_v2":{"full":"","thumbnail":"","medium":"","medium_large":"","large":"","1536x1536":"","2048x2048":"","trp-custom-language-flag":"","xs-thumb":"","appku-shop-single":""},"post_excerpt_stackable_v2":"<p>PHP und Apache &#8211; die verbreitetste Technologie, um Web-Anwendungen umzusetzen. Nicht selten stecken beide Tools viel Kritik bez\u00fcglich ihrer Performance ein. Doch auch bez\u00fcglich des Sprachendesigns muss vor allem PHP viel hinnehmen. In diesem Blog-Eintrag werden die Hauptkritikpunkte zusammengefasst. Im gro\u00dfen und ganzen kann man das \u00d6kosystem um PHP als eine Sammlung von inkonsistenten 1:1-Wrappern zu C-Bibliotheken bezeichnen. Dem entgegen stellt sich Node.js auf. Node.js ist ein asynchrones Kommunikations-Framework, das auf der JavaScript-Engine V8 von Google aufbaut, das oft f\u00fcr seine gute Performance und das gute Design gelobt wird. Synchron vs Asynchron Doch um den Unterschied zwischen den Kommunikationsmodellen von&hellip;<\/p>\n","category_list_v2":"<a href=\"https:\/\/launix.de\/launix\/category\/programming\/\" rel=\"category tag\">Programming<\/a>","author_info_v2":{"name":"Carl-Philip H\u00e4nsch","url":"https:\/\/launix.de\/launix\/author\/carli\/"},"comments_num_v2":"0 comments","uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false,"trp-custom-language-flag":false,"xs-thumb":false,"appku-shop-single":false},"uagb_author_info":{"display_name":"Carl-Philip H\u00e4nsch","author_link":"https:\/\/launix.de\/launix\/author\/carli\/"},"uagb_comment_info":0,"uagb_excerpt":"PHP und Apache &#8211; die verbreitetste Technologie, um Web-Anwendungen umzusetzen. Nicht selten stecken beide Tools viel Kritik bez\u00fcglich ihrer Performance ein. Doch auch bez\u00fcglich des Sprachendesigns muss vor allem PHP viel hinnehmen. In diesem Blog-Eintrag werden die Hauptkritikpunkte zusammengefasst. Im gro\u00dfen und ganzen kann man das \u00d6kosystem um PHP als eine Sammlung von inkonsistenten 1:1-Wrappern...","_links":{"self":[{"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/posts\/1001","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/comments?post=1001"}],"version-history":[{"count":6,"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/posts\/1001\/revisions"}],"predecessor-version":[{"id":5371,"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/posts\/1001\/revisions\/5371"}],"wp:attachment":[{"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/media?parent=1001"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/categories?post=1001"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/launix.de\/launix\/wp-json\/wp\/v2\/tags?post=1001"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}