Moin,
Ich habe eine Cluster aus drei pysikalischen Web-Server. Jetzt habe ich ein Skript geschrieben welches Bilder zur Laufzeit erstellt und ausgeben soll. Die Bilderstellung dauert ewig lange...
Das ist bei Bildern eher normal. :) Caching von Ergebnissen ist daher nahezu zwingend notwendig, wenn sich am Ergebnis ansonsten nichts ändert.
Da ich mehrere Server betreibe möchte ich die Rechenleistung optimal ausnutzen.
Praktisch erzeugt die Website (liegt nicht im Cluster) wo das Bild benötigt wird eine GET Übergabe an den Clusterverbund.
Dieser bekommt die Aufgabe die Bilder zu erzeugen und dann per FTP zur WEbsites zu schieben.
das funktioniert soweit auch ganz gut.Um die einzelnen Cluster Server nicht in die Knie zu zwingen habe ich mir folgendes Konzept ausgedacht.
Es ist ein Cluster. Der wird per Definition die Anfragen verteilen und lastmäßig optimieren.
Oder ist es eben gerade kein Cluster, sondern nur mehrere Maschinen nebeneinander, und die Verwaltung ist dein Bier?
In solch einem Fall wird man sich eine Queue bauen wollen (gibts schon fertig, "Gearman" wäre mein Favorit - Anbindung für PHP und viele andere Programmiersprachen existiert), in die die Webseite die Aufträge einstellt, und die weiteren Maschinen haben Worker laufen, die jeweils einen Auftrag der Queue zur Zeit abarbeiten.
So wie ich das im Moment verstehe, schickt die Webseite in dem Fall, dass lokal noch kein Bild existiert, einfach einen anderen Bild-Link, der dann auf den Cluster trifft und dort die Generierung startet. Am Ende wird das erzeugte Bild auf den Webserver kopiert, und ab dann wird der Generierungslink nicht mehr erzeugt. Das ist natürlich einfach in der Verwaltung, weil du im Cluster nur Generierungsskripte hast, die einfach machen, und der Webserver schaut auch nur nach, ob er schon ein Bild im Cache hat. Zusammengesetzt wird beides im Browser, allerdings mit nachvollziehbaren Unterschieden. Die Generierung auf dem Cluster ist nicht transparent.
Ein Angreifer kann die Bild-URLs im Cluster also kennen und zur Überlastung desselben durch Massenabfragen leicht beitragen. Ebenso reicht es aus, im ungecachten Bildzustand einfach mehrmals Reload zu drücken, um dadurch mehrere Cluster-Jobs desselben Bildes zu starten.
Das ist also nicht optimal.
Mit Gearman würde der Webserver einen Bilderzeugungsjob in die Queue legen, und ein Worker des Clusters würde den Job ausführen. Wenn die Arbeit getan ist, kriegt der Webserver die Nachricht der Fertigstellung - und wenn der Worker genauso wie bisher das Bild auf den Webserver gelegt hat, kann der Webserver von dort das Bild ausliefern.
Vorteile: Du kannst bestimmen, wieviele Worker auf jeder der Cluster-Maschinen laufen. Wieviele das sein sollen, wäre entweder durch Ausprobieren zu ermitteln, man kann sowas aber auch ausrechnen, wenn man weiß, wieviele Ressourcen für einen Worker für eine Aufgabe draufgehen. Man kann das Ganze auch dynamisch machen, indem ein Cronjob regelmäßig die Maschinenauslastung ermittelt und ggf. noch neue Worker startet.
Allerdings gilt der alte Lehrsatz der Queues: Sie sind entweder immer leer, oder immer voll. Niemals so halbvoll. Heißt: Entweder hast du genug Worker und Rechenpower, um alle reinkommenden Jobs sofort abzuarbeiten, so dass kein Job wartet (sondern eher die Worker ständig unbeschäftigt sind), oder du kriegst so viele Jobs rein, dass die Worker permanent in Vollauslastung arbeiten, und trotzdem nicht hinterherkommen (die Queue wird dann nur deshalb nicht unendlich groß, weil irgendwann Browser auch mal Timeouts haben und durch die Unverfügbarkeit der Bilder nicht weitergeklickt wird).
Ich möchte ein Schwellwert für CPU und RAM modellieren um den Server vor "Überlastung" zu schützen...
Verbraucht die Bildbearbeitung mehr als 40 Prozent an RAM bzw. CPU muss ein anderer Cluster benutzt werden. Das macht er automatisch bei der nächsten GET Anfrage
Finde ich keine so gute Idee. Das bedeutet ja, dass die erste Maschine so lange benutzt wird, bis sie unter Vollast liegt - erst dann wird die zweite Maschine benutzt.
Mit Gearman würde man ggf. zwar in der Verteilung der Jobs auf die Maschinen nicht direkt eingreifen, aber zumindest würden alle Maschinen des Clusters alle jeweils gestarteten Worker gleichzeitig zur Erledigung der Jobs anbieten - und Gearman steuert die Verteilung automatisch.
Das Thema ist allerdings komplex. Die Gestaltung der Worker ist der Knackpunkt. Man kann einen Worker so bauen, dass er genau eine Aufgabe übernimmt, und deine Bildgenerierung wäre dann genau diese eine Aufgabe.
Man kann die Bildgenerierung aber vermutlich auch in einzelne Zwischenschritte aufteilen. Dann könnte man die Einzelschritte einzeln ansteuern, und Worker könnten ihrerseits nach Erledigung des ersten Schritts den zweiten eigenständig in die Queue einstellen und ggf. auf einer anderen Maschine ausführen lassen.
Man kann auch unterschiedliche Jobs anbieten, wenn z.B. unterschiedliche Bildgenerierungen stattfinden sollen. Schreibt man dafür jetzt ZWEI Worker, die jeweils nur einen Job erledigen können, hat man zwar genau dieselbe einfache Situation, aber jetzt das Problem, wieviele Worker man pro Maschine und pro Job startet. Wenn 5 Worker für einen Job die Maschine auslasten können, aber parallel auch noch 5 Worker für den anderen Job laufen und ebenfalls benutzt werden, wäre die Maschine zu 200% auslastbar - das klingt nach keiner so guten Idee. Wenn man beide Jobs in einen Worker integriert, führt jeder Worker nur genau einen der beiden Jobs aus - dafür sind diese Worker aber ein wenig komplizierter zu bauen.
Der Bonus bei Gearman: Wenn derselbe Job mit denselben Parametern zweimal in die Queue getan wird, wird nur ein Worker damit beschäftigt, die erfolgreiche Ausführung aber beiden Auftraggebern rückgemeldet. Das verhindert Doppelarbeit sehr effektiv.
- Sven Rautenberg