Что такое java.io.EOFException, Message: Не удается прочитать ответ с сервера. Ожидалось читать 4 байта, читать 0 байт
Этот вопрос задавали пару раз в SO и много раз на других сайтах. Но ответа я не получил.
Моя проблема:
У меня есть веб-приложение java, которое использует простой JDBC для подключения к базе данных mysql через сервер приложений Glassfish.
Я использовал пул соединений на сервере Glassfish со следующими конфигурациями:
Начальный размер пула: 25
Максимальный размер бассейна: 100
Pool Resize Количество: 2
Idle Timeout: 300 секунд
Максимальное время ожидания: 60 000 миллисекунд
Приложение было развернуто в течение последних 3 месяцев, и оно работает безупречно.
Но с последних 2 дней на момент входа в систему появляется следующая ошибка.
Частичный 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....
Что вызвало эту ошибку внезапно? Я потерял много времени для этого.
EDIT: Проблема сохраняется даже после перезапуска сервера. В соответствии с DBA две важные конфигурации сервера mysql:
wait_timeout: 1800 секунд
connect_timeout: 10 секунд
ПРИМЕЧАНИЕ. Другие приложения, развернутые на одном сервере, подключающиеся к одной базе данных и использующие разные пулы, работают плавно.
EDIT-2: После прочтения многих вещей и ожиданий какого-то положительного результата я внес эти изменения в пул соединений.
Макс. время ожидания: 0 (раньше это было 60 секунд)
Проверка подключения: Требуется |
Метод проверки: таблица
Имя таблицы: Демо-версия
Подтвердить как минимум: 40 секунд
попытки повторной попытки создания: 1
Интервалы повторения: 5 секунд
Максимальное использование подключения: 5
И это работало, так как приложение работает в течение 3 дней. Но у меня получился очень странный и интересный результат. Наблюдая за пулом соединений, я нашел эти цифры:
NumConnAcquired: 44919 Count
NumConnReleased: 44919 Count
NumConnCreated: 9748 Count
NumConnDestroyed: 9793 Count
NumConnFailedValidation: 70 Count
NumConnFree: 161 граф
NumConnUsed: -136 Count
Как может NumConnFree
стать 161, поскольку у меня есть Maximum Pool Size = 100
?
Как может NumConnUsed
стать -136, отрицательное число ?
Как может NumConnDestroyed
NumConnCreated
?
Ответы
Ответ 1
Соединение завершилось неудачно, возможно из-за тайм-аута брандмауэра и т.д. Если у вас нет драйвера JDBC, настроенного на повторное подключение к ошибке, эта ошибка не исчезнет, если вы не откроете новое соединение.
Если вы используете пул соединений с базой данных (вы используете один, правда?), то вы, вероятно, захотите включить его функции проверки соединения, такие как выдача запроса, чтобы проверить, работает ли соединение, прежде чем передать его обратно приложение. В Apache commons-dbcp это называется validationQuery
и часто устанавливается на что-то простое, например SELECT 1
.
Поскольку вы используете MySQL, вы должны использовать запрос "ping" для Connector/J-specific, который имеет меньший вес, чем фактический выпуск истинного SQL-запроса, и установите ваш запрос проверки на /* ping */ SELECT 1
(часть ping должно быть точно).
Ответ 2
Скорее всего, это означает, что база данных перезагрузилась или сетевое соединение с базой данных было нарушено (например, время соединения NAT было отключено)... и ваш webapp пытается использовать устаревшее соединение с базой данных.
Если проблема повторится после перезапуска веб-контейнера, это может быть что-то более серьезное.
Вы спросили следующее:
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 ?
На первый взгляд это не имеет смысла. Однако они могут быть просто результатом того, что некоторые счетчики использования обновляются небезопасным способом. Это не обязательно связано с вашей исходной проблемой.
Ответ 3
Это EndOfFileException в java, происходит, когда начальная точка курсора находится в конечной точке или когда соединение с базой данных закрыто из-за какого-то неожиданного исключения.
Ответ 4
Пока у меня нет окончательных решений, кажется, что что-то мешает взаимодействию между сервером приложений и db. Ниже приведены несколько вещей, которые вы можете попытаться изолировать проблемы:
-
Попробуйте определить, есть ли проблема mysql или проблема с java-кодом. Попробуйте подключиться к mysql с помощью инструмента командной строки с того же хоста, что и сервер приложений, и выпустить аналогичный SQL для входа в систему. Протестируйте с помощью простого java-кода, который делает выбор, разворачивает его в той же инфраструктуре, видит, что произойдет и т.д. Также проверьте журнал сервера mysql, посмотрите, можете ли вы найти что-нибудь полезное
-
Существует два способа: закрытие незанятого соединения: по коду пула соединений, который запускается внутри сервера приложений, или самому mysql. Убедитесь, что вы проверяете конфигурацию с обеих сторон.
-
Проверьте, изменилась ли какая-либо конфигурация сетевой инфраструктуры в последнее время. Было ли какое-либо новое правило брандмауэра вмешиваться в соединение с сервером приложений ↔ mysql? Были ли какие-либо настройки, запрещающие открытое TCP-соединение на холостом ходу дольше X?
-
Попробуйте использовать другую библиотеку пула соединений, чтобы исключить возможность объединения пулов
Удачи.
Ответ 5
Это может быть проблема с Firewall.
Ответ 6
У меня была эта проблема, но мне не удалось внести изменения в конфигурацию базы данных MySQL. Поэтому я убедился, что в моем классе соединителей sql соединение всегда закрывается до его повторного запуска. Что-то вроде:
public static Connection getConnection() {
if (DatabaseConnnector.conn == null) {
initConn();
} else {
try {
DatabaseConnnector.conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
initConn();
}
return DatabaseConnnector.conn;
}
И это решило проблему.