繁体   English   中英

Postgresql 使用 Java 应用程序发送到后端时发生 I/O 错误

[英]Postgresql An I/O error occurred while sending to the backend using Java application

我正在使用 Amazon RDS 服务托管一个 PostreSql,它用作我的 Java 应用程序的数据库。 应用程序启动后,它能够按预期执行查询,直到我停止交互几分钟并尝试再次执行任何查询。 在那种情况下,我得到以下异常:

WARNING: Validating connection.
org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:327)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:428)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:354)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:169)
    at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:136)
    at org.postgresql.jdbc.PgConnection.isValid(PgConnection.java:1311)
    at org.apache.commons.dbcp2.DelegatingConnection.isValid(DelegatingConnection.java:897)
    at org.apache.commons.dbcp2.PoolableConnection.validate(PoolableConnection.java:270)
    at org.apache.commons.dbcp2.PoolableConnectionFactory.validateConnection(PoolableConnectionFactory.java:630)
    at org.apache.commons.dbcp2.PoolableConnectionFactory.validateObject(PoolableConnectionFactory.java:648)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:472)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:349)
    at org.apache.commons.dbcp2.PoolingDataSource.getConnection(PoolingDataSource.java:134)
    at org.apache.commons.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:753)

Caused by: java.net.SocketException: Operation timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:170)
    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:288)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1962)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:300)

在 Amazon RDS PostgreSQL 上,我看到以下错误:

2020-04-09 19:01:11 UTC::[]:LOG: could not receive data from client: Connection timed out
2020-04-09 19:04:27 UTC::@:[]:LOG: checkpoint starting: time
2020-04-09 19:04:28 UTC::@:[]:LOG: checkpoint complete: wrote 1 buffers (0.0%); 0 WAL file(s) added, 0 removed, 1 recycled; write=0.143 s, sync=0.001 s, total=0.154 s; sync files=1, longest=0.001 s, average=0.001 s; distance=16377 kB, estimate=16396 kB
2020-04-09 19:08:15 UTC::LOG: could not receive data from client: Connection timed out

知道如何解决这个问题吗?

我猜您有一个(虚拟)网络组件,例如路由器、负载均衡器、状态防火墙等,它决定在 X 秒后可以删除您的连接,从而节省一些宝贵的 memory。 然而,这并没有通知双方 TCP 连接(数据库和您的 Java 应用程序),所以一段时间后他们会注意到它们不再相互连接。

如果您无法更改静默终止连接的网络组件的行为,您可以从以下选项中进行选择:

  1. 配置您的连接池(DBCP,或者如果您不喜欢它,切换到 HikariCP)以主动关闭空闲连接,在上述超时之前,请参阅这个古老线程的说明
  2. 配置您的连接池以继续检查空闲连接的健康状况,这将使连接保持活动状态
  3. 通过以下方式使用操作系统 (TCP KeepAlive) 中的 TCP 功能:

    • 通过 JDBC 驱动程序在套接字上启用此功能:tcpKeepAlive="true"
    • 调整操作系统保活时间设置以在超时前传输保活数据包,请参阅: Linux 文档这些 Windows 注册表设置
  4. 不要使用连接池(但这对性能不利,请参阅: this answer了解更多详细信息

我以前曾经遇到过这个问题,这让我发疯。 最终问题是因为防火墙在没有通知后端的情况下停止任何空闲连接超过 30 分钟

我在这里看到了一个潜在的问题,您的连接池中与您的 postgres 数据库的连接可能用完了,这可能是因为现有的连接在您的数据库事务之后可能不会关闭,并且没有被新的传入事务重用。 尝试使用 pgbouncer 来解决这个问题。 这是我看到你的日志的猜测

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM