wall < "Tuning von WordPress mit varnish"

Broadcast message from spillerm@unixe.de (pts/1) (Fr Mrz 09 12:57:14 2012):
4
Diesen Beitrag schrieb ich vor 7 Jahren. Behalte das beim Lesen bitte im Hinterkopf.

Nachdem ich herausgefunden hatte, dass mein Server Teil eines Botnets geworden war, kümmerte ich mich sehr eingehend um das System: ich räumte auf und sicherte (noch weiter) ab, ich optimierte meine fail2ban-Konfiguration, ich mistete WordPress-Plugins aus und räumte mein $HOME auf. Parallel dazu beschäftigte ich mich mit der Frage, wie ich die Ladezeiten der Seite optimieren kann.

Dazu spielte ich ein wenig mit loads.in herum: durch das Simulieren von Zugriffen auf meine Seite von extern, aus verschiedenen Ländern, mit verschiedenen Browsern, kam ich zu dem Schluss, dass die Ladezeiten deutlich zu hoch waren; parallel hierzu stellte ich fest, dass die Cache-Hits, die varnish erzielte, deutlich zu gering ausfielen — unschön.

varnish steckt statische Inhalte in den Cache, die nicht Teil einer Session sind; bei WordPress ist jedoch so ziemlich alles Teil einer Session, und somit wurde nichts gecached. Eine rabiate — und recht wirkungsvolle — Methode ist es, alle involvierten Cookies einfach über Bord zu werfen:

sub vcl_recv {
  unset req.http.cookie;
}
 
sub vcl_fetch {
  unset beresp.http.set-cookie;
}

So werden zwar nun Inhalte in den Cache gestopft, jedoch funktioniert — wen wundert’s — auch das Login ins Backend nicht mehr. Also muss der Aufruf dahingehend verfeinert werden, dass alle Cookies, die nichts mit wp-login bzw. wp-admin zu tun haben, weggeschmissen werden:

sub vcl_recv {
  if (!(req.url ~ "wp-(login|admin)")) {
    unset req.http.cookie;
  }
}
 
sub vcl_fetch {
  if (!(req.url ~ "wp-(login|admin)")) {
    unset beresp.http.set-cookie;
  }
}

Das funktionierte dann schonmal sehr viel besser — Items im Cache, Login funktioniert. Zumindest auf meiner Webseite — denn das Joomla, das unter anderer Domain auf dem selben Server gehostet wurde, liess seinen Administrator nun auch nicht mehr ins Backend; also verfeinerte ich im nächsten Schritt den Aufruf, so dass die Regeln nur auf meine Domain Anwendung finden:

sub vcl_recv {
  if (req.http.host ~ "tagebuch.localwurst.de" && !(req.url ~ "wp-(login|admin)")) {
    unset req.http.cookie;
  }
}
 
sub vcl_fetch {
  if (req.http.host ~ "tagebuch.localwurst.de" && !(req.url ~ "wp-(login|admin)")) {
    unset beresp.http.set-cookie;
  }
}

Dann beobachtete ich die Sache. In der Tat funktionierten nun beide Webseites, und auch das Login in beide Backends tat, was man von ihm erwartet; auch wurden durchaus Cache-Hits verzeichnet, aber… naja, wenige halt. Die Dokumentation zur Software ist ein wenig kryptisch, aber irgendwann kam ich dahinter, dass die Default-TTL — also die Zeit, die ein Objekt im Cache verbringt — 120 Sekunden beträgt. Das mag für einen Auftritt wie heise.de sinnvoll sein, aber bei meinem Blog mit dreieinhalb Klicks pro Tag führte das natürlich dazu, dass die Objekte schon wieder aus dem Cache geflogen waren, ehe sie überhaupt erneut angefordert wurden…

Ich setzte also die TTL auf vier Stunden hoch und beobachte derzeit noch, inwiefern das sinnvoll ist:

sub vcl_fetch {
  if (req.http.host ~ "tagebuch.localwurst.de" && !(req.url ~ "wp-(login|admin)")) {
    unset beresp.http.set-cookie;
  }
  set beresp.ttl = 4h;
}

Mit dem folgenden Kommando kann man sehr gut überwachen, welche Objekte wirklich als Anfrage an den Webserver durchgereicht werden:

$ varnishtop -b -i TxURL

Detaillierte Angaben erhält man mit dem folgenden Kommando:

$ varnishstat -f n_object,n_objecthead,SMF.s0.balloc,cache_hit,cache_miss,n_lru_nuked,n_lru_moved

Kurz zur Eräuterung:

  • n_object ist die Anzahl der gecachten Objekte einschliesslich der Variationen gleicher Objekte
  • n_objecthead ist die Anzahl der gecachten Objekte ohne Variationen gleicher Objekte
  • cache_hit ist — ganz klar — die Anzahl der Cache-Hits
  • cache_miss ist — ebenfalls klar — die Anzahl der Cache-Misses (sprich: diese Objekte müssen über den Webserver angefordert werden)
  • n_lru_nuked ist die Anzahl der aus dem Cache verworfenen Objekte (ist der Wert > 0 sollte die Gesamtgrösse des Caches erhöht werden)
  • n_lru_moved ist die Anzahl der in den Cache eingelesenen und bewegten Objekte
  • SMF.s0.balloc ist das, was der Cache aktuell an Speicher belegt

Bleibt anzumerken, dass Zeilen, deren Ausgabewert 0 wäre, nicht angezeigt werden; kommt also zu n_lru_nuked überhaupt keine Aussage, dann ist das sehr gut :-D Mit varnishstat -1 kann man übrigens eine prima Ausgabe erzeugen, die sich auch grepen lässt ;-)

Nun muss ich beobachten, inwiefern vielleicht doch noch Fehler auftauchen; vielleicht erweisen sich die vier Stunden Vorhaltezeit auch als deutlich zu lang, zu kurz, sprich ungeeignet — das muss man sehen. Allzuviel möchte ich auch nicht experimentieren, denn jeder Neustart des Dienstes bedingt das Leeren des Caches, sprich: man fängt dann wieder ganz von vorne an.

Was mir auch sehr geholfen hat ist das mysqltuner-Script, mit dessen Hilfe ich die Performance der Datenbank denn doch deutlich erhöhen konnte; man kommt nicht umhin, sich in viele Dinge grundlegend einlesen zu müssen, aber einmal verstanden macht es sehr viel Spass — und die Seite rennt.

Deshalb die Frage an euch: kommen meine Bemühungen bei euch an? Bemerkt Ihr eine signifikante Leistungssteigerung, Reduzierung von Ladezeiten, oder hat sich für euch nichts geändert?

Update: an dieser Stelle habe ich mich dem Thema erneut gewidmet und eine ausgefeiltere Konfiguration erstellt!

4
  1. Das ist mir auch sofort aufgefallen, das die Seite sehr schnell nach oben fährt. Als ich mir deinen Text durchgelesen habe wurde mir Stück für Stück klar, dass Frauen doch etwas von Technik verstehen, denn ich habe kaum ein Wort von dem was gesprochen wurde verstanden.

  2. laut dem FF-Plugin „Fasterfox“ wurde diese Seite in 1,881s geladen. Passt :)

    Suchst du noch was zum Spielen? Dann vergleiche mal apache 2.2 mit apache 2.4 und ob da was schneller wird ;)

  3. laut dem FF-Plugin Fasterfox wurde diese Seite in 1,119s geladen.

    Falls du noch was zum Spielen suchst: teste doch mal, ob apache 2.4 irgendwas schneller/besser macht;)

  4. Ich finde die Seite auch superschnell. Etwas störend ist eher, dass ich hier das mobile Theme angeboten bekomme :-)

    Wenn du es noch weiter auf die Spitze treiben willst: du könntest vermutlich weit mehr als 4h cachen und Elemente gezielt beim Update im WordPress-Backend aus dem Cache löschen. Das Plugin wp-varnish sollte da weiterhelfen (das habe ich aber selbst auch noch nicht im Einsatz). Und du kannst auch eine neue vcl laden, ohne Varnish neuzustarten: /usr/share/varnish/reload-vcl

    • Vielen vielen Dank für den Hint mit dem /usr/share/varnish/reload-vcl – das kannte ich nicht!

      Das Plugin wp-varnish habe ich natürlich im Einsatz ;-) Und wenn man php5-curl installiert, dann tut es sogar, was es soll.

      Offenbar wurde das Posting in erster Instanz von jemandem mit mobilem Endgerät aufgerufen; das ist dann die Version, die im Cache landet, und somit die Version, die alle weiteren Leser erhalten #schock (bis nach Ablauf der vier Stunden halt); wie man dieses umgehen könnte weiss ich allerdings auch gerade nicht *völlig_ratlos‘ …

  5. Jepp, man spürt gar nicht, dass hier irgendwas lädt; der Browser hat noch nichtmal Gelegenheit seinen Ladebalken auszupacken.

Keine weitere Reaktionen mehr möglich.