Tag "apache"

Tierisch Traffic: „206 partial content“ mit dem iPhone

16. November 2009

Kam kürzlich ein Anruf meiner Hosterin: Ob mit meiner Website soweit alles in Ordnung sei, der Traffic würde sich in so relativ astronomischen Regionen bewegen (und in meinem „Asbach Uralt“-Tarif sei ja nun einmal nicht soviel Inklusiv-Bandbreite enthalten)?

Angeregt durch den freundlichen Hinweis suchte ich dann die gute alte Logfile-Statistik auf und staunte Bauklötze: Namentlich die beiden Baby-Einschlafhilfen „Fön“ und „Wasserhahn“ brachten es im Oktober gemeinsam auf satte 50GB Transfervolumen. Und über 8.700 Downloads. Irre.

Haartrockner-Traffic.png

Da sind wir doch auf die Logfile-Einträge gespannt – halt, was ist das? Der Großteil der Zugriffe auf die Dateien kommt von iPhones??

iphone-hits.png

Startet da etwa jemand mit einem hochgezüchteten iPhone eine Denial of Service-Attacke auf mein Blog? Zu Hilfe!

Des Rätsels Lösung: Das iPhone kann direkt im Browser MP3-Dateien abspielen. In diesem Fall ruft das Gerät aber nicht sofort die komplette Datei ab, sondern nur das jeweils benötigte Häppchen. Das ist z.B. von Vorteil, wenn man gleich bis kurz vor das Ende der Datei skippen möchte – es muss dann nicht erst gewartet werden, bis die vorher kommenden 90% der Datei durch die dünne Funkanbindung gekleckert sind. Das Telefon fragt beim Webserver mit einem sogenannten „Range Request“ direkt nach einem bestimmten Teil der Datei. Ebenso arbeiten auch Download-Beschleuniger, welche mehrere Teile einer Datei parallel herunterladen (nicht immer sehr ressourcenfreundlich). Wird ein Range-Request vom Webserver unterstützt, schlägt sich die Antwort im Logfile vermutlich mit dem HTTP-Statuscode „206 partial content“ nieder. Im Screenshot direkt neben der Spalte mit der 206 steht die übertragene Datenmenge – du liebe Güte, das sind immer über 16MB! Die Frage ist: Ist das auch wirklich immer durch die Leitung gewandert?

Wie die Gegenprobe mit dem Servermodul mod_logio ans Licht bringt, verlässt tatsächlich nur ein Bruchteil der Datenmenge bei den iPhone-Anfragen den Server (die letzten beiden Spalten stehen für eingehenden und ausgehenden Verkehr):

Bild 3.png

Das die Logfiles derart daneben liegen können, muss einem ja erst einmal gesagt werden. Meine 50GB Traffic sehen jedenfalls auf einmal ganz schön klein aus.

Da mod_logio dem Server zusätzlichen Aufwand beschert, wird aber sicherlich kaum ein Shared Hosting-Anbieter das Modul im normalen Betrieb ständig mitlaufen lassen.

Wir lernen:

  • Traue nicht den Traffic-Angaben aus den Logfiles.
  • Den richtigen Traffic misst man am besten dort, wo er entsteht – im Inneren des Netzwerk-Interface.

Prefetching verhindern – Traffic sparen

18. August 2007

Prefetching: was soll das denn sein?

Das ist zunächst mal ein ganz netter Mechanismus, mit dem es möglich wird, den Browser „vorausschauend“ mit dem Laden von Dateien zu beauftragen, die er demnächst brauchen könnte.

Bei einer Website, auf der die Pfade der Besucher leicht voraussehbar sind (z.B. wenn nur die Wahl zwischen „vorige Seite“ und „nächste Seite“ besteht), ließe sich sagen: gut, dann kann der Browser auch schon mal anfangen die nächste Seite zu saugen, wenn er schon sonst nichts zu tun hat. Realisiert wird das über das rel-Attribut in <link>-Tag, Metatag oder HTTP-Header. Beispiel:

[html]
[/html]

Nützliches Feature oder Traffic-Monster?

Das ist ja schön und gut, sofern ich selbst meinen Besuchern das Prefetching meiner Seiten nahelege. Benutzt wird Prefetching aber z.B. auch vom Suchriesen Google, der gerne mal die vordersten Suchergebnisse von den Browsern seiner Besucher saugen lässt (Herrjeh! Es könnte ja sein, dass da jemand draufklickt!).

Websites in den vorderen Rängen der Suchergebnisse kann auf diese Art durchaus eine Menge „ins blaue“ verusachter Datenverkehr blühen, der nicht mehr im gesunden Verhältnis zu den Besucherzahlen steht. Und wenn das großen Portalen noch egal sein mag – Otto Normalwebmaster rauft sich vielleicht die Haare.

Auch Proxies oder Tools wie der Google Web Accelerator arbeiten zur „gefühlten“ Beschleunigung des Surfens mit Prefetching

Zeig mir deinen HTTP-Header

Gegenwärtig wird Prefetching von iCab (*staun*), dem Mozilla Firefox und seinen Brüdern sowie dem Google Web Accelerator unterstützt. Führen diese Prefetching-Anfragen aus, wird der folgende Header mitgesendet:

[code]X-moz: prefetch[/code]

Möchte ich nicht, dass mein Server seine (Rechen-)Zeit mit solchen Anfragen vergeudet, kann ich die Anfrage abfangen und verwerfen, indem ich meine .htaccess-Datei ein wenig tune:

[code]RewriteEngine On
SetEnvIfNoCase X-moz prefetch IST_PREFETCH=1
RewriteCond %{ENV:IST_PREFETCH} 1
RewriteRule .* 503.php [L][/code]

Man beachte: statt dem Client einfach ein „Forbidden“ vorzusetzen, ist der HTTP-Status „503 Service Temporarily Unavailable“ angebracht – kommt der Zugriff von einem Suchmaschinen-Robot, wirft der uns am Ende sonst noch die Seite aus dem Index! Deswegen verpassen wir ihm eine „höfliche“ Abfuhr in gestalt des Robot-sicheren 503-Status‘ und geben ihm mit auf den Heimweg, dass er die Seite demnächst hier wieder abholen darf 🙂

Allein mit mod_rewrite ist das leider nicht möglich, deswegen behelfen wir uns einfach mit einem kurzen PHP-Script. Der Inhalt von 503.php kann z.B. so aussehen:

[html] header(‚HTTP/1.1 503 Service Temporarily Unavailable‘);[/html]

Und das war’s schon! Anhand der im Logfile notierten 503-Codes kann man sich in absehbarer Zeit anschauen, wieviele Zugriffe gespart wurden, jedenfalls sofern der Server keine anderen schwerwiegenden Probleme hat 🙂

Serverlast dynamisch reduzieren

Dieser kleine Trick ist nicht nur für Geizkragen geeignet: habe ich tatsächlich einen Webserver der zwischendrin wirklich mit starken Auslastungen zu kämpfen hat, kann ich die Prefetching-Sperre auch als dynamisch an- und ausschaltbares Feature implementieren.

Siehe auch:

gz-Kompression für statische Dateien mit Apache und PHP

26. Februar 2007

„Der erste Eindruck zählt“ gilt bei einer Website nicht nur für die Optik, sondern auch für die Geschwindigkeit mit der die Seite geladen wird. Und auch trotz schlankem Quellcode bringt eine Webseite mit all ihren Bildern, Stylesheets, Javascript-Frameworks schnell eine stattliche Größe von mehreren 100KByte auf die Waage, die erstmal durch die Leitung müssen.

Dann schlägt beim Apache-Webserver eigentlich die Stunde für Module wie mod_gzip oder mod_deflate, die für Kompression bei der Übertragung zuständig sind. Gerade diese Helferlein stehen beim Billighoster aber höchst selten zur Verfügung. Der Hoster muss in der Regel mit seiner Prozessorkraft haushalten – und wo käme man da hin, wenn jeder so mirnichts–dirnichts Rechenpower für das Komprimieren von Daten abzweigen kann (um Traffic zu sparen, den man genausogut teuer verkaufen kann)?

Scripte & Stylesheets komprimieren
Scripte und Stylesheets schreien dabei geradezu nach komprimierter Übertragung, bestehen sie doch aus Kompressions-freundlichem ASCII-Gebräu. Wie kriegt man diese Dateien also klein, ohne mod_gzip / mod_deflate zu bemühen?

Kompression mit PHP
Nun gut – dann muss der PHP-Interpreter herhalten: Kompression anschalten, Dateiinhalt ausgeben ausgeben (natürlich mit dem entsprechenden Header), fertig.

Als Beispiel soll mal die Datei „prototype.js“ des Prototype-Frameworks herhalten, die unkomprimiert immerhin an die 72KByte auf die Waage bringt.

ob_start("ob_gzhandler");
header('Content-Type: text/javascript');
print (...); //JavaScript-Code ausgeben

Und siehe da: der Firefox weist ca. 15KByte übertragene Daten aus – „mal eben“ 80% Ladezeit gespart …

Schönheitsfehler Dateiendung
Abzüge in der B-Note gibt es für die falsche Dateiendung: damit die umgepolte Javascript-Datei vom PHP-Parser verarbeitet wird, muss die Endung .php sein. Da weisen wir den Apache per .htaccess-Datei doch lieber gleich darauf hin, dass .js-Dateien ab jetzt PHP-Code enthalten:

AddType application/x-httpd-php .js .php

(Obacht: die Art, wie dies eingestellt wird kann schonmal von Hoster zu Hoster verschieden sein.)

Kompression ohne Caching ist Quatsch
Indem ich alle .js-Dateien zu dynamische Seiten „befördere“, kann die Datei nicht mehr gecached werden und wird bei jedem Seitenaufruf neu geladen. Oopsie! In meinem Beispiel habe ich also schlimmstenfalls nach 5 Seitenimpressionen a 15KByte den gewonnenen Vorteil wieder verspielt. Wer „A“ sagt, muss also auch …

… den Browser zum Cachen ermuntern
Header-Informationen über den Zeitpunkt der letzten Änderung an der Datei kann der Webserver nicht an den Browser senden, weil wir PHP benutzen – dynamische Seiten ändern sich eben ständig!
Das erledigen wir also von Hand, indem wir den entsprechenden „Last-Modified“ Header selbst erzeugen.

Und damit das auch den gewünschten Effekt zeigt, müssen wir vor der Ausgabe des Dateiinhalts prüfen, ob der Browser noch eine aktuelle Version besitzt („If-modified-since“-Header). Ist das der Fall, senden wir eine „304 Not Modified“-Antwort – die Datei muss nicht übertragen werden, Zeit und Traffic werden gespart. Hurrah!

Es kommt noch besser: mit der HTTP::Header::Cache() Klasse aus dem PEAR-Repository bringt man seinen dynamischen Dateien im Handumdrehen statische Verhaltensweisen bei und muss nicht das Rad neu erfinden:

require('HTTP/Header/Cache.php');
$header = new HTTP_Header_Cache(1,'days');
$header->sendHeaders();
$date=HTTP::date();

Das „Haltbarkeitsdatum“ der Datei setze ich einfach mal auf 24 Stunden an. Die Cache-Klasse prüft nun, ob der Browser noch eine gültige Version der Datei besitzt – ist das der Fall, wird der besagte 304-Header abgesendet und das Script beendet.

Plug & Play
Alle seine Scripte und Stylesheets mit PHP-Code vollzustopfen macht auch nicht grade viel Spaß. Darum weise ich den Server per .htaccess-Datei an, in meinem Script-Ordner allen PHP-Dateien automatisch die Datei prepend.php voranzustellen.

php_value auto_prepend_file prepend.php

Da sich alle zum Einleiten der Kompression nötigen Schritte vor der Ausgabe abspielen (logisch), brauche ich die zu komprimierenden Dateien auf diese Art gar nicht ändern. Einen bitteren Nachgeschmack hinterlässt, dass der PHP-Interpreter die nachfolgende Script/Stylesheet-Datei vergeblich nach PHP-Code durchwühlt. Da bleibt noch Raum für spannende Verbesserungen, aber das soll uns erstmal nicht interessieren.

Diese Lösung gewinnt vielleicht keine Benchmarks, trägt aber vielleicht ein wenig zur verbesserten Benutzererfahrung bei.

Fehlerseiten richtig definieren

15. März 2006

Wenn die schicke neue Website erstmal online gegangen ist, verliert man beim Relaunch gerne die Suchmaschinen aus den Augen. Diese schicken nach großen Änderungen auch mal gerne Besucher um Besucher ins Nirwana – solange bis die Spider die Datenbestände aktualisiert haben. Der Webserver kann nun wenig anderes tun, als dem Besucher eine Fehlermeldung zuzusenden, doch wie sieht die aus?

Der HTTP-Statuscode 404 „Not found“ wird im einfachsten Fall mit einer recht hässlichen, in HTML gekleideten Textmeldung quittiert. Häufig anzutreffen – und besonders „uncool“ – sind auch die Standard-Fehlerseiten der Massenhoster. Weder das eine noch das andere gibt dem Besucher die Möglichkeit, würdevoll auf die eigentliche Website zu gelangen, und so sucht er das Weite.
Dabei kann man dem Apache-Webserver mit einer einzigen Zeile in der Datei .htaccess auch weitaus besseres entlocken.

Den Rest des Beitrags lesen »