PHP-FPM mit mysqlnd bei connect hängenbleiben und kein timeout out (gdb backtrace drinnen)

8

Ich führe PHP-FPM aus und habe ein Problem während Zeiten extrem hoher Last, die dazu führen, dass PHP-Prozesse für immer hängen bleiben. Ich habe ein GDB-Backtrace eines laufenden Prozesses, der festgefahren war, und habe dies (irrelevante Frames entfernt):

%Vor%

Was ich also sehen kann, ist, dass ich versuche, mich mit MySQL zu verbinden, und dann stürzt PHP ab und fragt den Socket ab. Es ist möglich, dass MySQL die Verbindung abbrach oder ablehnte (die Datenbank war zu 100% CPU-Last).

Allerdings habe ich mysql.connect_timeout auf 60 gesetzt, also würde ich erwarten, dass die Verbindung nicht so lange dauert (es war über 20 Minuten). default_socket_timeout wird ebenfalls auf 300 Sekunden gesetzt.

Und ich werde alle Vorschläge für ein Upgrade auf mysqli vorwegnehmen, indem ich sage, dass ich das versucht habe (wir verwenden eine DBAL), und hatte dasselbe Problem wie mysqli die gleichen Verbindungsfunktionen unter der Haube verwendet / p>

Ich verwende PHP 5.5.19 unter Ubuntu und benutze den mysqlnd-Treiber.

Irgendeine Idee, was dazu führen könnte, dass PHP keine Zeitüberschreitung hat?

    
Brandon Wamboldt 09.12.2014, 16:19
quelle

3 Antworten

5

Ich denke, Sie treffen auf das, was ich die "Dead Usability Band" nenne. Was das bedeutet ist, dass du zwischen deiner Aktion, die komplett fehlschlägt (wo sie eine Auszeit nehmen würde), stecken und trotzdem nicht funktionieren wirst. Also ist die Kette der Dinge das

  1. Sie rufen Ihr PHP-Skript
  2. auf
  3. PHP versucht eine Verbindung zu MySQL herzustellen
  4. MySQL (bei 100% Auslastung) reagiert nur langsam, öffnet jedoch die Verbindung innerhalb des zugewiesenen Timeouts
  5. PHP sendet das SQL
  6. MySQL (immer noch bei 100% Auslastung) ist jetzt wahrscheinlich festgefahren. Die Abfrage wird schließlich ausgeführt, aber jetzt haben Sie das Problem, eine Antwort tatsächlich zurückzugeben. Also bekommt PHP ... etwas. Sag ein Rinnsal. MySQL wird keine Zeit verstreichen lassen (es hat eine gültige Anfrage, auf die es antwortet) und PHP wird es auch nicht (es werden Daten mit einer schmerzhaft langsamen Rate geliefert). So bleiben beide Programme in dieser "toten Zone" stecken, in der gerade genug passiert, um eine Zeitüberschreitung zu vermeiden, aber nicht genug, um den Deadlock zu beheben. Sie können dies manchmal in Aktion sehen, indem Sie SHOW PROCESSLIST; ausführen.

Ich verstehe, dass Sie nicht SQL senden, aber ich denke, dass die gleichen Prinzipien ins Spiel kommen. Manchmal können Sie sehen, dass dies in einer entfernten Datenbank mit MySQL Workbench passiert (wo eine Abfrage ausgeführt wird, aber keine Ergebnisse liefert). So wartet Workbench auf eine Antwort, die praktisch nie passieren wird.

Also, wie das zu beheben? In der Praxis kann man nicht auf der Programmier-Ebene von PHP. Die PHP-API stellt nicht genügend der zugrunde liegenden Aufrufe bereit, damit Sie erkennen können, dass Sie in einem toten Band stecken geblieben sind, und die Verbindung beenden. Und das Schreiben eines Skripts, das nach toten Bändern sucht, läuft immer Gefahr, ansonsten gute Prozesse zu beenden. Ihre beste Wette (so sehr ich es hasse es zu sagen) ist es, MySQL zu stärken und sicherzustellen, dass es genug Ressourcen hat, um nicht 100% zu erreichen. Wenn Sie einen Server mit PHP / Apache teilen, ist das ein Rezept für solche Dinge. Ich habe bemerkt, dass dies selten auf unserem größeren und besseren System geschieht, da wir MySQL in eine eigene Instanz verschoben haben. Überprüfen Sie auch mysqltuner . Es kann sich Ihre MySQL-Instanz ansehen und Konfigurationseinstellungen vorschlagen, um die Leistung zu verbessern.

    
Machavity 13.12.2014, 01:17
quelle
2

Ein paar Dinge zu überprüfen:

  • Netzwerksättigung. Vielleicht fallengelassene Frames.
  • Serverseitige Fehlerprotokolle.
  • Sie können mit netstat überprüfen, welchen Port Ihr php geöffnet hat, und Sie können den remote Port auf der mysql Serverseite bekommen, wo Sie vielleicht den gegebenen mysql thread finden und möglicherweise mysql debugging tools verwenden, vielleicht können Sie seine Statusinformationen. Netstat kann dir helfen, den Status der Verbindung zu überprüfen. Wenn es auf beiden Seiten eingerichtet ist, ist das Problem auf Anwendungsebene, wenn die Verbindung in Handshake oder Breakdown oder etwas Ähnliches ist, dann ist auch ein Netzwerkproblem wahrscheinlich.
  • Wenn Sie dieses Verhalten leicht reproduzieren können, ist es einen Versuch wert, den gegebenen Prozess zu überprüfen. Die Timeout-Einstellungen werden normalerweise mit alarm () oder ähnlichem implementiert.
  • Vielleicht wäre es nützlich, uns deinen PHP-Code zu zeigen, wo du dich verbindest. (Oder ein minimales Beispiel, das das Problem reproduzieren kann.)
Lajos Veres 17.12.2014 23:18
quelle
0

Ich habe auch ähnliche back strace-Informationen in meinen php-fpm-Programmen gefunden Es sollte durch die folgenden Fehlerbehebungen behoben worden sein: Ссылка , Ссылка

Die Ursache war auf einen Fehler in den PHP-Tools zurückzuführen: php_openssl_sockop_read.

php-fpm hat den 'feof'-Zustand einer solchen Verbindung nicht erkannt, und der' poll'-syscall benutzte immer noch eine solche fd (sie wurde von mysql server geschlossen), schließlich klemmte die Clientseite (php-fpm) fest (bei der Umfrage) für immer.

Sie sollten die neueste Version von PHP verwenden oder PHP mit solchen Bugfixes neu aufbauen (bugs.php.net/bug.php?id=41631, ich denke es reicht)

    
Harper Wang 04.11.2015 10:21
quelle

Tags und Links