Simone: Speicherverbrauch zur Laufzeit berechnen

HI,

ist ja schick hier geworden ;o) war schon lange nicht mehr hier ...

Ok, zu mein Problem:

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...

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.

1. ) ich nutze den Shared Memory Bereich hinterlege dort die Serverkennung und die PIDs

maximal 5-10 Bilder pro Server sollen zur ist Zeit erzeugt werden. (Muss ich noch testen)

jetzt geht es um die Route zur Berechnung des Ramverbrauches und Cpu Belastung

	  
  
$ps_lines = @explode("\n", `ps -u www-data -o rsz -o vsz -o pid`);  
  
	if(is_array($ps_lines))  
	{  
	foreach($ps_lines as $temp => $ps_line)  
	{  
	    @list($RSZ,$VSZ,$PIDS) = @preg_split('/\s+/', $ps_line);  
			if(is_numeric($RSZ.$VSZ.$PID) and $RSZ.$VSZ.$PID  > 0)  

VSZ & Virtuelle Prozessgröße
RSS & Größe des residenten Speichers

$RSZ
$VSZ

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

Sollte doch möglich sein ;o)

  1. Hi,

    Um die einzelnen Cluster Server nicht in die Knie zu zwingen habe ich mir folgendes Konzept ausgedacht.

    1. ) ich nutze den Shared Memory Bereich hinterlege dort die Serverkennung und die PIDs

    maximal 5-10 Bilder pro Server sollen zur ist Zeit erzeugt werden. (Muss ich noch testen)

    Ich würde das eher als eine Art Queue realisieren – und jeder Server im Cluster der gerade “nichts zu tun” hat, holt sich ein Item aus der Queue und verarbeitet es.

    MfG ChrisB

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
    1. Ich würde das eher als eine Art Queue realisieren – und jeder Server im Cluster der gerade “nichts zu tun” hat, holt sich ein Item aus der Queue und verarbeitet es.

      Jepp! Wobei die Frage entsteht, ob ein ein (1) Item sein soll. Immerhin werden in Servern Mehrprozessorsysteme verbaut und die Frage, ob das gegenständliche Programm einen oder mehrere CPU "beschäftigt" sollte man auch stellen.

      Im Übrigen enthalten die "Ordner" /proc und /sys "Dateien" mit wertvollen Informationen. Ein

      $ less /proc/meminfo  
      
      

      ist schon mal informativ und zeigt, wie es dem Rechner hinsichtlich des Speichers "ganz allgemein so geht". Wenn man ein Programm in einer (sub-)shell startet und dabei in den Hintergrund schickt kann man in der selben (sub-)shell mit echo $! dessen PID erfahren oder diese mit pid=$! speichern und dann auch in /proc/$pid nachsehen, wie es dem Programm selbst geht...

      $ program &  
      $ pid=$!;  
      $ less /proc/$pid/status
      

      ... liefert dann also einige Informationen zum Programm "program".

      Will man davon bestimmte, dann kann man die durch den (e)grep, tr und ggf. noch durch sed jagen:

      $ program &  
      $ pid=$!;  
      $ grep 'VmSize:' /proc/$pid/status | cut -d ':' -f2 | tr -d ' ' | tr -d "\t" | sed '~s/kB/000/'
      

      Natürlich geht es auch einfacher. Man lege auf Grund von Erfahrungswerten einfach die Anzahl der maximal zu startenden Jobs in dem verwaltenden Programm fest.

      Jörg Reinholz

      1. Hi,

        Danke für die Antworten ;o)

        Leider bin ich kein "Server Mensch"

        habe mich jetzt etwas reingelesen

          
        $ free -m  
                     total       used       free     shared    buffers     cached  
        Mem:          7988       5955       2032          0        169       5041  
        -/+ buffers/cache:        745       7243  
        Swap:         1968          0       1968  
        
        

        Dort müsste sich ja irgendwo was ändern bei Ram Last (Bildbearbeitung) woraus man was ableiten könnte

        Hm --- leider keine Ahnung wie ich das machen kann

        1. Danke nochmal an Alle!!

          Hier der Code

          	  
          	print_d(free_m());  
            
            
            
            
            
          function print_d($array_debug, $exit = false)  
          {  
              echo "<pre>";  
              echo "-------------------------------------------<br>";  
              echo " Count  =  <b>" . count($array_debug) . "</b><br>";  
              echo "-------------------------------------------<br><br>";  
              print_r($array_debug);  
              echo "</pre>";  
              if ($exit == true) {  
                  exit();  
              }  
          }  
            
            
            
            
            
              function free_m()  
              {  
                  $cmd = 'free -m | grep "buffers/cache" | sed -e "s/-\/+ buffers\/cache:\s*\([0-9]*\)\s*\([0-9]*\).*/\\1 \/ \\2/"';  
                  $memoryUsage = explode('/', exec($cmd));  
                  if (is_array($memoryUsage)) {  
                      if (count($memoryUsage)) {  
                          $memory = array(  
                              'used' => trim($memoryUsage[0]),  
                              'free' => trim($memoryUsage[1]),  
                          );  
                          $memory['total'] = $memory['used'] + $memory['free'];  
                          if ($memory['total']) {  
                              $memory['%'] = $memory['used'] / $memory['total'] * 100;  
                          }  
                      return $memory;  
          			}  
                  }  
              }  
          
          
          model name	: Intel(R) Xeon(R) CPU E5645 @ 2.40GHz  
          -------------------------------------------  
          -------------------------------------------  
           Count  =  4  
          -------------------------------------------  
            
          Array  
          (  
              [used] => 771  
              [free] => 7217  
              [total] => 7988  
              [%] => 9.65197796695  
          )  
            
          model name	: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz  
          -------------------------------------------  
          -------------------------------------------  
           Count  =  4  
          -------------------------------------------  
            
          Array  
          (  
              [used] => 253  
              [free] => 1751  
              [total] => 2004  
              [%] => 12.624750499  
          )  
            
            
          model name	: AMD Athlon(tm) II X3 405e Processor  
          -------------------------------------------  
          -------------------------------------------  
           Count  =  4  
          -------------------------------------------  
            
          Array  
          (  
              [used] => 889  
              [free] => 3038  
              [total] => 3927  
              [%] => 22.6381461676  
          )  
            
          
          

  2. 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