Postgres JDBC 客户端卡在从套接字读取

Posted

技术标签:

【中文标题】Postgres JDBC 客户端卡在从套接字读取【英文标题】:Postgres JDBC client getting stuck at reading from socket 【发布时间】:2018-05-11 18:44:08 【问题描述】:

我有一个 PostGIS 数据库和一个基于 HikariCP 构建的客户端,用于从数据库中读取数据。我的客户在某些机器上可以毫无问题地读取数据。但是,在其他一些机器上,客户端卡住了,无法读取任何数据,引发套接字超时异常。

MyClass:120 - Failed to execute HikariProxyPreparedStatement@2091541230 wrapping <my-query>.
org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:332)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155)
    at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:118)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
    ...
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:140)
    at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:109)
    at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:67)
    at org.postgresql.core.PGStream.receiveChar(PGStream.java:293)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1947)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306)
    ... 32 more

ProxyConnection:161 - HikariPool-1 - Connection org.postgresql.jdbc.PgConnection@1aafd32f marked as broken because of SQLSTATE(08006), ErrorCode(0)
org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:332)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155)
    at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:118)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
    ...
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:140)
    at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:109)
    at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:67)
    at org.postgresql.core.PGStream.receiveChar(PGStream.java:293)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1947)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306)
    ... 31 more

在客户端在数据库端抛出SocketTimeoutException 之前,我监控了pg_stat_activity 表。上面查询的对应行有wait_event_type=Clientwait_event=ClientWrite。此外,数据库服务器记录的消息表明连接丢失。

LOG:  unexpected EOF on client connection with an open transaction
LOG:  could not send data to client: Connection timed out
FATAL:  connection to client lost

版本

PostGIS-jdbc:2.2.1(postgresql jdbc:9.4.1208.jre7) HikariCP:3.1.0 Postgres 服务器:10.3 PostGIS 服务器:2.4.4

如果我不通过 jdbc 连接字符串设置socketTimeout,那么连接将永远卡住。一旦连接达到其最大寿命,它将被丢弃并再次连接。但是,它仍然无法读取数据。当我设置socketTimeout时,会抛出异常。

更新 如果未设置socketTimeout,则pg_stat_activity 表将包含具有以下值的连接行:state=idle in transactionwait_event_type=Clientwait_event=ClientRead

我的猜测是某种网络设置阻止了客户端从服务器读取。我该如何进一步调试并找到根本原因?

【问题讨论】:

两端的网络跟踪应该会有所帮助。看起来客户端和服务器都在等待另一个。也许防火墙会丢弃来自 PostgreSQL 服务器的响应。 您可能想尝试使用更新版本的 JDBC 驱动程序,42.2.2 是最新的驱动程序版本。 @MarkRotteveel 切换到 42.2.2,但没有区别。 【参考方案1】:

我们发现这是由数据库服务器的 MTU 设置引起的。 MTU 默认设置为 9000,导致丢包。将其更改为 1500 即可解决此问题。

【讨论】:

以上是关于Postgres JDBC 客户端卡在从套接字读取的主要内容,如果未能解决你的问题,请参考以下文章

数据流作业卡在从 Pub/Sub 读取

JDBC调用上的Weblogic卡住线程

Oracle 启动SQL Developer提示无法从套接字读取更多的数据

为啥在从服务器接收到所有数据后客户端套接字连接没有关闭?

在同一局域网中通过 JDBC 连接到 Postgres 服务器时出现 PSQLException(PGAdmin 工作)

RDS postgres 从 9.4 升级到 9.5,CPU 卡在 100% 几个小时