Tuning von WordPress mit varnish

Tuning von WordPress mit varnish

Diesen Beitrag schrieb ich 10 Jahre und 6 Monate zuvor; die nachfolgenden Ausführungen müssen heute nicht unbedingt noch genau so funktionieren. Behalte das beim Lesen (und vor allem: beim Nachmachen!) bitte stets im Hinterkopf.

Geschätzte Lesezeit: 3 Minuten

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.

Und 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, ließ 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 einschließlich 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öße 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 Spaß – 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!