PostgreSQL:在使用Java应用程序发送到后端时发生了I/O错误。

huangapple go评论121阅读模式
英文:

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

问题

以下是您提供的内容的中文翻译部分:

我正在使用Amazon RDS服务来托管一个用作我Java应用程序数据库的PostreSql。应用程序启动后,它能够正常执行查询,直到我停止交互一段时间,然后尝试再次执行任何查询。在这种情况下,我会收到以下异常消息:

警告:正在验证连接。
org.postgresql.util.PSQLException: 在发送到后端时发生I/O错误。
    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: 操作超时
    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: 无法从客户端接收数据:连接超时
2020-04-09 19:04:27 UTC::@:[]:LOG: 检查点开始:时间
2020-04-09 19:04:28 UTC::@:[]:LOG: 检查点完成:已写入1个缓冲区(0.0%);已添加0个WAL文件,已删除0个,已回收1个;写入=0.143秒,同步=0.001秒,总计=0.154秒;同步文件=1,最长时间=0.001秒,平均时间=0.001秒;距离=16377 kB,估计=16396 kB
2020-04-09 19:08:15 UTC::LOG: 无法从客户端接收数据:连接超时

有关如何解决这个问题的任何想法吗?

英文:

I am using Amazon RDS service to host a PostreSql which serves as a database for my Java application. After the application starts, it is able to execute queries as expected until I stop interacting for some minutes and try to execute any query again. In that scenario, I get the following exception:

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)

On Amazon RDS PostgreSQL I see the following errors:

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

Any idea of how to solve that issue?

答案1

得分: 2

我猜你有一个(虚拟的)网络组件,比如路由器、负载均衡器、有状态防火墙等,它决定在经过X秒后可以删除你的连接,从而节省一些宝贵的内存。然而,在不通知TCP连接的双方(数据库和你的Java应用程序)的情况下进行,因此过一段时间后,它们会注意到彼此之间不再连接。

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

  1. 配置连接池(DBCP,或者如果你不喜欢它,切换到HikariCP),在上述超时之前主动关闭空闲连接,详情请参阅这个古老的主题
  2. 配置连接池以持续检查空闲连接的健康状况,这将保持连接处于活动状态。
  3. 使用操作系统的TCP功能(TCP KeepAlive):
  • 通过JDBC驱动程序在套接字上启用此功能,方法是:tcpKeepAlive="true"
  • 调整操作系统的keepalive时间设置,以在超时之前传输keepalive数据包,参见:Linux文档这些Windows注册表设置
  1. 不使用连接池(但这对性能不利,详情请参阅:这个答案获取更多详情
英文:

I guess you have a (virtual)network component like a router, loadbalancer, stateful firewall, etc. that decides that after X seconds your connection can be removed saving some of its precious memory. This however without informing both parties of the TCP connection (the database nor your Java application) so after some time they will notice that they are no longer connected to each other.

If you cannot change the behaviour of your network components that silently kill your connections you are left to choose from these options:

  1. Configure your Connection Pool (DBCP, or if you dislike it, switch to HikariCP) to actively close idle connections, before above timeout, see for instructions this ancient thread
  2. Configure your Connection Pool to keep checking the health of idle connections, which will keep the connection alive
  3. Use TCP features from the operating system (TCP KeepAlive) by:
  • Enabling this feature on the socket via the JDBC driver with: tcpKeepAlive="true"
  • Tuning the operating systems keepalive time settings to transmit keepalive packets before the timeout, see: Linux docs or these Windows Registry settings
  1. Don't use a connection pool (but that is bad for performance, see: this answer for more details )

答案2

得分: 1

我之前曾经遇到过这个问题,而且它让我疯狂。最终问题出在防火墙在超过30分钟的空闲连接后没有通知后端而中断了连接。

英文:

I've faced this problem once before and it was driving me crazy. Eventually the problem was because the firewall stop any idle connection for more than 30 minutes without notifing the backend

答案3

得分: 0

我看到这里可能存在一个问题,你的连接池到 PostgreSQL 数据库的连接数量可能不足,这可能是因为现有的连接在数据库事务后没有关闭,并且新的传入事务没有重新使用它。尝试使用 pgbouncer 来解决这个问题。根据我看到的日志,这是我的猜测。

英文:

I see a potential problem here, you might be running out of connections in your connection pool to your postgres DB, this might be because the existing connection might not close after your DB transaction and is not being re-used by the new incoming transaction. Try using pgbouncer to resolve this. This my guess seeing your logs

huangapple
  • 本文由 发表于 2020年4月10日 04:05:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/61129371.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定