web-dev-qa-db-fra.com

qu'est-ce que Java.io.EOFException, Message: Impossible de lire la réponse du serveur. Prévu pour lire 4 octets, lire 0 octet

Cette question a été posée plusieurs fois dans SO et plusieurs fois dans d'autres sites. Mais je n'ai pas obtenu de réponse satisfaisante.

Mon problème:
J'ai une Java application web qui utilise simple JDBC pour se connecter à mysql base de données via Glassfish serveur d'applications.

J'ai utilisé le pool de connexions dans le serveur glassfish avec les configurations suivantes:
Taille initiale du pool: 25
Taille maximale de la piscine: 100
Pool Resize Quantity: 2
Délai d'inactivité: 300 secondes
Temps d'attente maximum: 60 000 millisecondes

L'application a été déployée au cours des 3 derniers mois et fonctionnait également parfaitement.
Mais depuis les 2 derniers jours, l'erreur suivante se produit au moment de la connexion.

Partial StackTrace

com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed due to underlying exception/error:  

** BEGIN NESTED EXCEPTION **  

com.mysql.jdbc.CommunicationsException  
MESSAGE: Communications link failure due to underlying exception:  

** BEGIN NESTED EXCEPTION **  

Java.io.EOFException  
MESSAGE: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.  

STACKTRACE:  

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:1997)  
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.Java:2411)  
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.Java:2916)  
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.Java:1631)  
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.Java:1723)  
at com.mysql.jdbc.Connection.execSQL(Connection.Java:3256)  
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.Java:1313)  
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.Java:1448)  
............  
............  
my application traces....  

Qu'est-ce qui a causé cette erreur soudainement? J'ai perdu beaucoup de temps pour cela.

EDIT: Le problème persiste même après le redémarrage du serveur. Selon DBA, deux des configurations de serveur mysql importantes sont:
wait_timeout: 1800 secondes
connect_timeout: 10 secondes
REMARQUE: Les autres applications déployées sur le même serveur se connectant à la même base de données et utilisant des pools différents fonctionnent sans problème.

EDIT-2: Après avoir lu beaucoup de choses et m'attendre à des résultats positifs, j'ai apporté ces modifications à mon pool de connexions.

Temps d'attente max: 0 (auparavant c'était 60 secondes)
Validation de la connexion: Obligatoire
Méthode de validation: table
Nom du tableau: Démo
Valider au moins une fois: 40 secondes
Tentatives de nouvelle tentative de création: 1
Intervalles de nouvelle tentative: 5 secondes
tilisation maximale de la connexion: 5

Et cela a fonctionné car l'application est exécutée pendant 3 jours de manière cohérente. Mais j'ai obtenu un résultat très étrange et intéressant de cela. Lors de la surveillance du pool de connexions, j'ai trouvé ces chiffres:

NumConnAcquired: 44919 compte
NumConnReleased: 44919 Count
NumConnCreated: 9748 Count
NumConnDestroyed: 9793 Count
NumConnFailedValidation: 70 comptes
NumConnFree: 161 Count
NumConnUsed: -136 Count

Comment le NumConnFree peut-il devenir 161 comme je l'ai Maximum Pool Size = 100?
Comment le NumConnUsed peut-il devenir -136, un nombre négatif ?
Comment le NumConnDestroyed>NumConnCreated?

42
mukund

La connexion a échoué, peut-être en raison d'un délai d'inactivité du pare-feu, etc. Si votre pilote JDBC n'est pas configuré pour se reconnecter en cas d'échec, cette erreur ne disparaîtra que si vous ouvrez une nouvelle connexion.

Si vous utilisez un pool de connexions à la base de données (vous utilisez un pool, n'est-ce pas?), Vous souhaiterez probablement activer ses fonctionnalités de vérification de connexion comme l'émission d'un requête pour vérifier si la connexion fonctionne avant de la remettre à l'application. Dans Apache commons-dbcp, cela s'appelle validationQuery et est souvent défini sur quelque chose de simple comme SELECT 1.

Étant donné que vous utilisez MySQL, vous devez utiliser une requête "ping" spécifique à Connector/J qui est plus légère que l'envoi réel d'une véritable requête SQL et définir votre requête de validation sur /* ping */ SELECT 1 (la partie ping doit être exacte ).

9
Christopher Schultz

Cela signifie très probablement que la base de données a redémarré ou que la connexion réseau à la base de données a été rompue (par exemple, une connexion NAT a expiré) ... et votre application Web essaie d'utiliser une base de données périmée). connexion.

Si le problème persiste après le redémarrage du conteneur Web, cela pourrait être quelque chose de plus grave.


Vous avez demandé ce qui suit:

How can the NumConnFree become 161 as I have Maximum Pool Size = 100 ?
How can the NumConnUsed become -136, a negative number ?
How can the NumConnDestroyed > NumConnCreated ? 

À première vue, cela n'a pas de sens. Cependant, ils peuvent simplement être le résultat de la mise à jour de certains compteurs d'utilisation de manière non thread-safe. Ce n'est pas nécessairement lié à votre problème d'origine.

8
Stephen C

Il s'agit de EndOfFileException en Java, qui se produit lorsque le point de départ de votre curseur se trouve sur le point de fin ou lorsque la connexion à la base de données est fermée en raison d'une exception inattendue.

6
Puneet

Bien que je n'aie pas de solutions définitives, il semble que quelque chose interfère avec la communication entre le serveur d'applications et la base de données. Voici quelques éléments que vous pouvez essayer d'isoler les problèmes:

  • Essayez de déterminer si c'est un problème mysql ou Java problème de code. Essayez de vous connecter à mysql en utilisant l'outil de ligne de commande du même hôte que le serveur d'application et émettez un code SQL similaire pour effectuer la connexion. Testez à l'aide d'un simple Java code qui fait une sélection, déployez-le sur la même infrastructure, voyez ce qui se passe, etc. Vérifiez également le journal du serveur mysql, voyez si vous pouvez trouver quelque chose d'utile

  • Il existe deux façons de fermer une connexion inactive: par le code du pool de connexions qui s'exécute à l'intérieur du serveur d'application, ou par mysql lui-même. Assurez-vous de vérifier la configuration des deux côtés

  • Vérifiez si une configuration d'infrastructure réseau a changé récemment. Y a-t-il eu une nouvelle règle de pare-feu interférant avec la connectivité du serveur d'applications <--> mysql? Y avait-il des paramètres qui interdisent l'ouverture de la connexion TCP au ralenti plus longtemps que X?

  • Essayez une autre bibliothèque de regroupement de connexions juste pour éliminer la possibilité que ce soit le regroupement de connexions

Bonne chance

5
gerrytan

Il peut s'agir d'un problème lié au pare-feu.

2
Mani

J'ai eu ce problème mais je ne pouvais pas faire de changements dans la configuration de la base de données MySQL. Par conséquent, je me suis assuré que dans ma classe de connecteur SQL, la connexion est toujours fermée avant d'être à nouveau lancée. Quelque chose comme:

public static Connection getConnection() {

    if (DatabaseConnnector.conn == null) {
        initConn();
    } else {
        try {
            DatabaseConnnector.conn.close();          
        } catch (SQLException e) {
            e.printStackTrace();
        }
          initConn();
    }
    return DatabaseConnnector.conn;
}

Et cela a résolu le problème.

1
macieks