HAProxy, Client-Timeouts beim Herstellen einer Verbindung aus dem JDBC-Pool


7

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 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 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 Sekunden timeBetweenEvictionRunsMillisbeträ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 clientauf 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 sDFlag 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 serverauch auf 75 Sekunden eingestellt.

Ein anderer Ansatz wäre , die Verbindungen zu verwenden testWhileIdleund aktiv valildationQueryzu 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.


Auf einer profaneren Ebene kann es sich lohnen, ethtool -S eth0 (oder was auch immer) auszuführen, um zu überprüfen, ob keine Pakete verworfen werden.
Ramruma

Keine verworfenen Pakete. ethtool -S eth1 | grep dropgibt Null zurück. Ich werde ein paar Pakete schnüffeln, um zu sehen, was passiert.
Quanten

Antworten:


6

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. Ich bin mir jedoch nicht sicher, ob Sie weitere nützliche Informationen erhalten würden.

Der cDBeendigungsstatus ist die hilfreichste Information, die Sie haben. Was es genau bedeutet, ist, 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 Listen-Bereich.

Sie sagten, dass Sie nicht sehen, dass gleichzeitige Verbindungen über 7 gehen, und dieser Protokolleintrag zeigt, dass der Fehler aufgetreten ist, wenn nur 3 Verbindungen vorhanden waren. Ich bezweifle, dass Sie ein Problem mit dem Verbindungslimit haben (auch außerhalb der Kontrolle von haproxy).

Es sieht also so aus, als würde der Pool gelegentlich eine neue Verbindung hinzufügen, die einige Abfragen verarbeitet und dann inaktiv ist. Wenn diese Verbindung länger timeout clientinaktiv ist als die Einstellung in Haproxy, beendet Haproxy die Verbindung selbst. Wenn diese Verbindung das nächste Mal aus dem Pool verwendet wird, wird der obige Fehler angezeigt.

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 Sekunden timeBetweenEvictionRunsMillisbeträ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.

Ein anderer Ansatz wäre , die Verbindungen zu verwenden testWhileIdleund aktiv valildationQueryzu halten, da ein paar Verkehrspakete alle paar Sekunden wahrscheinlich auch das Problem lindern würden.

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

Obwohl das Haproxy-Zeitlimit jetzt 75 Sekunden beträgt, erhalten Sie definitiv immer noch Sitzungszeitlimits. Während der gesamten Lebensdauer einer JDBC-Verbindung kann es zu einem zusätzlichen Spiel kommen, das mir nicht bekannt ist. Da für diese Art von Service nur sehr wenige Verbindungen erforderlich sind, ist es auch nichts Falsches, die Zeitüberschreitungen auf einen extrem hohen Wert in der Größenordnung von einer Stunde oder mehr zu erhöhen. Wenn der JDBC-Pool wirklich Probleme beim Freigeben alter Verbindungen hat, würde dies nur das Problem maskieren, aber es könnte auch eine einfache Lösung sein.


+1. Habe meine Antwort auf die ursprüngliche Frage angehängt.
Quanten
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.