2013-07-12 10 views
1

Je rencontre un comportement étrange. J'ai un programme Java qui écrit en permanence des données dans une table MySQL en utilisant des instructions préparées et des insertions par lots. Si un autre processus émet un LOCK TABLES t WRITE sur la même table et le libère peu après (après quelques minutes), le programme Java continue comme prévu. Cependant, lorsque le verrouillage dure plus longtemps (plus de 30 minutes), le programme Java perd la connexion et ne continue pas. Après 2 heures, il échoue avec un échec de liaison de communication. L'instruction d'insertion en attente pendant le verrouillage de la table est exécutée après la libération du verrou, mais la connexion a été supprimée par la suite.Échec de la liaison de communication vers MySQL pendant les longs LOCK TABLES

Voici les détails:

  • il arrive sur les deux 5.0.51a MySQL et 5.1.66
  • J'utilise le plus récent pilote JDBC mysql-connector-5.1.25-bin.jar
  • le wait_timeout est réglé à 28800 (8 heures)
  • la trace de pile de la défaillance de la liaison de communication et le programme Java sont donnés ci-

Est-ce que quelqu'un sait ce qui se passe ici? Y a-t-il des délais d'attente que je dois définir/augmenter?


L'exception levée au bout de deux heures:

Exception in thread "main" java.sql.BatchUpdateException: Communications link failure 

The last packet successfully received from the server was 7.260.436 milliseconds ago. The last packet sent successfully to the server was 7.210.431 milliseconds ago. 
    at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1836) 
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1456) 
    at com.mysql.jdbc.CallableStatement.executeBatch(CallableStatement.java:2499) 
    at main.LockTest.main(LockTest.java:26) 
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure 

The last packet successfully received from the server was 7.260.436 milliseconds ago. The last packet sent successfully to the server was 7.210.431 milliseconds ago. 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
    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:1121) 
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3670) 
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3559) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4110) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359) 
    at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1792) 
    ... 3 more 
Caused by: java.net.SocketTimeoutException: Read timed out 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:129) 
    at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114) 
    at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161) 
    at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189) 
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3116) 
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3570) 
    ... 13 more 

Le programme complet de Java:

package main; 

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.PreparedStatement; 
import java.sql.SQLException; 
import java.util.Date; 

public class LockTest { 

    private static final String CONNECTION_PATTERN = "jdbc:mysql://%s/?user=%s&password=%s" 
      + "&autoReconnect=true&rewriteBatchedStatements=true&characterEncoding=utf8"; 
    private static final String QUERY = "INSERT INTO test.lock_test (random_text) VALUES (?)"; 

    public static void main(String[] args) throws SQLException, InterruptedException { 
     Connection con = DriverManager.getConnection(String.format(CONNECTION_PATTERN, "host", "user", "pw")); 
     PreparedStatement ps = con.prepareCall(QUERY); 
     int i = 0; 
     while (true) { 
      i++; 
      ps.setString(1, Long.toString(System.currentTimeMillis())); 
      ps.addBatch(); 
      if (i % 10 == 0) { 
       ps.executeBatch(); 
       System.out.println(new Date() + ": inserting 10 rows"); 
      } 
      Thread.sleep(5000); 
     } 
    } 
} 

Répondre

3

Enfin, j'ai découvert la vraie raison. Le wait_timeout de MySQL n'a rien à voir avec le problème - tant qu'une instruction est en cours d'exécution (peu importe pour combien de temps), la session de base de données n'est pas dans l'état SLEEP et donc la session ne sera jamais fermée par MySQL.

La raison semble être le système d'exploitation Linux (Debian 6 ou 7), qui ferme la connexion tcp après 2 heures d'inactivité (le mécanisme concret m'est inconnu, peut-être quelqu'un peut-il expliquer cela?).

Pour éviter les délais d'attente décrits, il faut envoyer plus fréquemment des paquets tcp keep alive. Pour ce faire, il faut diminuer /proc/sys/net/ipv4/tcp_keepalive_time (je l'ai diminué de 7200 à 60). cat 60 > /proc/sys/net/ipv4/tcp_keepalive_time le fait temporairement; pour le conserver après un redémarrage du système, il faut définir net.ipv4.tcp_keepalive_time=60 dans /etc/sysctl.conf.

+0

Je ne peux pas modifier le contenu de mon fichier keep_current 'tcp_keepalive_time "E667: Fsynch a échoué' en utilisant' vi' Je devais le faire comme ceci: 'root @ sd-53310:/home/ocatelin # echo 60 | sudo dd de =/proc/sys/net/ipv4/tcp_keepalive_time 0 + 1 enregistrements lus 0 + 1 enregistrements écrits 3 octets (3 B) copiés, 2,4948e-05 s, 120 kB/s root @ sd -53310:/home/ocatelin # cat/proc/sys/net/ipv4/tcp_keepalive_time 60' – Stephane

0

Je cherche simplement la même question. Je pense que ma réponse peut vous aider.

  1. afficher votre exception

Le dernier paquet reçu avec succès depuis le serveur était il y a 7.260.436 millisecondes.

C'est apparemment signifie que 7.260.436 millisecondes < wait_timeout est réglé sur 28800

2. Si votre application génère une exception parce que le wait_timeout est trop petit.Le spectacle d'exception comme ceci:

 
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 46,208,149 milliseconds ago. The last packet sent successfully to the server was 46,208,150 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem. 
; SQL []; The last packet successfully received from the server was 46,208,149 milliseconds ago. 
The last packet sent successfully to the server was 46,208,150 milliseconds ago. 
is longer than the server configured value of 'wait_timeout'. 
You should consider either expiring and/or testing connection validity before use in your application, 
increasing the server configured values for client timeouts, 
or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.; 

cela signifie que il y a 46,208,150 millisecondes> wait_timeout

  1. réponse !!!

Soyez attention sur le mot clé suivante "de défaillance de la liaison de communication", cela est principalement sur les variables Mysql:. ​​net_write_timeout ou net_read_timeout

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

la valeur par défaut de net_write_timeout et net_read_timeout est petit, vous peut exécuter

 mysql> show variables like '%timeout%';
pour trouver le résultat.

Questions connexes