Hohe CPU-Last durch adaptierte Skripte oder Queueing reduzieren?

SolarCatcher

Well-Known Member
Ich habe folgende Situation: Ein Webserver cacht HTML-Dateien lokal zwischen und liefert - falls vorhanden - diese aus (funktioniert ungefähr wie die typischen Caching-Plugins für WordPress: W3 Total Cache, WP Super Cache u.ä.). Das ist soweit unproblematisch und läuft gut.

Im Anschluss werden diese HTML-Dateien aber noch etwas nach-optimiert (HTML minifiziert, komprimierte Versionen gzip und brotli erzeugt) und das ist vergleichswiese aufwändig. Wenn dann einer dieser eher unfreundlichen Bots daherkommt (Google justiert die Crawl-Rate offenbar recht gut, notfalls kann man Google auch geringere Rates vorgeben; andere sind da nicht so nett) erzeugt das aber manchmal zu hohe Prozessor-Last und das System wird sehr zäh. Ich habe es schon mit nice probiert, aber das kann das Problem nur mildern, nicht abstellen.

Ich sehe zwei Möglichkeiten, das Problem zu entschärfen und würde gerne mal wissen, welches Vorgehen/welche Tools Ihr dafür nehmen würdet:

1) Ich könnte die nachträgliche Optimierung reduzieren (z.B. die Stärke der Kompression mit zopfli/gzip bzw. brotli) wenn das Shell-Skript dazu die aktuelle CPU-Auslastung kennen würde. Hier weiß ich aber nicht, wie man da vorgehen würde und ob das tatsächlich performant wäre. Ziel wäre sowas wie "Ist die Prozessorlast über 80%, dann reduziere die Kompression auf ein Minimum (z.B. gzip -1".

2) Man könnte die Optimierungen in eine Queue schieben, von der sie abgearbeitet werden, sobald es die Prozessorlast (wieder) zulässt. Dann werden halt mal ein paar Minuten nicht-optimierte Dateien ausgeliefert, aber das System bleibt ansich einigermaßen responsiv. Ich habe mir dazu mal sowas wie at bzw. batch angeschaut, aber das wird standarmäßig nur alle 5 Minuten ausgeführt (Standard-Eintrag für atrun unter /etc/crontab). Gäbe es da eine einfache Lösung für einen etwas feiner-granulierten Queue-/Spool-Mechanismus, den man von einem Shellskript aus nutzen kann?

Oder gibt es noch einfachere/bessere Lösungswege?
 
Benutzt du wirklich gzip? Wäre pigz nicht eventuell besser geeignet?
Wie stark komprimierst du denn normalerweise? Lohnt es sich überhaupt starke Kompression zu benutzten (CPU last vs. Bandwidth/Traffic)?
 
Die Frage die sich mir stellt - wieso werden die html Datein nicht gleich optimiert wenn sie erstellt werden, bzw. im Cache landen? Wäre das nicht die beste Möglichkeit?
Wenn das alles eine geschlossene SW ist, hilft vielleicht ein caching reverse Proxy? Hier kanns natürlich wieder eklig werden den Cache zu invalidieren.

Ansonsten würde ich - wenn nicht ganz spezielle Umstände vorliegen - die Optimierung möglichst gering halten, gzip -1 liefert bei Text ähnlich gute Results wie gzip -6 oder gar -9. Und hilft das simplifizieren viel wenn man danach ohnehin komprimiert? Wenn im Vergleich zu nem einfachen gzip -1 durch das komplexe minifizieren / komprimieren nur nur 15-20% zusätzlich rausholt würd ichs einfach lassen :D
 
@gadan Normalerweise macht zopfli die gzip-Komprimierung. Das ist richtig aufwändig, aber in "normalen" Zeiten völlig OK, nur eben nicht, wenn z.B. ein Bot mehrere hundert Webseiten pro Minute abfragt, die oftmals noch nicht gecacht sind. Da wäre es schön darauf reagieren zu können.

Was Dateigrößen anbelangt, habe ich gerade nochmal händisch gecheckt - die Stärke der Komprimierung macht schon einen Unterschied:
Code:
Ausgangsdatei: 169.977
gzip -1:        27.393
gzip -9:        22.108
zopfli:         21.331
brotli:         17.902

Man sollte dazu vielleicht wissen, dass ich ein Webperformance-Fan bin. Ich versuche möglichste viele Dinge (im Front- und Backend) zu optimieren, damit wir wirklich schnelle Seiten haben. Bei Google Pagespeed kommen wir mit den allermeisten Seiten auf 90-100 von 100.

@medV2 Die Cache-Dateien werden direkt vom Webserver gespeichert (www/h2o-devel mit integriertem Mruby). Ich will den aber nicht durch die anderen Optimierungsschritte blockieren. Daher wird am Ende asynchron ein CGI-/Shell-Skript aufgerufen, das das HTML minifiziert und dann komprimiert. Ein externer Cache kommt nicht in Frage, weil in dem Caching auch noch Paywall-Funktionionalität steckt (so ein bisschen wie Varnish Paywall; nur selbstgebaut und damit überhaupt bezahlbar für meinen Kunden).
 
Die Konfiguration des Webservers wäre ziemlich hilfreich.
Verstehe Deinen Anliegen. Aber es handelt sich hier nicht um eine normale "Konfiguration" sondern schon um eine kleine Ruby-Applikation, die direkt im H2O-Webserver läuft.

Wen soetwas interessiert, dem empfehle ich wärmstens die Präsentation "How happy they became with H2O/mruby, and the future of HTTP" (ich verstehe kein Japanisch, daher ist das YouTube Video nix für mich, aber die verlinkten Slides waren für mich wirklich eine Inspiration).
 
Nur damit ich das auch richtig verstehe: Deine Scripte laufen also nachdem der Cache erstellt wurde auf die gecachten HTML Files und ersetzen die dann - das geschieht asynchron?

Dann wäre tatsächlich ne einfache load-Abfrage ein schneller weg - wenn der load höher als XY ist, führst du im Script halt nicht Optimierungsfunktion A sondern B aus, und B lässt einiges weg. Oder du setzt mit einem wait einfach das ganze Script für 10 Sekunden aus wenn die Last hoch ist und überprüfst dann nochmal. Wenn alles Async ist, sollte das ja auch kein Problem sein, wird der Cache bei Last eben etwas später nachoptimiert. Also ja eigentlich das, was du schon selbst angedacht hast :D

Oder - wenn der Service z.b. in einer Cloud läuft (jaja, böse!) - die Leistung deiner VM on the Fly auf die Last anpassen.
 
Nur damit ich das auch richtig verstehe: Deine Scripte laufen also nachdem der Cache erstellt wurde auf die gecachten HTML Files und ersetzen die dann - das geschieht asynchron?
Ja, das beschreibst Du richtig (nur "ersetzt" werden die Original-Cache-Dateien nicht; die un-optimierten Dateien würden immer noch ausgeliefert an Webclients, die nicht signalisieren brotli oder gzip zu beherrschen)


Dann wäre tatsächlich ne einfache load-Abfrage ein schneller weg

Und wie würde man da vorgehen? Welchen Befehl oder welches Tool verwendet man am besten, um die Load abzufragen? Ich habe eine ganze Weile danach gegoogelt, aber bin nicht so wirklich glücklich gewesen mit den Antworten (klappte in der Praxis oft nicht).
 
Ich nehme an du verwendest FreeBSD, da du die Ports gelinkt hast, da wäre sysctl vm.loadavg ne denke ich brauchbare Option. Der erste Wert ist das LoadAVG für 1min, dann 5 und 10 (oder 15). Relevant für dich also wohl der erste oder zweite Wert.

Unter Linux wär das ganze unter /proc/loadavg

Mit h2o kenn ich mich leider nicht wirklich aus, aber für Apache/nginx/lighttpd gibts Module über die du die Last direkt vom Webserver abfragen kannst. Z.b. wieviel gleichzeitige Verbindungen offen sind oder wieviele Clients du grade hast. Das wäre sonst auch ein guter Wert für dich.
 
Ich nehme an du verwendest FreeBSD, da du die Ports gelinkt hast, da wäre sysctl vm.loadavg ne denke ich brauchbare Option. Der erste Wert ist das LoadAVG für 1min, dann 5 und 10 (oder 15). Relevant für dich also wohl der erste oder zweite Wert.
FreeBSD ist schon richtig! Vielen Dank - genau diese Info hatte ich gesucht.

Mit h2o kenn ich mich leider nicht wirklich aus, aber für Apache/nginx/lighttpd gibts Module über die du die Last direkt vom Webserver abfragen kannst. Z.b. wieviel gleichzeitige Verbindungen offen sind oder wieviele Clients du grade hast. Das wäre sonst auch ein guter Wert für dich.
Auch bei H2O kann man statistische Daten abfragen - ich habe allerdings noch nicht geschaut, welche genau. Die Zahl der Verbindungen oder Requests in der letzten Minute o.ä. wären allerdings nicht soo interessant, weil es in diesem Fall einen gewaltigen Unterschied macht, ob "normale" Nutzer kommen, die vor allem an denselben, aktuellen Infos interessiert sind (es handelt sich um ein Newsportal in einer bestimmten Branche) - dann sind die Seiten in denn allermeisten Fällen bereits gecacht. Oder ob eben ein (Search-)Bot kommt, der massenhaft auch alte, selten gefragte Artikel abgrast. Daher ist die CPU-Last vermutlich schon der relevanteste Faktor für mein Optimierungs-CGI.
 
Zurück
Oben