HAProxy, Client-Timeouts beim Verbinden vom JDBC-Pool

HAProxy, Client-Timeouts beim Verbinden vom JDBC-Pool

Ich habe eine Webanwendung (Tomcat/Hibernate/DBCP 1.4), die Abfragen gegen MySQL ausführt, und das funktioniert bei einer bestimmten Last, sagen wir 50 Abfragen pro Sekunde, gut. Wenn ich dieselbe moderate Last über HAProxy leite (immer noch nur mit einer einzigen Datenbank), erhalte ich einen Fehler, vielleicht einen pro 500 Abfragen. Meine Anwendung meldet:

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 196,898 milliseconds ago.    The last packet sent successfully to the server was 0 milliseconds ago.
at sun.reflect.GeneratedConstructorAccessor210.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1117)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3567)
...
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3017)
...

Mittlerweile zeigt das HAProxy-Protokoll viele Einträge wie:

27] mysql mysql/db03 0/0/34605 2364382 cD 3/3/3/3/0 0/0
Oct 15 15:43:12 localhost haproxy[3141]: 127.0.0.1:35500 [15/Oct/2012:15:42:50.0

Das „cD“ zeigt anscheinend einen Client-Timeout-Zustand an. Während meine Webanwendung also angibt, dass HAProxy die Annahme neuer Verbindungen verweigert, sagt HAProxy, dass meine Webanwendung keine Daten zurücknimmt.

Ich schließe meine HAProxy-Konfiguration nicht ein, da ich viele verschiedene Parameterwerte ausprobiert habe, mit im Wesentlichen demselben Ergebnis. Insbesondere habe ich maxconn sowohl im globalen als auch im Serverabschnitt auf hohe und niedrige Werte eingestellt, und was in den Statistiken immer passiert, ist, dass die maximale Anzahl an Sitzungen auf nicht mehr als etwa 7 steigt. Meine JDBC-Poolgröße ist auch hoch.

Ist es grundsätzlich in Ordnung, einen JDBC-Pool und einen HAProxy-Pool zusammen zu verwenden? Sind Leute schon einmal auf dieses Problem gestoßen?

Ich habe eine Idee, wie man das lösen kann. Sie besteht darin, vor jeder Abfrage eine „Validierungsabfrage“ zu senden. Das ist aber mit einem gewissen Aufwand verbunden und ich würde immer noch gerne wissen, warum meine Webanwendung erfolgreich ist, wenn sie direkt zu MySQL geht, aber Verbindungen abbricht, wenn sie über HAProxy geht.

Wie kann ich weiter debuggen und mehr Informationen als nur „cD“ erhalten? Ich habe versucht, HAProxy im Debugmodus auszuführen, aber es scheint nichts weiter zu enthüllen.


UPDATE – Freitag, 4. Januar 2013, 11:49:28 ICT (Antwort an JimB)

Die einzige Möglichkeit, mehr Informationen von haproxy zu erhalten, als Sie haben, besteht darin, den Befehl show sessoder show sess <id>regelmäßig zu verwenden, um den Status jeder TCP-Verbindung zu überwachen.

Hier einige Informationen zu den Sitzungen:

0x31f4310: proto=tcpv4 src=192.168.3.40:60401 fe=FE_mysql be=BE_mysql srv=mysql3 ts=08 age=1m2s calls=2 rq[f=909202h,l=0,an=00h,rx=13s,wx=,ax=] rp[f=109202h,l=0,an=00h,rx=13s,wx=,ax=] s0=[7,18h,fd=0,ex=] s1=[7,18h,fd=1,ex=] exp=13s

0x31fca50: proto=tcpv4 src=192.168.3.40:60423 fe=FE_mysql be=BE_mysql srv=mysql1 ts=08 age=2s calls=2 rq[f=909202h,l=0,an=00h,rx=1m13s,wx=,ax=] rp[f=109202h,l=0,an=00h,rx=1m13s,wx=,ax=] s0=[7,18h,fd=9,ex=] s1=[7,18h,fd=12,ex=] exp=1m13s

Haproxy hat ein Standard-Timeout von 10 Sekunden (und die Beispielkonfigurationen haben, glaube ich, 50 Sekunden). Ich bin mit JDBC nicht so vertraut, aber laut Tomcat-Dokumentation gibt es eine Einstellung minEvictableIdleTimeMillis, die inaktive Verbindungen aus dem Pool entfernt. Der Standardwert liegt bei 60 Sekunden, kann aber bis zu 65 Sekunden betragen, da der timeBetweenEvictionRunsMillisStandardwert 5 Sekunden beträgt. Grundsätzlich müssen Sie sicherstellen, dass Ihr Haproxy-Timeout hoch genug ist, um diese inaktiven Verbindungen im Pool zu berücksichtigen.

Ich habe es timeout clientauf 75 Sekunden erhöht und jetzt scheint der obige Fehler seltener aufzutreten als zuvor:

04.01.2013 11:59:59 Debug: Kommunikationsverbindungsfehler

Das letzte erfolgreich vom Server empfangene Paket liegt 145.255 Millisekunden zurück. Das letzte erfolgreich an den Server gesendete Paket liegt 10 Millisekunden zurück.

Ich möchte außerdem Folgendes anmerken: Außer den oben genannten gibt es noch einige Fehler wie diesen:

Kommunikationsverbindungsfehler Das letzte erfolgreich an den Server gesendete Paket liegt 0 Millisekunden zurück. Der Treiber hat keine Pakete vom Server empfangen.

Auf der Serverseite sehe ich manchmal sDbei der Trennung die Flagge:

haproxy[15770]: 192.168.3.40:56944 [04/Jan/2013:11:06:55.895] FE_mysql BE_mysql/mysql1 0/0/77153 1954480 sD 1/1/1/1/0 0/0

Die timeout serverEinstellung ist ebenfalls auf 75 Sekunden festgelegt.

Ein anderer Ansatz wäre, die Verbindungen zu nutzen testWhileIdleund valildationQueryaktiv zu halten, da ein paar Verkehrspakete alle paar Sekunden das Problem wahrscheinlich ebenfalls lindern würden.

Ich würde dem Entwickler vorschlagen, diese Optionen auszuprobieren, wenn es keine andere Möglichkeit gibt.

Antwort1

Die einzige Möglichkeit, mehr Informationen von haproxy zu erhalten als Sie haben, besteht darin, regelmäßig den Befehl show sess„oder“ zu verwenden show sess <id>, um den Status jeder TCP-Verbindung zu überwachen. Ich bin jedoch nicht sicher, ob Sie dadurch weitere nützliche Informationen erhalten würden.

Der cDBeendigungsstatus ist die hilfreichste Information, die Sie haben. Er bedeutet genau, dass eine hergestellte Verbindung mit dem Client abgelaufen ist. Dies wird in haproxy über den timeout clientParameter in der Konfiguration gesteuert, global festgelegt oder in einem Frontent- oder Listenabschnitt.

Sie sagten, dass Sie keine über 7 gleichzeitigen Verbindungen feststellen und dieser Protokolleintrag zeigt, dass der Fehler auftrat, als nur 3 Verbindungen bestanden. Ich bezweifle also, dass Sie ein Problem mit der Verbindungsbegrenzung haben (selbst außerhalb der Kontrolle von haproxy).

Es sieht also so aus, als ob der Pool gelegentlich eine neue Verbindung hinzufügt, die einige Abfragen verarbeitet und dann im Leerlauf bleibt. Wenn diese Verbindung länger im Leerlauf bleibt als die timeout clientEinstellung in Haproxy, beendet Haproxy die Verbindung selbst. Wenn diese Verbindung das nächste Mal aus dem Pool verwendet wird, erhalten Sie den obigen Fehler.

Haproxy hat ein Standard-Timeout von 10 Sekunden (und die Beispielkonfigurationen haben, glaube ich, 50 Sekunden). Ich bin mit JDBC nicht so vertraut, aber laut Tomcat-Dokumentation gibt es eine Einstellung minEvictableIdleTimeMillis, die inaktive Verbindungen aus dem Pool entfernt. Der Standardwert liegt bei 60 Sekunden, kann aber bis zu 65 Sekunden betragen, da der timeBetweenEvictionRunsMillisStandardwert 5 Sekunden beträgt. Grundsätzlich müssen Sie sicherstellen, dass Ihr Haproxy-Timeout hoch genug ist, um diese inaktiven Verbindungen im Pool zu berücksichtigen.

Ein anderer Ansatz wäre, die Verbindungen zu nutzen testWhileIdleund valildationQueryaktiv zu halten, da ein paar Verkehrspakete alle paar Sekunden das Problem wahrscheinlich ebenfalls lindern würden.

[Bearbeiten] Als Antwort auf die zusätzlichen Informationen von @quanta:

Auch wenn das Haproxy-Timeout jetzt 75 Sekunden beträgt, kommt es definitiv immer noch zu Sitzungstimeouts. Es kann sein, dass es in der Gesamtlebensdauer einer JDBC-Verbindung noch weitere Spielräume gibt, die mir nicht bekannt sind. Da für diese Art von Dienst nur sehr wenige Verbindungen erforderlich sind, ist es auch nicht verkehrt, die Timeouts auf einen extrem hohen Wert zu erhöhen, etwa eine Stunde oder mehr. Wenn der JDBC-Pool wirklich Probleme hat, alte Verbindungen freizugeben, würde dies das Problem nur verschleiern, aber es könnte auch eine einfache Lösung sein.

verwandte Informationen