Ich habe eine Webanwendung (Tomcat / Hibernate / DBCP 1.4), die Abfragen gegen MySQL ausführt, und dies funktioniert gut für eine bestimmte Last, beispielsweise 50 Abfragen pro Sekunde. Wenn ich dieselbe moderate Last über HAProxy weitergebe (immer noch nur eine einzige Datenbank), wird ein Fehler angezeigt, möglicherweise einer pro 500 Abfragen. Meine App 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)
...
In der Zwischenzeit 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
Die "cD" zeigt anscheinend einen Status des Client-Timeouts an. Während meine Webanwendung sagt, dass HAProxy sich weigert, neue Verbindungen zu akzeptieren, sagt HAProxy, dass meine Webanwendung keine Daten zurück akzeptiert.
Ich beziehe meine HAProxy-Konfiguration nicht ein, da ich viele verschiedene Parameterwerte mit im Wesentlichen demselben Ergebnis ausprobiert habe. Insbesondere habe ich maxconn sowohl im globalen als auch im Serverbereich auf hohe und niedrige Werte gesetzt. In den Statistiken geschieht immer, dass die maximale Anzahl der Sitzungen auf nicht mehr als etwa 7 steigt. Meine JDBC-Poolgröße ist ebenfalls hoch.
Ist es im Allgemeinen in Ordnung, einen JDBC-Pool und einen HAProxy-Pool zusammen zu verwenden? Sind die Leute schon einmal auf solche Probleme gestoßen?
Ich habe eine Idee, wie dies gelöst werden kann, indem vor jeder Abfrage eine "Validierungsabfrage" gesendet wird. Aber da gibt es einen gewissen Overhead, und ich würde immer noch gerne wissen, warum meine Webanwendung erfolgreich ist, wenn sie direkt zu MySQL geht, aber beim Durchlaufen von HAProxy Verbindungen unterbrochen werden.
Wie kann ich weiter debuggen und mehr Informationen als nur "cD" erhalten? Ich habe versucht, HAProxy im Debug-Modus auszuführen, aber es scheint nichts mehr zu verraten.
UPDATE - Fri Jan 4 11:49:28 ICT 2013 (Antwort an JimB)
Die einzige Möglichkeit, mehr Informationen von Haproxy zu erhalten als Sie haben, besteht darin, den Befehl
show sess
odershow 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 eine Standardzeitüberschreitung von 10 Sekunden (und die Beispielkonfigurationen haben meiner Meinung nach 50 Sekunden). Ich bin mit JDBC nicht allzu vertraut, aber aus Tomcats Dokumenten geht hervor, dass es eine Einstellung gibt
minEvictableIdleTimeMillis
, die die Leerlaufverbindung aus dem Pool entfernt und standardmäßig 60 SekundentimeBetweenEvictionRunsMillis
beträgt. Sie kann bis zu 65 Sekunden betragen, da dies standardmäßig 5 Sekunden sind. Grundsätzlich müssen Sie sicherstellen, dass Ihr Haproxy-Timeout hoch genug ist, um diese inaktiven Verbindungen im Pool zu berücksichtigen.
Ich habe die timeout client
auf 75 Sekunden erhöht und jetzt scheint der obige Fehler weniger als zuvor aufzutreten:
2013-01-04 11:59:59 Debug: Kommunikationsverbindungsfehler
Das letzte erfolgreich vom Server empfangene Paket war vor 145.255 Millisekunden. Das letzte erfolgreich an den Server gesendete Paket war vor 10 Millisekunden.
Ich möchte auch Folgendes beachten: Abgesehen von den oben genannten gibt es einige Fehler wie diesen:
Kommunikationsverbindungsfehler Das letzte erfolgreich an den Server gesendete Paket war vor 0 Millisekunden. Der Treiber hat keine Pakete vom Server empfangen.
Auf der Serverseite sehe ich manchmal das sD
Flag beim Trennen:
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
Das ist timeout server
auch auf 75 Sekunden eingestellt.
Ein anderer Ansatz wäre , die Verbindungen zu verwenden
testWhileIdle
und aktivvalildationQuery
zu halten, da ein paar Verkehrspakete alle paar Sekunden wahrscheinlich auch das Problem lindern würden.
Ich würde dem Entwickler empfehlen, diese Optionen auszuprobieren, wenn es keinen anderen Weg gibt.
ethtool -S eth1 | grep drop
gibt Null zurück. Ich werde ein paar Pakete schnüffeln, um zu sehen, was passiert.