Alexander (HH): Server Systemauslastung Normalwerte

Beitrag lesen

Moin Moin!

Du brauchst jemanden, der sich WIRKLICH damit auskennt.

Hab keinen ;O) und mit Linux kenne ich mich nur oberflächlich aus.

Du hast einen Managed Server. Greif Dir den Manager und laß den seinen Job machen. Und wenn der keinen Plan hat, sollte er wenigstens jemanden kennen, der Dir weiterhelfen kann -- notfalls gegen Geld. Oder jemand aus dem Forum. Hier gibt es ein paar Leute, die gegen Geld genau das machen, was Du brauchst -- eine gründliche Analyse Deiner Anwendung.

Es geht nicht um Größe, es geht um Geschwindigkeit. Wenn Deine Anwendung 80% der Zeit mit dem Shared Memory rumfummelt, obwohl es nur 10KByte groß ist, ist es Dein Problem.

1 mal lesen + 1 mal schreiben pro Zugriff im Ram das sollte den Server nicht plattmachen.

Es wird vermutlich nicht bei einem Zugriff bleiben.

Finde den Bottleneck.

JA ABER WO??? Oder besser gesagt wie??

Messen, messen, messen, und nochmal messen.

Kannst Du mir bitte sagen wie! Programme die sowas unter Linux das machen sind mir nicht bekannt.

Du hast kein Linux-Problem (das schließe ich einfach mal so aus, eben weil Du einen managed Server hast), sondern Performance-Probleme in Deiner PHP-Anwendung und evtl. auch in Deinem MySQL-Server.

Also brauchst Du keine großartigen Linux-Kenntnisse, um herauszufinden, was so lange dauert. Nehmen wir mal an, Deine Anwendung würde aus folgendem (Pseudo-)Code bestehen:

function main(request) {   var config=read_config();   var db=connect_db_cached(config->db);   var data=validate_input(request);   var output=calculate_output(db,data,config)   var html=fill_template(output);   return html; }

Wie bekommst Du jetzt raus, wo es klemmt? Natürlich mit dem guten alten printf-Debugger, sprich: Du fügst Diagnose-Ausgaben ein. Damit das einfacher geht, baust Du Dir erstmal einen kleinen Helfer:

function log_debug(msg) {   var now=hires_time_string();   printf(stderr,"%s: %s\n",now,msg); }

Und den rufst Du dann vor und nach kritischen Bereichen auf und berechnest anschließend aus dem generierten Log die Laufzeiten der jeweiligen Funktionen:

function main(request) {   log_debug('anfang');   var config=read_config();   log_debug('config gelesen');   var db=connect_db_cached(config->db);   log_debug('db connected');   var data=validate_input(request);   log_debug('input validated');   var output=calculate_output(db,data,config)   log_debug('output calculated');   var html=fill_template(output);   log_debug('html generated');   return html; }

Das ergibt dann ungefähr so eine Ausgabe:

Tue Jan 13 17:00:42.123 2008 anfang Tue Jan 13 17:00:42.227 2008 config gelesen Tue Jan 13 17:00:45.875 2008 db connected Tue Jan 13 17:00:45.925 2008 input validated Tue Jan 13 17:01:58.456 2008 output calculated Tue Jan 13 17:01:59.001 2008 html generated

In diesem Beispiel fällt auf, das connect_db_cached() und calculate_output() extrem langsam sind (3,5 bzw. 12,5 Sekunden), während der Rest in Sekundenbruchteilen durchläuft.

Also baust Du die log_debug-Aufrufe entsprechend in connect_db_cached() und calculate_output() ein, die anderen Aufrufe in main() bleiben erstmal drin! Das wiederholst Du notfalls so lange, bis Du an eingebauten Funktionen von PHP ankommst.

Irgendwann hast Du die kritischen Stellen eingekreist und kannst dort dir Geschwindigkeit optimieren. Das kann in diesem Beispiel z.B. ein SELECT mit mehreren JOINs und WHERE über nicht indizierte Spalten sein, das auch noch größere Datenmengen aus der DB in die Anwendung schaufelt.

Hast Du je eine Liste der am häufigsten und am längsten laufenden SQL-Queries? Wenn nein, warum nicht?

Nein, das habe ich mir auch schon überlegt. Gibt es zum Auswerten der Mysql Querie logs Programme. Bzw. wiekann ich das bewerkstelligen?

Das sollte im MySQL-Handbuch stehen. MySQL ist zwar IMHO eine katastrophale Datenbank, aber wenigstens ist fast alles dokumentiert.

Im dümmsten Fall ersetzt Du die Funktion, die ein SQL-Statement an die DB überreicht, durch eine eigene Funktion, die die SQL-Statements loggt.

function prepare_sql_debug(db,command) {   log_debug(command);   return prepare_sql(db,command); }

Hast Du überprüft, auf welchen Spalten und Spaltenkombinationen die Queries laufen? Und das für diese schweren Fälle passende Indices vorhanden sind?

Zumindest das was mir bekannt ist Explain Select .......... usw.

Und passen die Indices zu den Queries?

MySQL sollte bei explain select eigentlich einen abstrakten Kostenfaktor ausgeben, den Du möglichst klein halten solltest. (Oops, nee, tut MySQL natürlich NICHT!)

Meine Vermutung ist auch das es an Mysql liegen kann.

MySQL ist zwar s..., aber nicht so s..., dass es sich auf Kosten der CPU nur mit sich selbst beschäftigt. MySQL sollte im Leerlauf keine CPU brauchen, die CPU-Last kommt dann "nur" von Deinen SQL-Statements und Deiner DB-Struktur. Es liegt also sehr wahrscheinlich an Deinem SQL in Kombination mit Deiner DB-Struktur.

Mir fehlen einfach Vergleichswerte.

Brauchst Du nicht unbedingt. Die gängigen Daumenwerte sagen, dass Du eine Seite innerhalb von 2 bis 3 Sekunden vollstädig ausgeliefert haben solltest. Und eine load averge von mehr als 100% pro CPU ist für ein Unix-System auch nicht gut, sprich: Ein Single-Core-Prozessor sollte mit der Load deutlich unter 100% bleiben, ein Dual-Core-Prozessor bzw. zwei einzelne CPUs sollten insgesamt nicht über 200% load average gehen.

Laufzeit-Informationen Dieser MySQL-Server läuft bereits 0 Tage, 14 Stunden, 14 Minuten und 15 Sekunden. Er wurde am 12. Januar 2009 um 20:49 gestartet.

Abfragestatistik: Seit seinem Start wurden 1.608.278 Abfragen an diesen MySQL-Server gesandt. Insgesamt   ø pro Stunde   ø pro Minute   ø pro Sekunde 1.608.278   112.960,70       1.882,68      31,38

30 Abfragen pro Sekunde, mit einer Nacht dazwischen? Deine Anwendung ist sehr DB-intensiv. Versuche, daran zu drehen.

Abfrageart   ø pro Stunde   % delete   69.747   4.898,82   4,78 %

Warum löschst Du so viel aus der DB?

insert   356.186   25.017,45   24,43 %

select   398.842   28.013,49   27,35 %

update   109.894   7.718,63   7,54 %

Das Verhältnis von Insert und Select kommt mir seltsam vor. Mir scheint, alles was Du schreibst, liest Du nur ein einziges Mal wieder, danach wird es nicht mehr gebraucht.

Über 14 Stunden ist das natürlich eine sehr wackelige Statistik.

Weitere Statusvariablen Variable   Wert Created tmp disk tables   99375 Created tmp tables   129594

Warum so viele temporäre Tabellen?

Ist Dein DB-Schema kaputt? Nicht normalisiert?

Open tables   541

Über 500 offene(!) Tabellen? Was machst Du mit so einem riesigen DB-Schema?

Nichr raten, messen, messen, messen.

Ja womit und wie?

Siehe oben.

Wie lange ein HTTP-Request dauert, kannst Du u.a. mit firebug herausfinden.

Warum willst Du Deine Anwendung unbedingt mit einem ".html" am Ende der URL ausliefern? Dem Browser ist das Ende der URL vollkommen egal, umd dem Server macht es weniger Arbeit, wenn Du auf so einen Unsinn verzichtest.

Geht nicht bin auch ein wenig SEO

Scheiße Endet Oben?

Glaubst Du wirklich, irgendeine Suchmaschine würde sich für das Ende Deiner URL interessieren? MIME-Types vielleicht, aber nicht irgendwelche URL-Bruchstücke.

Caching?

Ja! ca. 24 Stunden als *.zip File. Mysql Cache ist on. Hauptdatenbänke im Cache ohne upload und co. Bei der Entwicklung der Seite habe ich mir überlegt wenn ich Datenbankabfragen der letzten 24h als File bzw. fertiges *.html im Cache Ordner lege gewinne ich Zeit und entlaste den MysqlServer.

Hast Du überlegt, wie oft die selbe Abfrage innerhalb 24h kommt?

Schalte diese Logik mal komplett ab. Insbesondere, wenn Du die Dateien in ein ZIP-File packst, das bei jedem Request aktualisiert wird, hast Du eine RIESIGE Performance-Bremse. File-I/O ist langsam, aber wenn Du File-I/O auf ein komprimiertes Archiv machst, verbrennst Du auch noch jede Menge RAM und CPU für das Komprimieren und Dekomprimieren.

Wenn Du 20x eine Liste aller Uploads eines Users brauchst, machst Du dann 20x "SELECT FROM UPLOADS WHERE userid=x"? Oder machst Du den SELECT nur beim ersten Mal und merkst Dir das Ergebnis für die nächsten 19 Mal?

Das macht der Mysql Cache

Das ist die falsche Stelle! MySQL muß Dein SQL-Statement 20x parsen, 20x seinen Cache prüfen, und 20x Daten ausliefern, die Du schon in der Anwendung hast. Und im schlimmsten Fall baust Du 20x eine TCP-Verbindung zu MySQL auf, um jeweils das selbe Statement ausführen zu lassen, inklusive DNS-Abfrage für localhost. Frag die DB nur einmal pro Request nach Daten, die sich innerhalb eines Requests sehr wahrscheinlich nicht ändern. Und benutze die Verbindung zu MySQL mehr als einmal, möglichst für den gesamten Request.

Packe die SQL-Statements in Funktionen, die bevorzugt das jeweils letzte Ergebnis zurückliefern, statt die DB zu befragen.

memcached könnte da hilfreich sein.

PHP Version? Libraries? Frameworks?

Da habe ich keine Ahnung was Du meinst. Ich nutze so gut wie keine fertigen Programme.

MySQL Version 4.0.23_Debian-7 Php Version  4.3.10,

Beides nicht mehr so ganz frisch. Debian macht zwar Backports von Bugfixes, aber PHP 4 ist TOT. (Müffelte ja auch schon eine ganze Weile recht unappetitlich.)

Ein Update möchte ich nicht weil ich nicht weis ob dann noch alles läuft!

Ich verkneife mir den Kommentar mal, trotz der guten Vorlage.

Ich habe einen managed Server weil ich kein Linux Mensch bin.

Du solltest aber in der Lage sein, mit deinen Werkzeugen zu arbeiten. Wenn Du es nicht kannst, lerne es.

Google ist Dein Freund, http://en.wikipedia.org/wiki/PHP_accelerator ist ein brauchbarer Anfang. »» Habe ich mir mal vor längerer Zeit angesehen. Aber irgendwie sind damals nur die kostenpflichtigen Versionen stabil gewesen.

You get what you paid for. Entweder setzt Du Dich mal ein paar Tage hin und suchst die unperformanten Stellen, oder Du nimmst Geld in die Hand und hoffst, das diese Software schnell genug ist, um Deine Fehler auszubügeln.

Vermeide, ALLE Resourcen per PHP auszuliefern. Das ist nicht soeinfach umzusetzen. Bei den Anwendungen kann kein reines  Filesystem aus statischen Seiten Anwendung finden.

Erzähl mir was neues. Ich baue seit 10 Jahren Web-Anwendungen und verdiene damit mein Geld. Aber statische Resourcen nur um der URL willen durch PHP zu prügeln ist schlicht und ergreifend dämliche CPU-Quälerei.

Und nochmals eine Frage welche Programme / Befehle eignen sich unter Linux / Php zum finden von Laufzeitintensiven Prozessen.

Die graue Pampe zwischen Deinen Ohren.

Also eine Auswertung / Überwachung von:

top

1546 nobody    16   0  143m 4912 3540 R 19.1  0.2   0:00.50  0 /usr/sbin/httpd -k restart

Das ist viel zu grob, damit siehst Du nur von außen auf den Webserver. Du mußt das innere der Anwendung betrachten.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".