什么是 java.io.EOFException,消息:无法读取服务器的响应.预期读取 4 个字节,读取 0 个字节

2022-01-24 00:00:00 connection pool mysql java glassfish

这个问题已经在 SO 中被问过几次,在其他网站上也被问过很多次.但我没有得到任何令人满意的答案.

This question has been asked a couple of times in SO and many times in other sites. But I didn't get any satisfiable answer.

我的问题:
我有一个 java web 应用程序,它使用简单的 JDBC 通过 Glassfish 应用程序服务器连接到 mysql 数据库.

My problem:
I have a java web application which uses simple JDBC to connect to mysql database through Glassfish application server.

我在 glassfish 服务器中使用了连接池,配置如下:
初始池大小:25
最大池大小:100
池调整数量:2
空闲超时:300 秒
最大等待时间:60,000 毫秒

I have used connection pooling in glassfish server with the following configurations:
Initial Pool Size: 25
Maximum Pool Size: 100
Pool Resize Quantity: 2
Idle Timeout: 300 seconds
Max Wait Time: 60,000 milliseconds

该应用程序已部署了 3 个月,并且运行良好.
但是从过去 2 天开始,登录时出现以下错误.

The application has been deployed for last 3 months and it was running flawlessly too.
But from last 2 days the following error is coming at the time of login.

部分堆栈跟踪

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

是什么突然导致了这个错误?我为此浪费了很多时间.

What caused this error suddenly ? I have lost a lot of time for this.

重新启动服务器后问题仍然存在.根据 DBA,两个重要的 mysql 服务器配置是:
wait_timeout : 1800 秒
connect_timeout : 10 秒
注意: 部署在同一台服务器上的其他应用程序连接到同一个数据库并使用不同的池运行顺利.

EDIT : The problem even persists after restarting the server. As per DBA two of the important mysql server configurations are:
wait_timeout : 1800 seconds
connect_timeout : 10 seconds
NOTE : Other applications deployed in the same server connecting to the same database and using different pools are running smoothly.

EDIT-2 : 在阅读了很多内容并期待一些积极的结果之后,我对我的连接池进行了这些更改.

EDIT-2 : After reading a lot of things and expecting some positive outcome I made these changes to my connection pool.

最大等待时间: 0(以前是 60 秒)
连接验证:必需
验证方法:表格
表名:演示
最多验证一次: 40 秒
创建重试次数: 1
重试间隔: 5 秒
最大连接使用量: 5

Max Wait Time : 0 (previously it was 60 seconds)
Connection Validation : Required
Validation Method : table
Table Name : Demo
Validate Atmost Once : 40 seconds
Creation Retry Attempts : 1
Retry Intervals : 5 seconds
Max Connection Usage : 5

这很有效,因为应用程序连续运行了 3 天.但我得到了一个非常奇怪和有趣的结果.在监控连接池时,我发现了这些数字:

And this worked as the application is running for 3 days consistently. But I got a very strange and interesting result of out this. While monitoring the connection pool, I found these figures:

NumConnAcquired: 44919 计数
NumConnReleased: 44919 计数
NumConnCreated : 9748 个计数
NumConnDestroyed : 9793 计数
NumConnFailedValidation : 70 个
NumConnFree: 161 个
NumConnUsed: -136 计数

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

如何 NumConnFree 变成 161,因为我有 Maximum Pool Size = 100 ?
如何 NumConnUsed 变成-136,一个负 数?
如何 NumConnDestroyed > NumConnCreated ?

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 ?

推荐答案

连接失败,可能是由于防火墙空闲超时等原因.如果您没有将 JDBC 驱动程序配置为在失败时重新连接,那么这个除非您打开新连接,否则错误不会消失.

The connection has failed, possibly due to a firewall idle-timeout, etc. If you don't have your JDBC driver configured to reconnect on failure, then this error will not go away unless you open a new connection.

如果您正在使用数据库连接池(您正在使用一个,对吗?),那么您可能希望启用它的连接检查功能,例如发出查询以检查连接是否在将其交还给应用程序之前正在工作.在 Apache commons-dbcp 中,这称为 validationQuery,通常设置为简单的东西,例如 SELECT 1.

If you are using a database connection pool (you are using one, right?), then you probably want to enable it's connection-checking features like issuing a query to check to see if the connection is working before handing it back to the application. In Apache commons-dbcp, this is called the validationQuery and is often set to something simple like SELECT 1.

由于您使用的是 MySQL,因此您应该使用比实际发出真正的 SQL 查询更轻量的 Connector/J 特定ping"查询,并将您的验证查询设置为 /* ping */SELECT1(ping 部分 需要准确).

Since you are using MySQL, you ought to use a Connector/J-specific "ping" query that is lighter-weight than actually issuing a true SQL query and set your validation query to /* ping */ SELECT 1 (the ping part needs to be exact).

相关文章