mod_gzip, mod_deflate und sonstige Komprimierungsverfahren für Web-Inhalte

Bei den meisten Webprojekten dauert die Übertragung des HTML-Codes zum Client länger als die Generierung der Inhalte auf dem Server. Zusätzlich besteht immer das Problem, dass Bandbreite auf Servern / Webhosting-Paketen oft (teuer bezahlte) Mangelware ist. Dieses Problem und wie man es umgehen kann, habe ich bereits in einem früheren Beitrag beschrieben. Diesmal möchte ich weitere Möglichkeiten der Bandbreiteneinsparung zusammenfassen.

Die Basis für die Komprimierung des HTML-Codes ist es, dass moderne Browser mit GZIP umgehen können. Dazu senden Sie einen entsprechenden Header-Eintrag im HTTP-Request namens Accept-Encoding. Anhand dieses Eintrags kann serverseitig bestimmt werden, ob der Browser des anfragenden Clients GZIP-Koprimierung der Inhalte unterstützt. Wenn ja, darf man diese Möglichkeit auch nutzen und kann alle zum CLient zu übertragenden Inhalte komprimieren. Das spart bis zu 80%!

Doch vorweg noch eine andere Sache: Alle hier genannten Komprimierungsverfahren sind nur sinnvoll, wenn die serverseitige Generierung des HTML-Codes wirklich schneller ist als die Übertragung zum Client. Wenn ihr mehrsekündige SQL-Abfragen ausführt, solltet ihr auf Komprimierung lieber verzichten, da die Komprimierung stets warten muss bis das gesamte HTML-Dokument fertig ist. Wenn ihr also solch lange Abfragen habt und diese auch nicht verbessert bekommt, dann solltet ihr auf Komprimierung verzichten, da der User dann zumindest schon etwas von der Seite sieht und nicht ewig warten muss.
Also: Erster Schritt ist die Optimierung der SQL-Abfragen bzw. allgemein der Seitengenerierung (eventuell durch Caching) und anschließend die GZIP-Komprimierung.

Nun gibt es mehrere Möglichkeiten die Komprimierung vorzunehmen: mod_gzip, mod_deflate, ob_gzhandler.

mod_gzip und mod_deflate
Der Apache-Webserver (und andere auch, aber ich möchte es anhand des Apache beschreiben) unterstützt die GZIP-Komprimierung ohne Code-Veränderung der Anwendung. Das bedeutet ihr müsst nicht eure ganzen Scripte umschreiben, sondern steuert alles über besagte Module mod_gzip und mod_deflate sowie die .htaccess-Datei. Ob mod_gzip oder mod_deflate derzeit installiert ist, lässt sich einfach per phpinfo() prüfen.

Die Komprimierung mit mod_deflate aktiviert man nun, indem folgende Zeilen in die .htaccess geschrieben werden:

# Komprimierung nach MIME-Type: Text, HTML und XML komprimieren
AddOutputFilterByType DEFLATE text/html text/plain text/xml   
  
# ODER: bestimmte Dateiendungen komprimieren (hier .html)
<Files *.html>
SetOutputFilter DEFLATE   
</Files>
Nun werden also alle angegebenen Dateien gepuffert und komprimiert.

Eine andere feine Geschichte ist es, dass man nicht nur HTML sondern auch andere Textdaten komprimieren kann (CSS, JavaScript und was man sonst noch so hat):

<Location />  
  SetOutputFilter DEFLATE   
  SetEnvIfNoCase Request_URI  \   
        \.(?:gif|jpe?g|png)$ no-gzip dont-vary   
  SetEnvIfNoCase Request_URI  \   
        \.(?:exe|t?gz|zip|gz2|sit|rar)$ no-gzip dont-vary   
</Location>
Diese Variante komprimiert alle Daten außer Bildern und Binärdaten (exe sowie bereits komprimiete Archive).

Wer mod_gzip hat, der muss einen anderen Code in die .htaccess eintragen.

<IfModule mod_gzip.c>  
    mod_gzip_on       Yes   
    mod_gzip_dechunk  Yes   
    mod_gzip_item_include file      \.(html?|txt|css|js|php|pl)$   
    mod_gzip_item_include handler   ^cgi-script$   
    mod_gzip_item_include mime      ^text/.*   
    mod_gzip_item_include mime      ^application/x-javascript.*   
    mod_gzip_item_exclude mime      ^image/.*   
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*   
</IfModule>
Hierbei wird die Entscheidung, ob eine Datei komprimiert werden soll (oder nicht) über reguläre Ausrücke der Dateiendung oder des MIME-Typs getroffen.

ob_gzhandler
Was aber, wenn man ein Shared-Hosting-Paket hat und der Webhoster mod_gzip und mod_deflate weder unterstützt noch bereit ist zu installieren? Dann kann man immernoch PHP-Funktionen verwenden. Das funktioniert über die Funktion ob_gzhandler.
Dazu muss in jede Datei, die man komprimieren möchte, folgender Code ganz am Anfang eingefügt werden:

<?php   
ob_start("ob_gzhandler");    
?>

Man muss dabei nicht selbst überprüfen, ob der Client GZIP unterstützt, da das die Funktion selbst übernimmt. Das einzige Problem an dieser Variante ist, dass wirklich alle zu komprimierenden Dateien bearbeitet werden müssen, es sei denn …

… auto_prepend_file
Wer nicht alle Dateien einzeln bearbeiten möchte, kann einfach eine PHP-Datei mit dem ob_start(„ob_gzhandler“) erstellen (nur diesen Code, nichts weiter) und sagt dem Apache anschließend, dass er diese Datei vor dem Bearbeiten einer anderen Datei einfügen soll, indem folgender Code in die .htaccess eingefügt wird:

&lt;FilesMatch "\.(txt|html|htm|php)"&gt;  
    ForceType application/x-httpd-php   
    php_value auto_prepend_file /the/full/path/gzip-enable.php
&lt;/FilesMatch&gt;
Dieser Code besagt, dass die Datei immer eingefügt werden soll, wenn die Dateiendung txt, html, htm oder php ist. Anschließend wird der Webserver angewiesen diese Datei zwingend durch den PHP-Parser zu schicken (sonst hätte man bei Aufruf einer txt-Datei einfach den Code ob_start(„ob_gzhandler“) am Anfang stehen). Und zuletzt wird noch der Pfad zu dem soeben erstellten Script angegeben.
Wem diese Variante gefällt, der kann natürlich die Prepend-Dateien auch für andere Dateitypen erweitern (CSS und JS – Achtung, hier muss der Content-Type gesetzt werden) und die so komprimierten Dateien auch noch cachen:

<?php   
 
   // Datenpufferung aktivieren, am Ende gesamten Inhalt an ob_gzhandler übergeben 
   ob_start ("ob_gzhandler");   
 
   // korrekten Content-Type setzen 
   header ("content-type: text/css; charset: UTF-8");   
 
   // Client-Cache anweisen sicht strikt an diese Anweisungen zu halten 
   header ("cache-control: must-revalidate");   
 
   // wie lange soll der Content gecached werden 
   $offset = 60 * 60;   
 
   // Ablauf-Datum setzen 
   $expire = "expires: " . gmdate ("D, d M Y H:i:s", time() + $offset) . " GMT";   
 
   // Header senden
   header ($expire);   
?>

Und dann das hier in die .htaccess:

<FilesMatch "\.(css)">  
    ForceType application/x-httpd-php   
  
    php_value auto_prepend_file "/the/full/path/of/this/file/gzip-css.php"   
  
</FilesMatch> 

Falls ihr noch weitere Möglichkeiten kennt zum Komprimieren oder sinnvolle Erweiterungen für die hier angegebenen Codes, würde ich mich über Kommentare freuen!

Jan hat 152 Beiträge geschrieben

27 Kommentare zu “mod_gzip, mod_deflate und sonstige Komprimierungsverfahren für Web-Inhalte

  1. robo47 sagt:

    apache + mod_deflate in Kombination mit statischen Dateien die oft angefragt werden (css / js ) kann aber auch nach hinten losgehen, aufgrund eines Bugs funktioniert nämlich dann das Conditional Get ( https://issues.apache.org/bugzilla/show_bug.cgi?id=45023 ) nicht richtig. Fragt der Client also an ob sich das Dokument verändert hat, bekommt er anstatt nur nem 304er header jedes mal das komplette (komprimierte) dokument geschickt.

  2. Gerhard sagt:

    1. Habe ich nach Recherche jetzt richtig verstanden, dass mod_deflate im Apache 2 das mod_gzip in Apache 1.3 quasi ersetzt hat?

    2. Die immer wiederkehrende Komprimierung verursacht ja auch Prozessorlast. Wenn ich eh schon cache, habe ich dann eine Möglichkeit gleich die komprimierten Sachen zu cachen und diese dann auszuliefern? Hat jemand Erfahrungen?

  3. narkaT sagt:

    das cachen der komprimierten daten ist auch möglich, allerdings
    nicht über die apache module.

    die cache-logik müsste man dann in php umsetzen.

  4. robo47 sagt:

    1) Ja, mod_gzip ist für apache 1.3.x und mod_deflate für die 2.0/2.2-Serie, wobei mod_deflate trotz des namens nicht nur deflate-komprimierung sondern gzip nutzt.

    2) Lighttpd kann das mit mod_compress out of the box, bietet sich teilweise auch an für statischen content unter ner subdomain nen 2ten kleinen webserver der sich nur um statische dinge kümmert zu haben.

    Mit einer Kombination aus mod_cache und mod_deflate sollte das auch beim 2er apache möglich sein -> http://httpd.apache.org/docs/2.2/mod/mod_cache.html

  5. Dominic sagt:

    Wer sowieso schon seine Seiten in einen statischen Cache schreibt (z.B. cache/seite.html), kann dabei auch gleich noch mit der PHP funktion gzwrite() eine komprimierte Version rausschreiben (z.B. cache/seite.gzhtml). Über mod_negotiation kann dann, je nach Accept-Encoding, die unkomprimierte oder gzip Version ausgegeben werden.

    Options +MultiViews
    AddType text/html .gzhtml
    AddEncoding gzip .gzhtml

    Somit wird die CPU des Servers entlastet, da die Dateien nicht jedes mal aufs neue komprimiert werden müssen – zugegebenermaßen für die allermeisten Seiten unerheblich 🙂

  6. Gerhard sagt:

    Hey cool, ich wusste gar nicht, dass die GZip-Funktionalität so gut im PHP implementiert ist. Meist hat man ja nur Teile der Seite im Cache, so dass man den Cache nicht schon in gz vorliegen haben kann, aber ich denke mal bspw. bei der Startseite kann das schon Lastspitzen abfedern.

  7. Björn sagt:

    Alle Lösungen da sind nicht die besten…

    Komprimierung via PHP könnte besser sein, ist sehr lastig. Die Kompressionsrate sollte da einstellbar sein. das man eine Mischung zwischen Last und Kompressionshöhe findet für den Server.

  8. robo47 sagt:

    Sowohl ob_gzhandler als auch manuelle kompression mit gz* erlauben doch die Übergabe eines parameters für die Kompression von 1 bis 9 oder verstehe ich dich grad falsch ?

  9. Siegfried sagt:

    Für statische Dateien kann man gleich von vornherein eine Gezippte Variante zusätzlich ablegen. Die kann der Server dann ohne extra Prozessorlast ausliefern. Das geht dann besonders schnell. Und gecached werden können diese Dateien auch noch gut.

    Und das geht ganz ohne mod-gzip oder mod-deflate 🙂

  10. Björn sagt:

    genau Kompression 1-9 das meine ich. Sein Beispiel was er hier zur Verfügung stellt ist glaube ich automatisch Stufe 9 was ziemliche Last darstellt….

  11. Der hier bereits vergestellte QuickCache erledigt beides, Caching und http-Komprimierung. Dabei ist er so intelligent die bereits komprimierten Seiten zu cachen, das kann man sehen, wenn man mal in das Verzeichnis schaut, wo die Dateien abgelegt werden.
    Ausserdem setzt werden noch http-Header gesetzt für clientseitiges Caching und für „not modified“.

    Ich kann QuickCache nur empfehlen, es lässt sich sehr schnell in bestehende PHP-Websites einbinden und reduziert die Serverlast erheblich.

    http://phpperformance.de/quickcache-frueher-jpcache-vorstellung-und-konfigurationsempfehlung/

  12. Martin sagt:

    > da die Komprimierung stets warten muss bis das gesamte HTML-Dokument fertig ist

    Ist dem so? Ich dachte, es wird dabei immer blockweise komprimiert und ausgeliefert.

  13. Jan sagt:

    @Martin: Also ich habe folgenden Test gemacht:
    1. ohne GZIP Stück für Stück ausgegeben (das was schon fertig berechnet ist), Ausführungszeit: ca. 3 Sekunden, erste Elemente nach 0,5 Sekunden sichtbar
    2. mit GZIP alle HTML-Elemente auf einmal angezeigt, aber eben auch erst nach 3 Sekunden.

    Also ich habe nicht wirklich ein Benchmark gemacht, aber Du kannst es ja ausprobieren. Bei mir wurde die Ausgabe der ersten Elemente insofern verzögert, dass alle Elemente erst angezeigt wurden, wenn alles fertig berechnet war.

  14. Martin sagt:

    Also die Kombination aus Apache 2, mod_deflate, einer mehreren MB großen Textdatei, Schmalband-DSL und Firefox 3 zeigt die Daten beim Laden an.

  15. Jan sagt:

    Darum ging es doch gar nicht – HTML-Quellcode ist sehr selten über 1 MB groß. Vielleicht greift da die Größe der Blöcke nicht, sodass der gesamte Quellcode in einen Block passt.

    Und das diese Datei beim Laden angezeigt wird, muss nicht heißen, dass sie wirklich bereits während des Herunterladens angezeigt wird. Stattdessen wird die Datei erst vollständig heruntergeladen und dann langsam angezeigt, weil die Verarbeitung natürlich etwas Zeit kostet.

  16. Martin sagt:

    Ich kann ausschließen, dass mein DSL so schnell ist, dass die Datei so schnell runtergeladen wird, dass sie vor der Anzeige bereits vollständig geladen ist.

    Ich habe mal ein Skript geschrieben, das die Ausgabe bewusst verzögert (wie langsame Datenbankabfragen): http://nopaste.php-quake.net/242917

    Ergebnis (mit Firefox 3): Nahezu sofortige Anzeige der ausgegebenen Daten. Auch mit gzip. (Tipp: Beim Laden die Ende-Taste gedrückt halten. Dass gzip bei solchen Fällen die teiweise Anzeige des Dokuments verhindert, ist damit widerlegt.

    Eine mögliche Verzögerung liegt wohl eher an dem Ausgabepuffer von PHP (spätestens mit ob_start(‚ob_gzhandler‘); aktiv). Das ist a) nicht auf mod_deflate und Co. zu verallgemeinern und b) mit einem ob_flush(); vor der langsamen Stelle kinderleicht zu beheben.

  17. Voku sagt:

    Ersteinmal vielen Dank für den Artikel, finde es echt super, dass sich Leute mit diesem Thema befassen.

    PS: Habe ebenfalls einen Blog-Eintrag über dieses Thema geschrieben…

    -> http://voku-online.de/comment-n153.html

    1.) Voraussetzungen
    1.1) Webseiten Analyse
    1.2) Webseiten Benchmark

    2.) Komprimierung
    2.1) Bilder komprimieren
    2.1.1) Bilder Sprites
    2.1.2) PNG-Bilder komprimieren
    2.1.3) JPEG-Bilder komprimieren
    2.1.4) Bilder komprimieren – Online
    2.2) JavaScript/CSS komprimieren
    2.2.1) JavaScript/CSS komprimieren – serverseitig
    2.2.2) JavaScript/CSS komprimieren – Online
    2.3) Apache gzip-Kompression
    2.3.1) Aktiviere mod_deflate unter Debian
    2.3.2) Aktiviere mod_gzip

    3.) JavaScript richtig im HTML-Code platzieren

    4.) Browser-Cache nutzen
    4.1) Browser-Cache manuell einstellen
    4.2) Browser-Cache serverseitig einstellen

    5.) Apache-Module deaktivieren

    6.) PHP optimieren/caching
    6.1) PHP-Daten zwischenspeichern
    6.2) SQL-Abfrage mittels PHP zwischenspeichern
    6.3) PHP-Module deaktivieren
    6.4) php.ini (Konfiguration) optimieren

    7.) MySQL optimieren

  18. seolar sagt:

    Danke für diesen durchaus hilfreichen und verständlichen Artikel zum Thema Website Komprimierung. Es gibt wirklich nicht viele gute BEiträge zu diesem Thema. Aber dieser ist ein Artikel, der nicht nur aufzeigt was möglich ist, sondern auch verständlich beschreibt wie es geht.

    Danke nochmals, denn Ladezeiten sind ja nunmehr auch wesentlich in Sachen SEO, sodass ich als SEO schon daran interessiert bin, das Beste aus meiner Website oder Kundenprojekten zu holen.

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>