AWS SDK S3套接字关闭异常

12

我的应用程序使用近10个线程,每个线程每分钟可能会向S3发出大约7,000个Put请求。(我在一台性能强大的EC2机器上运行它,可以很好地处理负载。) 它运行得非常顺畅,接近一个小时,但是,一个小时后,出现“无法执行HTTP请求:套接字关闭”异常:

        http.AmazonHttpClient: Unable to execute HTTP request: Socket Closed
    java.net.SocketException: Socket Closed
    at java.net.AbstractPlainSocketImpl.setOption(AbstractPlainSocketImpl.java:206)
    at java.net.Socket.setSoTimeout(Socket.java:1105)
    at sun.security.ssl.SSLSocketImpl.setSoTimeout(SSLSocketImpl.java:2414)
    at org.apache.http.impl.io.SocketInputBuffer.isDataAvailable(SocketInputBuffer.java:106)
    at org.apache.http.impl.AbstractHttpClientConnection.isResponseAvailable(AbstractHttpClientConnection.java:246)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.isResponseAvailable(ManagedClientConnectionImpl.java:180)
    at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:238)
    at com.amazonaws.http.protocol.SdkHttpRequestExecutor.doSendRequest(SdkHttpRequestExecutor.java:47)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
    at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:713)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:518)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:446)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:256)
    at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3641)
    at com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1438)
    at com.amazonaws.services.s3.transfer.internal.UploadCallable.uploadInOneChunk(UploadCallable.java:128)
    at com.amazonaws.services.s3.transfer.internal.UploadCallable.call(UploadCallable.java:120)
    at com.amazonaws.services.s3.transfer.internal.UploadMonitor.upload(UploadMonitor.java:176)
    at com.amazonaws.services.s3.transfer.internal.UploadMonitor.call(UploadMonitor.java:134)
    at com.amazonaws.services.s3.transfer.internal.UploadMonitor.call(UploadMonitor.java:50)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

使用AWS SDK TransferManager异步完成Put请求。我想,一个Put请求完全完成所需的时间内,已经异步执行了约10个Put请求。

通过谷歌搜索该异常,我发现可能有两种原因:

  1. MaxConnections限制。我已将其从默认值50提高到3000,但无济于事。
  2. 过早进行垃圾回收。我尝试保留由TransferManager返回的Upload对象的引用(在并发队列中),但仍然没有帮助。

我该如何解决这个问题?再次强调,应用程序运行良好接近一个小时,但是,在一小时左右之后,始终会遇到这个问题。(我在EC2上运行Amazon AMI Linux。)

更新

  • 除AWS SDK外,没有其他代码触摸套接字,甚至知道它们。所有HTTP工作都是通过AWS SDK独家完成的。
  • 因此,如果有东西关闭它们,那一定是AWS SDK中的某些东西。
  • 代码正在EC2服务器上运行;没有理由预期EC2和S3之间存在任何类型的网络连接问题,肯定没有理由预期它们会每次都可预测地出现(在运行一小时后)。

你能够发布一些最小化的代码,以便在不同的数据集上重现问题吗?这发生时,你也能展示一下你的 netstat -tn 的输出吗? - b4hand
@b4hand - 我会尽力而为。由于问题仅在约45分钟后出现,实验变得缓慢。我需要一些时间来尝试解决它,但我会尽力而为。 - SRobertJames
4个回答

1
我不确定这是否是答案,但 http://docs.aws.amazon.com/AmazonS3/latest/dev/request-rate-perf-considerations.html 指出“如果您预计桶的请求速率快速增加到每秒300个PUT/LIST/DELETE请求或每秒800个GET请求以上,我们建议您打开支持案例以为工作负载做好准备并避免请求速率上的任何临时限制”。也许是因为我超过了限制,AWS开始中止连接; SDK检测到IDLE套接字并将其关闭,然后,我们会收到异常。 更新: 不确定是否正确。 亚马逊似乎表明,在这种情况下,您将收到显式的“慢下来”错误消息,而不是意外关闭。 因此,谜题仍然存在。

如果我是正确的,确认这一点,更重要的是,一个解决方案 - 特别是一个不需要 AWS 支持工程师就能工作的解决方案 - 仍然会赢得奖励。 - SRobertJames

1

Sandeep - 这是否意味着仅仅提高套接字超时时间就可以解决这个问题?我会尝试一下。你有猜测为什么只有大约40分钟后才会出现这种情况吗? - SRobertJames
从您发布的代码来看,当您尝试在已关闭的套接字上设置超时时,会抛出异常。当套接字超时时不会抛出异常! - SRobertJames
不是获取套接字超时时间,而是设置它,而且在设置超时时间的过程中遇到了关闭的套接字。如果出现了读取超时,就会抛出 SocketTimeoutException 异常。这完全是颠倒的。 - user207421

-1

我认为你最好尝试使用ClientConfiguration.setSocketTimeout(int)。如果套接字异步关闭,我认为这是由于超时引起的。根据亚马逊文档:

public void setSocketTimeout(int socketTimeout)

Sets the amount of time to wait (in milliseconds) for data to be transfered 
over an established, open connection before the connection times out and is closed. 
A value of 0 means infinity, and isn't recommended.

所以,根据文档,如果连接超时,我认为它会自动关闭。
链接:http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html#setSocketTimeout(int)

1
超时到期会导致 SocketTimeoutException 异常,而不是关闭。 - user207421
1
@EJP,感谢您的评论。但根据文档,连接可以异步关闭。 - Byungjoon Lee
@EJP - 你能否详细说明是什么导致了这个关闭,更重要的是,我该怎么做? - SRobertJames
1
我认为你最好尝试将显式超时设置为“0”或至少大于两个小时。例如,创建ClientConfiguration对象,调用setSocketTimeout(0)并将其作为参数传递给创建AmazonHttpClient对象的方法。这样做有意义吗? - Byungjoon Lee
@ByungjoonLee,你引用的文档中没有出现“异步”一词。而且也没有提到要抛出OP的异常,而不是SocketTimeoutException。而且OP的异常发生在设置超时时间时,这意味着它还没有被设置,也就是说它不是由于超时而过期。你完全搞反了。 - user207421

-3

这个异常只有一个原因,你或者你的框架关闭了套接字却继续使用它。


我不知道JVM会随意关闭套接字。是什么导致JVM关闭它,更重要的是,我如何防止它这样做? - SRobertJames
请支持您的说法,即JVM正在关闭套接字。我从未听说过这个。 - SRobertJames
@SRobertJames,我并没有说JMVs '任意'关闭套接字。 它们不会。是您的应用程序或某个有缺陷的库这样做了。该断言得到了Javadoc的支持。 - user207421
实际上,原始答案确实说“JVM关闭了套接字”。在我的评论之后,它被编辑为“您关闭了套接字”。 - SRobertJames
@SRobertJames,它并没有说“任意”。那是你的贡献。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接