Ich kann in der Dokumentation kein Zitat finden, aber meine Erfahrung legt nahe, dass die Netzwerkinfrastruktur von EC2 im Allgemeinen (was RDS und wahrscheinlich jeden anderen AWS-Service umfassen würde, der auf virtuellen Maschinen läuft, die pro Kunde bereitgestellt werden, wenn nicht alle AWS, und scheint sicherlich nicht streng auf "EC2-Instanzen" beschränkt zu sein) implementiert eine zustandsbehaftete Paketprüfung und "vergisst", dass eine TCP-Verbindung nach einigen Minuten absoluter Untätigkeit gültig ist ... was das von Ihnen beschriebene Verhalten verursacht.
Die Maschinen an beiden Enden der Verbindung können davon überzeugt sein, dass die Verbindung noch besteht, aber das Netzwerk lässt den Datenverkehr zwischen ihnen nicht zu, da TCP-Sitzungen in einer SPI-Umgebung nicht erkannt werden, sie werden erstellt und können nur erstellt werden, wenn das Netzwerk die Verbindung ganz am Anfang sieht (SYN, SYN/ACK, ACK ). Ich bin ursprünglich auf dieses Problem mit MySQL-Servern in EC2 (nicht RDS) gestoßen, wäre aber sehr überrascht, wenn die zugrunde liegende Ursache nicht dieselbe ist.
Es gibt zwei mögliche Ansätze, um dies zu umgehen.
Wenn Ihre PHP-Maschine Linux ist, konfigurieren Sie den Kernel so, dass er die Verbindungen auf Schicht 4 am Leben erhält. Diese Änderung ist für Sie in dem Sinne unsichtbar, dass diese Keepalives den Wert in Time
nicht ändern Spalte in SHOW PROCESSLIST
für Verbindungen im Sleep
weil es die Zeit, die die Verbindung auf Schicht 7 im Leerlauf war, nicht zurücksetzt ... aber es sollte die Zeitüberschreitungen der AWS-Infrastruktur vermeiden, wenn die Bibliotheken, die die MySQL-Verbindungen verwalten, die Socket-Optionen richtig einstellen, um sie zu nutzen.
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive .html erklärt, wie man dies live einrichtet und wie man es über Neustarts hinweg dauerhaft macht.
Andernfalls besteht die andere Möglichkeit darin, MySQL dazu zu zwingen, die Verbindung früher als das Netzwerk-Timeout zu schließen damit die PHP-Maschine sofort erkennt, dass sie versucht, über einen geschlossenen Socket zu sprechen. Es mag kontraintuitiv klingen, ein Timeout zu verkürzen, anstatt es zu verlängern, aber das Verkürzen des Timeouts sollte dazu führen, dass Ihr Ping-Test sehr schnell fehlschlägt, wenn eine Sitzung zu lange im Leerlauf war, was auch (im Wesentlichen) das Problem "löst", vorausgesetzt, Sie sind gesund in der PHP-Clientbibliothek. Sobald Ihre Anwendung stärker ausgelastet ist, werden die Verbindungen vermutlich selten lange genug inaktiv sein, um das Zeitlimit zu erreichen.
MySQL Server hat zwei verschiedene Leerlauf-Timeout-Einstellungen: wait_timeout
(für nicht interaktive Sitzungen, d. h. Verbindungen aus Code wie PHP) und interactive_timeout
(von Abfragebrowsern und dem Befehlszeilenclient), aber der Server kennt den Unterschied nur, weil die Clientbibliothek dem Server mitteilen muss, welche Art von Verbindung sie herstellt. Angenommen, Ihre Client-Bibliothek verwendet das richtige Setup, dann wait_timeout
ist der, den Sie suchen. Wenn Sie dies auf einen Wert unter 900 setzen, sollte das Problem behoben werden, wenn das Ändern der TCP-Keepalive-Einstellungen im Linux-Kernel dies nicht tut. Beachten Sie jedoch, dass nach der Änderung nur zukünftige Verbindungen betroffen sind – Verbindungen, die bereits hergestellt wurden, als die Änderung vorgenommen wurde, werden weiterhin mit dem aktuellen Wert ausgeführt, der standardmäßig 8 Stunden (28800 Sekunden) beträgt. Diese sind in der RDS-Parametergruppe für Ihre Instanz konfigurierbar.
Es gibt Hinweise auf ähnliches Verhalten in den AWS-Dokumenten hier , zusammen mit den Windows-Registrierungseinstellungen, die angepasst werden müssen, um TCP-Keepalives zu ändern, wenn Sie den PHP-Server unter Windows und nicht unter Linux ausführen, wie ich oben angenommen habe ... obwohl sich der Artikel speziell auf Redshift und externe Verbindungen bezieht EC2 scheint das zugrunde liegende Problem wie oben beschrieben immer noch zu bestätigen.