Eddie: /MySQL: DB-Connection auch bei Last sicherstellen

Hallo allerseits,

bei höherer Serverlast habe ich in letzter Zeit Probleme, die Verbindung zur Datenbank herzustellen:

Warning: mysql_connect(): User xxx has already more than
   'max_user_connections' active connections in xxx on line 51
   [Verbindungsfehler ] ( 1203 : User p7808352 has already more than
   'max_user_connections' active connections )

Ich habe jetzt zuerst mal persistente Datenbank-Verbindungen mit mysql_pconnect() probiert, aber zum einen schien das nicht wirklich was zu ändern, zum anderen gab es bei einigen schreibenden Zugriffe ernsthafte Probleme.

Was könnte ich sonst noch machen? Ich habe mir überlegt, ggf. die Datenbankverbindung mehrmals zu versuchen, in einer entsprechenden Schleife mit sleep() dazwischen. Also bspw. 3 Verbindungsversuche mit jeweils 3 Sekunden Wartezeit. Meint ihr das bringt was?

Da das Problem im Augenblick akut ist, kann ich auch mit einer nicht so perfekten Lösung leben, für Anregungen wäre ich euch darum sehr dankbar!

Eddie

--
Old men and far travelers may lie with authority.
  1. Hi,

    wie lange laufen deine Skripte und wie oft benötigen sie die Verbindung?
    Bsp.:

    1. Auslesen eines Startwertes
    2. Berechnen von 59.000 Fakultät + Startwert
    3. Ausgabe

    Du brauchst die Verbindung ja offenbar nach (1) nicht mehr, könntest sie also schließen und damit für ein anderes Skript freigeben.

    MfG
    Rouven

    --
    -------------------
    ss:) zu:) ls:& fo:) de:< va:{ ch:? sh:) n4:( rl:? br:$ js:| ie:) fl:(
  2. Hallo,

    als erstes solltest Du mal Zeitfresser suchen.
    Bei Datenbankzugriffen sind das i.d.R. schlecht formulierte Queries, die z.B. eine zu tiefe oder zu breite Ergebnismenge liefern.

    Dann auf jeden Fall nach Schleifen suchen in den Abfragen und diese durch intelligentere Queries ersetzen.

    Dann auch Zwischenergebnisse in Scripten wieder freigeben.
    Ein MySQL_free_result() an der passenden Stelle wirkt oft Wunder!
    Das ist ein Punkt, der ganz schnell ins Garaus führen kann.

    Dazu gehört auch, die Connection so spät wie möglich aufzunehmen und so schnell wie möglich wieder freizugeben.

    Und zum Schluss kann man noch mit Medizin arbeiten. MySQL kann wohl immer noch keine stored procedures und kein Query-Chaching. Das kannst Du aber vom Abfrage-Design her ggf. emulieren. Tabellen, die nicht so häufig geändert werden, müssen nicht unbedingt jedes Mal abgefragt werden, sondern könnten per shared Memory (mit Dirty-Flag = Semaphoren) zwischengepuffert werden. Allerdings sollte MySQL bei der passenden Wahl des Speichermodells auch schon größtenteils selber machen... Also abwägen!

    LG
    Chris

    1. n'abend,

      Und zum Schluss kann man noch mit Medizin arbeiten. MySQL kann wohl immer noch keine stored procedures und kein Query-Chaching.

      da muss ich intervenieren...
      query-caching ist durchaus ein feature von mysql!
      stored procedures stehen ab mysql5 zur verfügung.

      ADOdb ist übrigens ein sehr netter abstraction layer - mit query optimizer schon bevor die query abgesetzt wird. wenn du zugriff drauf hast, dann kannst du dir auch das php-modul installieren um den speed weiter zu erhöhen.

      ansonsten gilt:

      • wo keine db-afrage gemacht wird, braucht es keine verbindung. also nicht kategorisch eine verbindung zur db aufbauen, das tötet.

      • verbindung nur solang erhalten wie sie benötigt wird. wenn du eine verbindung also nicht bis zum script ende brauchst (weil du beispielsweise deine session in der DB speichern musst) kannst du sie nach der letzten query wieder beenden.

      • wenn du die rechte hast, erhöhe die anzahl simultaner connections (my.cnf)

      weiterhin schönen abend...

      --
      wer braucht schon großbuchstaben?
      sh:( fo:# ch:# rl:° br:> n4:& ie:{ mo:} va:) de:] zu:} fl:{ ss:? ls:[ js:|
    2. Hallo Chris,

      Dann auch Zwischenergebnisse in Scripten wieder freigeben.
      Ein MySQL_free_result() an der passenden Stelle wirkt oft Wunder!
      Das ist ein Punkt, der ganz schnell ins Garaus führen kann.

      Bin leider erst heute dazu gekommen, mich wieder damit zu beschaeftigen :-/
      MySQL_free_result war schon immer drin, wusste ich auch nicht mehr, war grad selbst ueberrascht, dass ich das damals bedacht habe... :-)

      Mal sehen, was die anderen Vorschlaege erbringen.

      Eddie

      --
      Old men and far travelers may lie with authority.
  3. Huhu Eddie,

    einige nützliche Tipps hast Du ja schon bekommen.

    Ein paar Detailinformationen wie Deine Seite erzeugt wird
    wären nicht schlecht.

    Was für eine Hostingumgebung/ Webpaket hast Du zur Verfügung?
    Was werkelt da im Hintergrund, etwas bekanntes oder selbstgestrickt?
    Und vielleicht kannst Du uns einen Einblick in die Struktur der Datenbank-Tabellen geben.

    Wenn Deine SQL-Queries über eine einzige Funktion oder Klasse
    abgewickelt werden kannst Du leicht die Zeitfresser aufspüren.
    Dazu einfach mal eine zeitlang jede Query mit Zeitbedarf in einer eigenen Tabelle protokollieren.
    Dann ggf. das Datenbankdesign (u.a. Spaltentyp, Index!) optimieren.

    Dann kannst Du noch serverseitige Cache-Mechanismen einsetzen.
    Je nachdem wie Deine Seite funktioniert sind das unter günstigen Umständen nur ein paar Zeilen die dafür sorgen, dass bei mehrfach angeforderten Seiten nicht jedesmal die Datenbank befragt wird.

    Folgendes fiel mir noch auf, auch wenn es nicht direkt mit der
    Datenbank zu tun hat:

    Diese HTML-Seite hier hat z.B. knapp 170 KB.
    http://www.umdiewelt.de/Australien-und-Ozeanien/Australien/Reiseziel-au.html

    Wenn Du dort die CSS-Klassen und die span-Tags (da ist noch weiteres überflüssiges Markup drin) rausnehmen würdest könntest Du leicht mindestens 30 KB sparen.
    Es ist besser mit Selektoren zu arbeiten.
    (In diesem Zusammenhang sind die Bücher von Dan Cederholm unbedingt empfehlenswert)

    Das freut dann auch Deine Besucher denn die Seiten laden schneller.
    Und der Server wird auch entlastet, die dynamischen Seiten können schneller ausgeliefert und die Datenbankverbindung dann u.U. auch eher geschlossen werden.

    Viele Grüße

    lulu

    --
    bythewaythewebsuxgoofflineandenjoytheday
    1. Hallo lulu,

      Was für eine Hostingumgebung/ Webpaket hast Du zur Verfügung?
      Was werkelt da im Hintergrund, etwas bekanntes oder selbstgestrickt?

      LAMP, und dann alles selbstgebastelt - zugegebenermassen ist es recht chaotisch gewachsen, auch schon ein paar Jahre her...

      Wenn Deine SQL-Queries über eine einzige Funktion oder Klasse
      abgewickelt werden kannst Du leicht die Zeitfresser aufspüren.
      Dazu einfach mal eine zeitlang jede Query mit Zeitbedarf in einer eigenen Tabelle protokollieren.

      Das habe ich jetzt mal gemacht, morgen guck ich mir an, was dabei rauskam. Aber einen konkreten Zeitfresser habe ich schon im Blick (s. anderer Thread: https://forum.selfhtml.org/?t=121483&m=780920).

      Dann kannst Du noch serverseitige Cache-Mechanismen einsetzen.
      Je nachdem wie Deine Seite funktioniert sind das unter günstigen Umständen nur ein paar Zeilen die dafür sorgen, dass bei mehrfach angeforderten Seiten nicht jedesmal die Datenbank befragt wird.

      Mmmh, prinzipiell muss ich doch nur den Code als HTML-Datei speichern und bei jeder Aktualisierung loeschen, oder?
      Das ist wirklich ueberfaellig, mal ueberlegen, wie ich das am geschicktesten mache.

      Folgendes fiel mir noch auf, auch wenn es nicht direkt mit der
      Datenbank zu tun hat:

      Diese HTML-Seite hier hat z.B. knapp 170 KB.
      http://www.umdiewelt.de/Australien-und-Ozeanien/Australien/Reiseziel-au.html

      Ja, fies gell? Da gehoert eigentlich ein mehrseitiges Design her, pro Seite 10 Reiseberichte.

      Wenn Du dort die CSS-Klassen und die span-Tags (da ist noch weiteres überflüssiges Markup drin) rausnehmen würdest könntest Du leicht mindestens 30 KB sparen.
      Es ist besser mit Selektoren zu arbeiten.

      Stimmt, tu ich bisher nicht. Ich werde mal die Tage in den Code reingucken - hat aber grad keine Prioritaet. Das jetztige Projekt ist in vielerlei Hinsicht so "ueberarbeitungswuerdig", dass ein komplettes Neudesign mehr Sinn macht.
      Das Datenbank-Problem ist aber sehr kritisch, das muss ich vor allem anderen in den Griff kriegen.

      Danke dir,
      naechtliche Gruesse,
      Eddie

      --
      Old men and far travelers may lie with authority.
      1. Hi Eddie,

        Dann kannst Du noch serverseitige Cache-Mechanismen einsetzen.

        Mmmh, prinzipiell muss ich doch nur den Code als HTML-Datei speichern und bei jeder Aktualisierung loeschen, oder?
        Das ist wirklich ueberfaellig, mal ueberlegen, wie ich das am geschicktesten mache.

        Angenommen Du hast eine dynamisch erzeugte Seite, dann kann man das z.B. ungefähr so lösen:

        1. Alle für den Request relvanten Parameter in einen String stecken.
        Im einfachsten Fall ist das nur die angeforderte URI.

        2. Von diesem String den md5-hash berechnen, das ist der Cache-Dateiname für diesen Request

        3. Gucken ob zu diesem Dateinamen bereits eine Datei existiert.

        4.a) Wenn ja, diese Datei direkt ausliefern (z.B. mit readfile() oder fpassthru())

        4.b) Wenn diese Datei nicht existiert dann neu erzeugen, im Cache-Verzeichnis speichern und ausliefern

        Das ist es im wesentlichen schon.

        Jetzt musst Du Dir noch Regeln überlegen nach denen der Cache aktualisiert/ bzw. als veraltet angesehen wird.

        Z.B.

        • modification time der Cache-Datei
        • modification time der Datenbank
        • wenn es ein POST-Request ist dann nie cachen
        • ggf. Datumsgrenze berücksichtigen (wenn man z.B. täglich wechselnde News hat)
        • bestimmte Seiten generell ausnehmen, z.B. Fehlermeldungen etc.

        Am besten auch einen last-modified header mitschicken, dann kann man ggf. einen Request direkt mit 304 beantworten.

        Viele Grüße

        lulu

        --
        bythewaythewebsuxgoofflineandenjoytheday
      2. Hallo Eddie,

        Das habe ich jetzt mal gemacht, morgen guck ich mir an, was dabei rauskam. Aber einen konkreten Zeitfresser habe ich schon im Blick (s. anderer Thread: https://forum.selfhtml.org/?t=121483&m=780920).

        Wie ich schon einmal vermutet habe, könnte es auch an der Speichereinstellung für das MySQL-DBMS liegen. Wenn Die nicht zur Größe und Form der Tabellen passt, muss das System swapen und das kostet dann.

        Der Erfolg durch Teilung deutet ebenfalls darauf hin.

        LG
        Chris