SEOSunday – Performanceoptimierung dynamischer Websites

SEOSunday – Performanceoptimierung dynamischer Websites

rankingCHECK startet heute den SEOSunday. Wir werden ab sofort jeden Sonntag ein Thema der Suchmaschinenoptimierung näher beleuchten. Heute geht es um die Performanceoptimierung dynamischer Webseiten.

Wir hatten bereits vor einiger Zeit darauf hingewiesen, dass die Ladezeit von Websites ein wichtiger Faktor für die Bestimmung von Qualitätsfaktor und PageRank ist.

Doch das Thema Performance ist vielschichtig. Zum einen gibt es da die „gefühlte Ladezeit“. Sie entspricht der Dauer der Anzeige des kleinen blauen Ladebalkens in der Statuszeile der meisten Webbrowser. Zum anderen gibt es tatsächlich eine technische Ladezeit, mit der wir uns heute näher befassen werden. Erstere ist für die User-Experience zumindest in Ballungsgebieten nicht wirklich entscheidend.
Gerade bei dynamisch generierten Websites, und das dürfte zumindest im E-Commerce und Blogbereich auf alle zutreffen, bestehen Performanceprobleme meist in der Generierungszeit der Website. Was häufig übersehen wird: Ruft ein Nutzer eine Website auf, bedeutet dies in der Regel nicht, dass irgendeine Datei, die auf irgendeinem Webserver liegt, einfach an den Nutzer gesendet wird. Hierfür sind teilweise extrem komplexe Mechanismen verantwortlich, denn die Inhalte ändern sich ja in unseren oben genannten Beispielen ständig. Gespeichert werden diese in nahezu 100% der Fälle in Datenbanken.
Bis es zur Auslieferung einer dynamischen Website kommt, müssen folgende Phasen einer Anfrage durchlaufen werden:

Verbindung zum Server aufbauen

Bevor irgendeine Kommunikation mit dem Webserver erfolgen kann benötigt der Browser zunächst eine Verbindung zu ebendiesem. Vergleichbar ist dies mit einem Telefonat. Bevor ich mit jemandem sprechen kann muss ich erstmal seine Nummer wählen. Steht die Verbindung, ist die Leitung belegt. Außer ich verfüge über einen ISDN oder eine Primärmultiplex-Anschluss. Glücklicherweise verfügt heutzutage jeder Webserver über einen Primärmultiplexer :-)

Ist uns die Nummer unserers Ansprechpartners unbekannt müssen wir erstmal die Auskunft anrufen. Das DomainNameSystem ist hier unser Freund. Es sorgt für die Zuordnung der für Menschen unzumutbaren IP-Adressen (192.168.1.1) zu Domains wie www.ranking-check.de. Ist dem anfragenden Computer die Adresse noch nicht bekannt und somit nicht im DNS-Cache (unser Kurzzeitgedächtnis nach dem auswendiglernen) des Betriebssystems vorhanden, muss zunächst die Rufnummer ermittelt werden.

Nutzeranfrage bearbeiten

Dies ist der aufwändigste Teil des Abfragelebenszyklus. Denn er gliedert sich wiederum in mehrere Schritte:

  • Analyse der Abfrage: Was wurde angefragt?
  • Aufruf des zuständigen Programmes (in der Regel ein PHP-Script, Java-Servlet, oder vergleichbares)
  • Beschaffung der benötigten Daten mit Hilfe der Datenbank
  • Zusammensetzen der Seite, die dem Nutzer angezeigt werden soll

Die Dauer der Bearbeitung der Nutzeranfrage ist abhängig von folgenden Faktoren:

  • Performance des Server-Prozessors und anderer Hardwarekomponenten
  • Konfiguration des HTTP-Servers
  • Konfiguration der Datenbank (bei großen Sites bietet es sich an, die Datenbank auf einen anderen Rechner zu legen, als den HTTP-Server)

Auslieferung der Seite

Wurde die Seite zusammengesetzt wird sie in der Regel im Arbeitsspeicher des Webservers zwischengespeichert und von dort aus an den Nutzer geliefert. Doch vorher muss sie noch ins passende Format übersetzt werden. Informationen über die Dateigröße, Art der ausgelieferten Datei, etc. werden ermittelt und der Antwort beigefügt. In vielen Fällen werden die auszuliefernden Textdaten noch komprimiert und als eine Art Zip-Archiv versandt. Wichtig: ist die Kompression aktiviert, kostet dies Prozessorpower. D.h. die Anzahl möglicher gleichzeitiger Anfragen reduziert sich. Hier sollte also unbedingt abgewogen werden, ob die verkürzte Auslieferungszeit zum Nutzer hin, die Beanspruchung des Prozessors rechtfertigt. Aber keine Sorge, in der Regel tut sie das. Hier gibt ein moderner Prozessor im Server den Ausschlag. Allerdings kostet das auspacken der komprimierten Fassung auch beim Nutzer CPU-Zeit. So kommt es gelegentlich dazu, dass die gut gemeinte Kompression der ausgelieferten Daten mehr schadet als sie nützt. Neben Fragen der Kompression, entscheiden über die Auslieferungszeit der Seite nur noch die Bandbreite des Servers und die Bandbreite der Internetverbindung des Nutzers.

Rendering im Browser

Das Rendering bezeichnet die Übersetung des gelieferten Codes in die Seite, die letzlich auf dem Monitor erscheint. Ist die Datei einmal am Ziel angekommen, soll Sie vom Browser angezeigt werden. Dieser setzt sie jetzt optisch und mehr oder minder ansehnlich zusammen und veranstaltet im Anschluss ein richtiges Anfragefeuerwerk mit unserem Server. Denn ist der Rumpf der Seite (der HTML Code) ersteinmal geladen werden die fehlenden Ressourcen nachgeladen. Hierzu zählen:

  • Bilder
  • CSS-Daten
  • externe Javascript-Dateien
  • evtl. Daten aus iFrames oder Frames

Da es sich dabei um statische Ressourcen handelt, werden diese recht schnell zum Nutzer übertragen. Interessant in diesem Zusammenhang ist, dass dies in der Regel über die zuvor aufgebaute Verbindung geschieht. Um beim Telefonbeispiel zu bleiben: Jede Ressource ist ein gesprochener Satz während unserer Verbindung. Hierzu zählt die generierte HTML-Datei ebenso wie die statischen Dateien. Für Renderingzeit im Browser sind zwei Faktoren von Bedeutung:

  • Die Programmsturktur des Browserss
  • Die Prozessorgeschwindigkeit des Endbenutzer-PCs

Fertig. Dies alles ist also notwendig, bevor der schöne rankingCHECK Blog angezeigt werden kann.

Welche Dinge könnten jetzt die auslieferung der Seite hinsichtlich der Performance negativ beeinflussen?

1. Eine fehlerhafte DNS-Konfiguration

Die Einstellung beim setzen des DNS-Records legt nämlich ein Keep-Alive Timeout fest. Dieses ist in der Regel auf einen Tag festgesetzt. Liegt der Wert darunter, kommt es dazu, dass von anderen DNS-Servern häufiger mal nachgefragt werden muss, wie denn jetzt die Ziel-IP (unsere Telefonnummer) der Webpräsenz lautet. Angefragt wird immer nur, wenn auch jemand die Adresse wissen möchte. D.h. steht das Keep-Alive -Timout des DNS-Eintrages auf 5 Minuten, muss der DNS-Server den wir verwenden (in der Regel der des verwendeten Internetproviders) erstmal beim Domaininhaber nachfragen. Dies kann die Abfrage unnötig in die Länge ziehen. Jedoch spielt dies in der realität keine entscheidende Rolle.

2. Der Verbindungsaufbau zum Webserver

Eine der häufigsten Ursachen für Flaschenhälse: Der Verbindungsaufbau zum Server hin dauert zu lange. Hier spielen zwei Parameter eine Rolle. Einer davon heißt wieder Keep-Alive-Timeout. Gemeint ist hier die Zeit innerhalb derer eine Verbindung zum HTTP-Server offen gehalten wird. Da der Verbindungsaufbau immer ein paar Millisekunden in Anspruch nimmt können Browser und Server eine Zeitspanne vereinbaren innerhalb derer eine Verbindung offen bleibt, um weitere Dateien (z.B. die Bilder) zusätzlich über die Leitung zu schicken. Um beim Telefonbeispiel zu bleiben: So lange ich rede bleibt die Verbindung bestehen. Schweige ich eine definierte Zeitspanne lang, legt mein Gesprächspartner auf. Will ich jetzt noch etwas sagen muss ich erneut anrufen.

Der Verbindungsaufbau wird in der Regel durch eine zu geringe Anzahl simultan möglicher HTTP-Verbindungen in Kombination mit einem zu hohen Keep-Alive-Timout gehemmt. Ein Beispiel:

Der Webserver (in unserem Fall ist es Apache) lässt in der Standardkonfiguration nur 30 gleichzeitige Verbindungen zu. Auf das Problem der Gleichzeitigkeit bin ich bereits an anderer Stelle eingegangen. Ebenfalls voreingestellt ist das Keep-Alive-Timout. Im Standardfall beträgt dieser Wert 15 Sekunden. Dies bedeutet, dass ein Nutzer eine mögliche Verbindung für mindestens 15 Sekunden beansprucht, bevor der Server auflegt. Zu Zeiten bei denen viele Nutzer auf die Seite zugreifen, verbringt der Server also einen Großteil der Zeit damit darauf zu warten endlich auflegen zu können. D.h. die Wartezeit ist zu hoch, denn eigentlich geht es nur darum die relevanten Informationen zu übertragen. Hierzu zählen aber nur HTML und ergänzende Daten. Sind alle Daten übertragen, wird trotzdem noch 15 Sekunden gewartet. Der dahinter steckende Gedanke beabsichtigt auch mehrere Klicks über eine Verbindung abzuwickeln. Das ist in der Regel nicht nötig, denn der Verbindungsaufbau dauert nur wenige Millisekunden. Im Gegensatz dazu wartet unter Umständen der nächste Nutzer mehrere Sekunden darauf überhaupt eine Verbindung zu bekommen (im schlimmsten Fall sind es 15)!!

Unser Tipp: Das Keep-Alive-Timout des Webservers sollte gering gehalten werden. In der Regel reichen 1-2 Sekunden. Denn die Zeitspanne nach der die Verbindung aufgelegt wird, wird nach jeder übertragenen Datei erneut hochgesetzt. D.h. nach dem Übertragen des HTML bleiben dem Server 2 Sekunden, um über die gleiche Verbindung das erste Bild auszuliefern. Das ist mehr ist als genug. Nach dem ersten Bild sind es wieder 2 Sekunden für das nächste, usw. Ein Abschalten des Timouts ist hingegen nicht empfehlenswert, denn dann müsste für jede Datei aus der eine Einzelseite besteht eine neue Verbindung aufgebaut werden. Da eine Website aber in der Regel aus 10 und mehr Dateien bestehen kann würde die gut gemeinte Optimierung hier wiederum die Performance negativ beeinflussen. Sofern der Arbeitsspeicher des Webservers dafür ausreicht, kann gleichzeitig auch die Anzahl der möglichen Verbindungen hochgesetzt werden. Hier gilt: Eine Verbindung schlägt mit etwa 2MB zu Buche.

3. Probleme mit der Generierung der Website

Hier kommen wir zum schwierigsten Punkt. Auf alle Möglichen Probleme in diesem Bereich einzugehen würde Bücher füllen. Daher wenden wir uns an dieser Stelle nur den häufigsten zu. Diese betreffen die Codequalität der Scripte, die Struktur der Datenbank sowie die Konfiguration der Datenbank.

Zur Codequalität sei lediglich erwähnt, dass jede Stelle im Programm bei der der Entwickler dachte: “Das muss nicht optimiert werden, weil der Prozessor schnell genug ist”, sofort eliminiert werden sollte, weil sie einen zukünftigen Flaschenhals darstellt, den man unter Umständen nur schwer wiederfindet. Ebenfalls wichtig: Unnötige Datenbankabfragen sind zu vermeiden. Diese kosten eine Menge Zeit und Rechenleistung.

Die Datenbankstruktur ist ein entscheidender Faktor bei der Performance der Seitengenerierung. Dabei geht es weniger um die Einhaltung von Normalisierungsregeln. Viel entscheidender ist die Frage, für welche Spalten Indizes gesetzt wurden. Ein Index erleichtert der Datenbank das Auffinden eines Datensatzes, da er eine Art komprimierte Wegbeschreibung durch die Datenbank beherbergt. Wird in einer Datenbank beispielsweise häufig nach einer Kundennummer gesucht, sollte die Spalte, in der die Kundennummer enthalten ist, auch indexiert werden. Dies beschleunigt die Performance beim Auffinden eines spezifischen Datensatzes leicht um das zwanzigfache.

Voraussetzung dafür ist allerdings eine korrekte Konfiguration des Datenbankservers. In nahezu jedem Performancetuning-Tutorial werden die Werte der sogenannten Key-Buffer viel zu klein bemessen. Der Key-Buffer definiert die Größe des für Indizes reservierten Arbeitsspeichers. Ein Index ist nur dann wirklich hilfreich, wenn er im Arbeitsspeicher des Server seinen Platz findet, da dieser um ein vielfaches schneller ist, als ein persistentes Medium wie die Festplatte. Hier gilt: Die Summe des reservierten Arbeitsspeichers für alle Indizes aller Datenbanken, innerhalb eines Datenbankmanagementsystems wie MySQL, sollte mindestens so groß sein wie die Summer aller Indizes aller Datenbanken selbst. Das sind in der Regel deutlich mehr als die in vielen Tutorials vorgeschlagenen 32MB, bzw. die bei MySQL voreingestellten 16MB.

Über die schlecht konfigurierten Indexeinstellungen des Servers hinaus, kommt unter Umständen ein weiteres Problem zum Tragen: Die Anzahl maximal möglicher Verbindungen zum Datenbankserver. Es handelt sich um einen Trugschluss anzunehmen, dass eine HTTP-Verbindung zum Webserver auch nur eine Verbindung auf der Datenbank in Anspruch nimmt. Dies ist in höchsten Maße abhängig von der Struktur der Scripte. WordPress, auf dessen Tuning wir in einem weiteren Tutorial noch eingehen werden, ist hier besonders verschwenderisch. Bis zu 30 (!) Datenbankabfragen werden hier getätigt, um eine einzige Seite auszuliefern. Diese brauchen zwar nicht unbedingt 30 Verbindungen zum Datenbankserver, mehr als eine sind es aber allemal. MySQL lässt in der Standardkonfiguration aber nur 100 simultane Verbindungen zu, so dass sich hier recht schnell der nächste Flaschenhals ergibt.

Unser Tipp: Die Anzahl der zugelassenen Verbindungen des Datenbankservers sollte in etwa doppelt so hoch sein, wie die Summe aller zugelassenen Verbindungen sämtlicher Webserver, die darauf zugreifen.

4. Die Bandbreite des Servers

Hat man alle internen hürden genommen, kommen unter umständen externe Hinzu. Hierzu zählt insbesondere die Bandbreite des Servers (in der Regel 100Mbit). Dummerweise erreicht man diesen Wert bei günstigen Providern eigentlich nie, denn hier sind immer mehrere Server an eine 100Mbit Leitung angeschlossen. Die Kalkulation ist hier relativ einfach: ein Nutzer der eine 16Mbit Leitung hat, reizt diese in der Regel auch aus.  Wir können also selbst wenn uns die 100Mbit vollständig zur Verfügung stehen maximal 6,25 Nutzer absolut gleichzeitig bei voller Bandbreite bedienen. Doch keine Sorge der Webserver lässt trotzdem weitere Verbindungen zu, allerdings reduziert sich dabei die Auslieferungsgeschwindigkeit für die anderen Nutzer. Das Problem maximiert sich durch den genannten Punkt, dass pro 100Mbit Leitung bis zu 20 andere Server auf die wir keinen Einfluss haben an der Bandbreite zehren. Dieser Umstand ist dafür verantwortlich, dass wir beim Surfen durch die weiten des Netzes den Unterschied zwischen einer 6Mbit und einer 25Mbit Leitung in der Regel gar nicht so sehr zur Kenntnis nehmen. Für die meisten Internetpräsenzen dürfte diese Problematik allerdings eine eher untergeordnete Rolle spielen. Dennoch ist es wichtig auch solche Dinge zu wissen und sich im zweifelsfall daran zu erinnern.

Hiermit kommen wir nun zum Ende des mittlerweile recht umfangreich gewordenen Artikels zur Performanceoptimierung dynamischer Websites. Fragen können gerne in den Kommentaren gepostet werden. Übrigens rankingCHECK berät Sie gerne auch bei der Lösung Ihrer Performanceengpässe.

 

 

4 Kommentare »

  1. buildblog | Heute: SEO-Sunday Schrieb,

    18. Oktober, 2009 @ 16:08


    [...] Name ist Programm: Analog zum #FollowFriday und #MusicMonday habe ich eben den #SEOSunday im rankingCHECK Blog eingeleutet. Dort wird fortan jeden Sonntag ein Teilbereich der Suchmaschinenoptimierung näher beleuchtet. [...]


  2. Webseiten Ladezeiten: Google stellt Optimierungstool zur Verfügung « rankingCHECK Blog Schrieb,

    19. Oktober, 2009 @ 16:25


    [...] Suchmaschine einzelnen Seiten zuweist. Ladezeiten können mit einfachen Mitteln gemessen und durch Optimierungsmaßnahmen verkürzt [...]


  3. SEO Sunday – Linkjuice Steuerung durch interne Verlinkung « rankingCHECK Blog Schrieb,

    29. November, 2009 @ 13:46


    [...] aktiviert bzw. überhaupt installiert hat, was natürlich zu Problemen im Hinblick auf die Usability einer Website führen kann. Der eigentliche Einsatz von JavaScript läuft dann so ab, dass Links [...]


  4. SEO Sunday – Performance, Performance, Performance Schrieb,

    11. April, 2010 @ 10:20


    [...] Performanceoptimierung dynamischer Websites [...]


Hinterlassen Sie einen Kommentar