Сбой канала связи с MySQL во время длинных LOCK TABLES

Я сталкиваюсь с каким-то странным поведением. У меня есть программа Java, которая постоянно записывает данные в таблицу MySQL, используя подготовленные операторы и пакетные вставки. Если какой-либо другой процесс выдает LOCK TABLES t WRITE в той же таблице и вскоре после этого освобождает ее (через несколько минут), программа Java продолжает работу, как и ожидалось. Однако, когда блокировка сохраняется в течение более длительного периода времени (более 30 минут), программа Java теряет соединение и не продолжает работу. Через 2 часа происходит сбой с сбоем канала связи. Оператор вставки, отложенный во время блокировки таблицы, выполняется после снятия блокировки, но после этого соединение разрывается.

Вот подробности:

  • это происходит как в MySQL 5.0.51a, так и в 5.1.66.
  • Я использую самый последний драйвер JDBC mysql-connector-5.1.25-bin.jar.
  • wait_timeout установлено на 28800 (8 часов)
  • трассировка стека отказа канала связи и программа Java приведены ниже

Кто-нибудь знает, что здесь происходит? Есть ли тайм-ауты, которые мне нужно установить/увеличить?


Исключение, возникшее через два часа:

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

Полная программа 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);
        }
    }
}

person twonkeys    schedule 12.07.2013    source источник


Ответы (2)


Наконец-то я узнал об истинной причине. wait_timeout MySQL не имеет ничего общего с проблемой - пока выполняется оператор (независимо от того, как долго), сеанс базы данных не находится в состоянии SLEEP, и, следовательно, сеанс никогда не будет закрыт MySQL.

Причина, похоже, в операционной системе Linux (Debian 6 или 7), которая закрывает tcp-соединение после простоя в течение 2 часов (конкретный механизм мне неизвестен, может быть, кто-то может уточнить это?).

Чтобы избежать описанных таймаутов, нужно чаще отправлять пакеты tcp keep Alive. Для этого нужно уменьшить /proc/sys/net/ipv4/tcp_keepalive_time (я уменьшил с 7200 до 60). cat 60 > /proc/sys/net/ipv4/tcp_keepalive_time делает это временно; чтобы сохранить его после перезагрузки системы, нужно установить net.ipv4.tcp_keepalive_time=60 в /etc/sysctl.conf.

person twonkeys    schedule 13.07.2014
comment
Я не могу изменить содержимое моего файла поддержки активности tcp_keepalive_time" E667: Fsynch has failed с помощью vi. Пришлось сделать так: root@sd-53310:/home/ocatelin# echo 60 | sudo dd of=/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 - person Stephane; 25.03.2017

Я просто ищу тот же вопрос. Думаю, мой ответ может вам помочь.

  1. просмотреть свое исключение

Последний пакет, успешно полученный от сервера, был 7.260.436 миллисекунд назад.

Очевидно, это означает, что 7.260.436 миллисекунд ‹ для параметра wait_timeout установлено значение 28800.

2. Если ваше приложение выдает исключение, потому что время ожидания слишком мало. Исключение отображается следующим образом:

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.;

это означает 46 208 150 миллисекунд назад> wait_timeout

  1. Отвечать !!!

Обратите внимание на следующее ключевое слово «Сбой канала связи», в основном это относится к переменным MySQl: net_write_timeout или net_read_timeout

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

the default value of net_write_timeout and net_read_timeout is small ,you can execute

 mysql> show variables like '%timeout%';
to find the result.

person wish lv    schedule 10.07.2015