Durchdachte Einstellungen beim Webserver und kleine Tricks beim Optimieren machen lahmen Webseiten Beine.
Workshop “Webseiten optimieren”
| Teil 1: Einführung und Endbenutzer (Client) | LU 06/2105, S. 92 | https://www.linux-community.de/34587 |
| Teil 2: Redakteur (Inhalt) | LU 07/2105, S. 88 | https://www.linux-community.de/34588 |
Als Administrator obliegt Ihnen die Verantwortung für die technischen Aspekte einer Internetseite. Abgesehen von der eingesetzten Hardware beinhaltet das die Konfiguration und den Betrieb des Webservers. Bei allen nachfolgend vorgestellten Aktionen besteht das primäre Ziel darin, die Anzahl der GET-Requests möglichst zu minimieren: Sie verursachen einen Großteil der Last. Somit verringern Sie einerseits die allgemeinen Unkosten in Bezug auf die Anfragen, andererseits die Last auf dem Webserver und erreichen damit in der Gesamtheit eine schnellere Reaktionszeit.
Verfallsdatum
Auf Wunsch ergänzt der Webserver die von ihm ausgelieferten Inhalte (Text und Bilder) mit einem Ablaufdatum beziehungsweise Zeitstempel zu deren Gültigkeit. Rein technisch betrachtet, sendet er in seiner Antwort sogenannte Cache Control Header mit, die entweder relativ zum letzten Zeitpunkt der Änderung der Datei wirken oder sich am letzten Zeitpunkt des Zugriffs orientieren.
Surfen Sie danach die Webseite an, überprüft der Webbrowser zunächst die Inhalte in seinem Zwischenspeicher (Cache). Liegen die Daten bereits lokal vor und ist das dazu hinterlegte Ablaufdatum noch nicht überschritten, nimmt der Browser die Daten direkt aus dem Cache und stellt sie dar. Das geht deutlich schneller, als die Daten erneut über das Netzwerk vom Server zu beziehen. Ist das Zeitlimit jedoch bereits abgelaufen oder lösen Sie ein Nachladen explizit aus (Reload), fordert der Browser die Inhalte erneut vom Server an und aktualisiert die Daten im Cache.
Die Voraussetzung für eine sinnvolle Nutzung stellt in diesem Zusammenhang eine korrekte Systemzeit auf den beteiligten Rechnern dar, was Sie beispielsweise über einen Abgleich via Network Time Protocol (NTP) erreichen. Bei nicht korrekt gesetzter Zeit bleiben die Seiten im Zwischenspeicher entweder zu lange oder zu kurz gespeichert.
Für den Webserver Apache steht für entsprechende Zeitstempel das Modul mod_expires bereit [3]. Sie finden es bei Debian und Ubuntu im Paket apache2-bin [4]. Die Konfiguration des Moduls erfolgt je nach Servertyp und Hoster in der Datei .htaccess oder in den statischen Virtual Hosts unter /etc/apache2/sites-enabled/vh-statics [5]. Die fünf Zeilen in Listing 1 sorgen dafür, dass ein Browser sowohl Bilder in gängigen Formaten als auch CSS-Dateien für einen Zeitraum von 30 Tagen nach dem Zugriff zwischenspeichert.
Nach dem Konfigurieren aktivieren Sie das Modul durch den Aufruf aus der ersten Zeile von Listing 2 und starten den Apache-Webserver neu (zweite Zeile). Verwenden Sie Nginx [6] anstelle von Apache und nutzen Sie eine Konfiguration analog zu Listing 3.
Listing 1
ExpiresByType image/jpg "access plus 30 days" ExpiresByType image/gif "access plus 30 days" ExpiresByType image/jpeg "access plus 30 days" ExpiresByType image/png "access plus 30 days" ExpiresByType text/css "access plus 1 month"
Listing 2
# a2enmod expires # service apache2 restart
Listing 3
location ~* \.(png|jpg|jpeg|gif)$ {
expires 30d;
}
Ob für eine Webseite eine zeitliche Begrenzung eingestellt ist, finden Sie mit dem Programm Curl [7] und der Option -I (Langform --head) auf der Kommandozeile heraus. Ein entsprechender Aufruf liefert nicht die gesamte Webseite, sondern nur die Kopfzeilen (Header). Listing 4 zeigt das Ergebnis für die Webseite des Debian-Projekts. Die Zeilen 12 und 13 geben darüber Auskunft, dass für die Startseite ein Verfallsdatum gilt.
Listing 4
$ curl --head http://www.debian.org HTTP/1.1 200 OK Date: Tue, 14 Jul 2015 16:59:22 GMT Server: Apache Content-Location: index.en.html Vary: negotiate,accept-language,Accept-Encoding TCN: choice Last-Modified: Sat, 11 Jul 2015 23:34:58 GMT ETag: "3a4e-51aa1efc97682" Accept-Ranges: bytes Content-Length: 14926 Cache-Control: max-age=86400 Expires: Wed, 15 Jul 2015 16:59:22 GMT X-Clacks-Overhead: GNU Terry Pratchett Content-Type: text/html Content-Language: en
Statisch und dynamisch
Die Webserver Apache und Nginx liefern Inhalte an und für sich bereits zügig aus. Nimmt die Menge der Anfragen jedoch zu, kommt auch serverseitig das Thema Caching von Inhalten ins Spiel. Dabei unterscheiden sich die Varianten in Bezug auf den Speicherort, wobei man zwischen dem Disk Cache und dem Memory Cache unterscheidet. Während die erste Variante die übermittelten Inhalte auf einem Datenträger puffert, nutzt die zweite Variante das RAM als Zwischenspeicher. Ein Disk Cache arbeitet naturgemäß langsamer als ein Memory Cache, bietet dafür aber mehr Kapazität.
Beide Varianten zielen auf unterschiedliche Einsatzbereiche ab. Verwenden Sie einen Disk Cache in Kombination mit statischen Inhalten aus lokalen Quellen, hat das lediglich einen begrenzten Effekt. Aufgrund der hohen Leistungsfähigkeit der Datenträger macht es heutzutage keinen großen Unterschied mehr, von welcher Datei auf der lokalen Festplatte der Inhalt letztlich stammt. Beziehen Sie jedoch Daten von externen Quellen, etwa über AFS, NFS, Samba (SMB) oder von einem NAS, ist der Disk Cache aufgrund der Latenzen im Netzwerk oft sinnvoll.
Etwas anders sieht es bei identischen Inhalten aus, die der Server jeweils dynamisch erzeugt. Dazu zählt unter anderem die Kombination aus Skripten und Datenbankzugriffen, die häufig bei CM-Systemen wie WordPress [8], Drupal [9], Typo3 [10] oder Contao [11] im Hintergrund ablaufen. Sowohl ein Disk Cache als auch ein Memory Cache bringen hier einen klaren Geschwindigkeitsvorteil.
Um das Caching mit Apache zu verwenden, benötigen Sie das Modul mod_cache [12]. Fürs Disk-Caching kommt bei Apache 2.2 das Modul mod_disk_cache hinzu beziehungsweise mod_cache_disk ab Apache 2.4. Das Caching im RAM übernehmen mod_mem_cache (Apache 2.2) oder mod_file_cache (Apache 2.4).
Sie aktivieren die Module für einen Disk Cache durch den Aufruf aus Listing 5 und starten anschließend den Apache-Webserver neu. Das Beispiel bezieht sich auf Apache 2.4. Ausführlichere Informationen zur Konfiguration dazu entnehmen Sie der Dokumentation [13]. Benötigen Sie die Schritte aus Listing 5 häufiger, dann packen Sie die Abfolge am besten in ein Shell-Skript, um noch ein wenig Zeit zu sparen.
Listing 5
# a2enmod cache # a2enmod mod_cache_disk # service apache2 restart
Inhalte komprimieren
Bei Bedarf komprimiert der Webserver zunächst die ausgelieferten Inhalte und sendet sie dann in dieser kompakteren Form an den Anfragenden. Der Browser entpackt die Inhalte vor dem Anzeigen. Ziel bei diesem Vorgehen ist, möglichst wenig Daten vom Server zum Endgerät zu übertragen. Der Vorteil liegt darin, dass derzeit etwa 90 Prozent aller Webbrowser komprimierte Inhalte verstehen und diese im laufenden Betrieb entpacken.
Die Rechenleistung der beteiligten Geräte gibt diese Umstellung heute oft problemlos her. Das Aktivieren der entsprechenden Apache-Module nehmen Sie über das Kommando a2enmod vor. Zur Verfügung stehen zwei unterschiedliche Verfahren – einerseits ein echtes Komprimieren der Inhalte über das Apache-Modul mod_deflate [14] und andererseits das Übermitteln bereinigter Inhalte mittels mod_tidy [15]. Beide Module fungieren dabei als Filter für die Ausgabe.
Dabei lohnt es sich, nur die textbasierten Formate zu berücksichtigen, wie HTML, CSS, Javascript, XML und JSON. Bilder und andere Binärdaten liegen oft bereits komprimiert vor – hier würde der zusätzliche Schritt zum Komprimieren nur Rechenzeit vergeuden. Welche Formate mod_deflate konkret berücksichtigt, legen Sie in der Datei /etc/apache2/mods-available/deflate.conf fest (Listing 6). Das Benennen der Formate entspricht der üblichen Schreibweise gemäß dem MIME-Standard.
Listing 6
AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE image/svg+xml AddOutputFilterByType DEFLATE image/x-icon AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript
Das Modul mod_tidy hingegen entfernt vor dem Ausliefern an den Browser aus den Daten alle Kommentare, Leerzeilen und Umbrüche. Das betrifft selbst Copyright-Informationen und Angaben zu Lizenzen, die als Kommentare hinterlegt sind. Damit geht verloren, ob und vor allem wie Sie es anderen erlauben, die vom Webserver bezogenen Codeschnipsel weiter zu verwenden.
Eine hübsche Struktur des Dokuments ist nur für Sie als Autoren und Entwickler wichtig – den Webbrowser interessiert sie nicht. Er interpretiert lediglich den an ihn übermittelten Datenstrom. Die durch den Einsatz des Moduls erzielten Einsparungen im übertragenen Datenvolumen variieren stark und lagen in Tests um die 10 bis 25 Prozent.
In eine ähnliche Richtung – jedoch deutlich drastischer – geht RabbIT [16]. Dahinter verbirgt sich ein Caching Proxy, der ebenfalls Inhalte von Webseiten filtert. Gleichzeitig komprimiert er ausgewählte Inhalte wie Text und Bilder. Daneben beherrscht er noch das Herausfiltern von Werbung sowie von Hintergrundbildern.
RabbIT steht derzeit nicht als Debian-Paket bereit, sondern lediglich als Quellcode. Da die Entwickler dabei auf die Programmiersprache Java setzen, sollte die Software weitestgehend problemlos auf den einzelnen Distributionen ihren Dienst verrichten. Achten Sie dabei darauf, dass die verwendete Java Virtual Machine (JVM) für einen entsprechenden Durchsatz optimiert ist. Als Referenzwert bietet sich ein Vielfaches der Garbage Collection an.
SPDY oder HTTP/2
Helfen die zwischengeschalteten Filter nicht mehr, dann verbessert unter Umständen der Wechsel des verwendeten Protokolls zum Übertragen der Daten die Reaktionszeit. Im Januar 2015 wurde das Protokoll HTTP/2 als Nachfolger von HTTP 1.1 offiziell freigegeben [17]. Dabei übernahmen Mozilla, Google und die Google-Ausgründung Twist die Führung.
In das Konzept von HTTP/2 flossen die Erfahrungen aus dem SPDY-Protokoll mit ein, mit dem Google zwischenzeitlich versucht hatte, die Übertragung zu optimieren [18]. Dabei empfiehlt die Spezifikation, jede Verbindung mittels TLS zu verschlüsseln. Ob das tatsächlich die Sicherheit erhöht, darf man bislang bezweifeln, da HTTP/2 noch nicht so ausgereift wirkt wie seine Vorgänger [19]. Derzeit kommt HTTP/2 bereits bei Google Chrome, Firefox ab Version 35 und Internet Explorer (bereits aktiviert) zum Einsatz. Für die Webserver Apache und Nginx stehen passende Module zur Erweiterung bereit, um die Kommunikation von der Seite des Servers zu vereinfachen.
Diverse Tests zeigen, dass HTTP/2 schneller agiert als SPDY, obwohl die Antworten oft größer ausfallen. Das liegt daran, dass parallele Verbindungen zum Einsatz kommen (mehrere UDP-Verbindungen über eine einzige TCP-Verbindung) und andererseits die verwendete HPACK-Kompression kleinere GET-Requests erzeugt [20].
Abbildungen wandeln
Als weiterer Weg, um die Anzahl der Zugriffe zu verringern, bietet sich der geschickte Einsatz von Bildern an. Selbst wenn das eher in das Aufgabenfeld der Redakteure der Webseite fällt, lohnt sich ein Blick auf die Methode. Zu den möglichen Varianten zählen unter anderem das Optimieren von PNG-Bildern, die direkte Integration der Bilder als Base64-codierter Text im HTML-Dokument und das Erzeugen von Sprites.
Die erste Variante stellt den einfachsten Weg dar und reduziert einerseits die Menge der zu übertragenden Daten sowie andererseits die Zeit, die der Webbrowser zum Anzeigen der Bilder benötigt. Mithilfe des Werkzeugs Optipng [21] verringern Sie verlustfrei PNG-Bilder [22], indem Sie die im Bild gespeicherte Palette oder Farbtiefe verkleinern und es auf eine Form zurechtstutzen, die im Browser erscheint. Abbildung 1 zeigt an einem Beispiel den Durchgang, wobei sich hier die Bildgröße um über 30 Prozent verringert.

Abbildung 1: Mit Optipng verringern Sie die Größe von PNG-Bildern im günstigen Fall um einen beträchtlichen Faktor.
Bei der direkten Integration von Bildern als Base64-codierte Daten im HTML-Dokument [23] überträgt der Server die Bilddaten mit dem HTML-Dokument; der Browser muss also die Grafik nicht mittels eines zusätzlichen GET-Requests vom Server beziehen. Um die Bilddatei als Base64-codierte Daten zu erhalten, kombinieren Sie die beiden Kommandos cat und base64 im Terminal (Listing 7). Die resultierende Zeichenkette übernehmen Sie in das HTML-Dokument. Anstelle der Referenz auf die Bilddatei kopieren Sie Zeichen vollständig in einer einzigen Zeile in das IMG-Tag (Listing 8).
Listing 7
$ cat bild.png | base64 iVBORw0KGgoAAAANSUhEUgAAAJYAAAAyCAIAAAAx7rVNAAAAA3NCSVQICAjb4U/gAAAACXBIWXMA AA3XAAAN1wFCKJt4AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAFbBJREFU [...]
Listing 8
<img src="data:image/png;base64, iVBORw0KGgoA[...]" alt="Beispielbild" />
Beim Einsatz von sogenannten Sprites handelt es sich um die komplexeste der drei Varianten. Dabei setzen Sie mehrere einzelne Bilder zu einem einzigen zusammen; mithilfe eines passenden CSS-Stylesheets und darin hinterlegter Koordinaten schneiden Sie es dann wieder auseinander. Dieses Vorgehen ersetzt mehrere Downloads durch maximal zwei – das große Bild und das dazugehörige Stylesheet. Ein solches Sprite samt passendem CSS erzeugen Sie mittels des Werkzeugs Glue-sprite [24] aus dem Paket glue-sprite [25].
Zunächst erzeugen Sie ein Verzeichnis mit den einzelnen Bildern – in unserem Beispiel schlicht distro genannt. Danach rufen Sie Glue-sprite mit zwei zusätzlichen Parametern auf (Listing 9). Der erste Parameter benennt das Verzeichnis mit den Bildern, der zweite den Ordner für die Ausgabe, in dem die Software das neue Bild samt CSS abspeichert.
Listing 9
$ glue-sprite distro sprites Processing 'distro': debian.png => .sprite-distro-debian gnu.png => .sprite-distro-gnu mandriva.png => .sprite-distro-mandriva Creating 'distro' image file... Creating 'distro' css file... $
Im Beispiel liegen im Verzeichnis distro drei Dateien mit den Logos von Debian, GNU und Mandriva Linux. Glue-sprite erzeugt daraus ein Gesamtbild namens distro.png sowie ein zugehöriges CSS namens distro.css (Abbildung 2). Beide Dateien referenzieren Sie nun direkt in der HTML-Seite. Um die Bilder auf verschiedenen Ausgabegeräten optimal darzustellen, hinterlegen Sie für jede Variante ein eigenes Bild – damit erfüllen Sie alle Kriterien des Responsive Programming [26].

Abbildung 2: Glue-sprite kombiniert einzelne Bilder zu einer Datei und erzeugt darüber hinaus ein CSS, mit dem Sie die Bereiche dieses großen Bilds exakt ausgeben.
Anbindung untersuchen
Haben Sie die Software analysiert und optimiert, fällt jedoch der Datendurchsatz immer noch nicht zufriedenstellend aus, dann lohnt ein Blick auf die Infrastruktur. Als Ansatzpunkte dienen dabei die Knoten, die Switches samt ihrer Konfiguration, die Anbindung und Verkabelung, die sich daraus ergebenden Zwischenschritte (Hops) zum Server sowie die generelle Last im Netzwerk.
Die Anzahl der Hops ermitteln Sie mithilfe des Werkzeugs Traceroute (Listing 10). Mit der Analyse der Last [27] und insbesondere deren Verursachern [28] beschäftigten sich bereits ausführlich zwei Artikel in früheren Ausgaben.
Listing 10
$ traceroute www.tu-berlin.de traceroute to www.tu-berlin.de (130.149.7.201), 30 hops max, 60 byte packets 1 217.0.117.212 (217.0.117.212) 20.221 ms 21.246 ms 21.224 ms 2 217.237.153.214 (217.237.153.214) 22.284 ms 22.270 ms 22.248 ms 3 h-ea3-i.H.DE.NET.DTAG.DE (62.154.49.106) 66.155 ms 66.158 ms 66.138 ms 4 80.156.160.138 (80.156.160.138) 26.952 ms 27.923 ms 27.911 ms 5 cr-tub1-hundredgige0-6-0-0-7.x-win.dfn.de (188.1.144.190) 30.851 ms 32.837 ms 32.833 ms 6 kr-tub87-1.x-win.dfn.de (188.1.235.118) 32.809 ms 68.585 ms 32.355 ms 7 e-ns-e-n.gate.tu-berlin.de (130.149.126.78) 162.247 ms 162.256 ms 163.436 ms [...]
Im internen Netz sollten Sie prüfen, ob einige ältere Netzwerkgeräte noch auf Halbduplex eingestellt sind. Bei der Nutzung von Full Duplex fällt die Latenz deutlich geringer aus. Aktuelle Netzwerkkarten wissen, was für Information Sie senden, und funktionieren mit dieser geänderten Einstellung fehlerfrei.
Einen weiteren Knackpunkt stellt die gewählte Software-Architektur des Webservers dar. Es macht einen großen Unterschied, ob Sie den Server nativ auf Hardware betreiben, eine Virtualisierung darunterlegen oder ihn in einen Docker-Container [29] verfrachten. Bei den letzten beiden Varianten verringert sich die Latenz, da sich alle Elemente einschließlich der Netzwerkschnittstellen im RAM befinden, was die Kommunikationszeiten verkürzt.
Fazit
Die hier vorgestellten Tipps bilden nur kleine Schritte. Kombinieren Sie aber mehrere davon, erreichen Sie nach kurzer Zeit bereits messbare Fortschritte und die Reaktionszeit der Webseite sinkt oft deutlich. Um herauszufinden, an welchen Stellen Sie ansetzen könnten, hilft Ihnen neben den in Teil 1 dieser Reihe genannten Erweiterungen für den Browser das Werkzeug YSlow [30]. Entwickelt von Yahoo, gibt es Ihnen neben vielen Hinweisen einen guten Überblick zum Stand der Dinge. Die Besucher Ihrer Webseite werden es Ihnen danken.
Danksagung
Die Autoren bedanken sich bei Werner Heuser, Wolfram Eifler, Wolfram Schneider und Thomas Osterried für deren Kritik und Anregungen im Vorfeld dieses Artikels.
Die Autoren
Frank Hofmann (http://www.efho.de/) arbeitet in Berlin im Open-Source-Experten-Netzwerk Büro 2.0 als Dienstleister mit Spezialisierung auf Druck und Satz. Der Mitgründer des Schulungsunternehmens Wizards of FOSS koordiniert seit 2008 das Regionaltreffen der LUGs in der Region Berlin-Brandenburg. Der gebürtige Kanadier Gerold Rupprecht wohnt seit 25 Jahren in Genf und arbeitet als Spezialist für Finanzsoftware sowie die Evaluierung und Optimierung von IT-bezogenen Prozessabläufen. Seit 2000 unterstützt er das GNUstep-Projekt und – als Organisator – die FOSDEM.
Infos
[1] Ladezeiten verringern (Teil 1): Gerold Rupprecht, Frank Hofmann, “Beschleunigt”, LU 06/2015, S. 92, https://www.linux-community.de/34587
[2] Ladezeiten verringern (Teil 2): Gerold Rupprecht, Frank Hofmann, “Optimiert”, LU 07/2015, S. 88, https://www.linux-community.de/34588
[3] Apache-Modul mod_expires: http://httpd.apache.org/docs/current/mod/mod_expires.html
[4] Debian-Paket zu Apache 2: https://packages.debian.org/jessie/apache2-bin
[5] Browser-Cache steuern: http://www.debianroot.de/server/den-browsercache-steuern-mit-apache2-und-mod_expires-1226.html
[6] Nginx: http://nginx.org
[7] Curl: http://curl.haxx.se
[8] WordPress: https://wordpress.org
[9] Drupal: https://www.drupal.org
[10] Typo3: http://typo3.org
[11] Contao: https://contao.org/de/
[12] Apache-Modul mod_cache: http://httpd.apache.org/docs/current/mod/mod_cache.html
[13] “Apache 2.4 Caching Guide”: http://httpd.apache.org/docs/2.4/caching.html
[14] Apache-Modul mod_deflate: http://httpd.apache.org/docs/2.4/mod/mod_deflate.html
[15] Apache-Modul mod_tidy: http://mod-tidy.sourceforge.net
[16] RabbIT: http://khelekore.org/rabbit/
[17] HTTP/2: Julia Schmidt, “Netzwerkprotokoll HTTP/2 ist fertig”, http://www.heise.de/newsticker/meldung/Netzwerkprotokoll-HTTP-2-ist-fertig-2552760.html
[18] SPDY bei Wikipedia: https://de.wikipedia.org/wiki/SPDY
[19] HTTP/2: Poul-Henning Kamp, “HTTP/2.0 – The IETF is Phoning It In.”, http://queue.acm.org/detail.cfm?id=2716278
[20] Vergleich SPDY und HTTP/2: https://blog.httpwatch.com/2015/01/16/a-simple-performance-comparison-of-https-spdy-and-http2/
[21] Optipng: http://optipng.sourceforge.net
[22] Debian-Paket optipng: https://packages.debian.org/de/jessie/optipng
[23] Bilder codieren: http://emelpe.de/bilder-mit-base64-codieren-und-in-den-quelltext-einbinden/
[24] Glue: http://glue.readthedocs.org/en/latest/
[25] Debian-Paket glue-sprite: https://packages.debian.org/jessie/glue-sprite
[26] Responsive Webdesign: https://de.wikipedia.org/wiki/Responsive_Webdesign
[27] Netzwerke analysieren: Frank Hofmann, “Verkehrsbeobachter”, LU 02/2013, S. 35, https://www.linux-community.de/28144
[28] Bandbreitenmonitoring: Martin Steigerwald, Frank Hofmann, “Raus aus dem Engpass”, LU 06/2013, S. 78, https://www.linux-community.de/28993
[29] Docker: https://www.docker.com
[30] YSlow: http://yslow.org





