【问题标题】:AWS SDK S3 Socket Closed exceptionAWS 开发工具包 S3 套接字关闭异常
【发布时间】:2014-11-19 10:49:32
【问题描述】:

我的应用程序使用近 10 个线程,每个线程每分钟向 S3 发出大约 7,000 个 Put 请求。 (我在一个功能强大的 EC2 机器上运行它,它可以很好地处理负载。)它运行得很漂亮将近一个小时,但是,一个小时后,得到Unable to execute HTTP request: Socket Closed 异常:

        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)

Put 请求使用 AWS 开发工具包 TransferManager 异步完成。我想,在一个 put 请求完全完成所需的时间内,大约有 10 个是异步发出的。

谷歌搜索该异常,我发现了两个可能的原因:

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

我该如何解决这个问题?同样,该应用程序运行良好近一个小时,但始终如一地在大约一个小时后撞到这堵墙。 (我在 EC2 上的 Amazon AMI Linux 上运行。)

更新

  • 除 AWS 开发工具包外,没有任何代码接触套接字,甚至不知道它们。所有 HTTP 工作都是通过 AWS SDK 专门完成的。
  • 因此,如果有什么东西正在关闭它们,那一定是 AWS 开发工具包中的东西。
  • 代码在 EC2 服务器上运行;没有理由预计 EC2 和 S3 之间会出现任何类型的网络连接问题,当然也没有理由每次都可预见地发生(运行一小时后)

【问题讨论】:

  • 你能发布一些在不同数据集上重现问题的最小代码吗?发生这种情况时,您还可以显示您的netstat -tn 输出吗?
  • @b4hand - 我会尽力搞定这一切。由于问题仅在大约 45 分钟后出现,因此实验速度很慢。这需要我一点时间,但我会努力的。

标签: java sockets amazon-web-services amazon-s3 aws-sdk


【解决方案1】:

我不确定这是否是答案,但http://docs.aws.amazon.com/AmazonS3/latest/dev/request-rate-perf-considerations.html 指出 “如果您预计存储桶的请求率会快速增加到每秒 300 多个 PUT/LIST/DELETE 请求或每秒超过 800 个 GET 请求,我们建议您打开支持案例以准备工作负载并避免对您的请求速率造成任何临时限制”。也许因为我超过了限制,AWS 开始中止连接; SDK,检测空闲套接字,关闭它们,然后,瞧!,我们得到了异常。

更新:不确定这是否正确。亚马逊似乎声明,在这种情况下,您会收到明确的“减速”错误消息,而不是意外关闭。所以,难题仍然存在。

【讨论】:

  • 如果我是对的,请确认这一点,更重要的是,一个解决方案 - 尤其是。无需 AWS 支持工程师即可工作 - 仍将赢得赏金。
【解决方案2】:

异常是由 java.net.Socket 中的 setSoTimeout() 方法引起的 SocketException。(参见堆栈跟踪)。方法可以看这里:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/net/Socket.java#Socket.setSoTimeout%28int%29

可能的原因可能是对 S3 的请求仍处于挂起/未完成状态,导致线程等待()。一旦等待时间超过socket timeout,socket就会关闭并抛出异常。

【讨论】:

  • Sandeep - 这是否意味着简单地提高套接字超时就可以解决这个问题?我会试试的。关于为什么会在大约 40 分钟后发生这种情况的任何猜测。
  • 查看您发布的代码,当您尝试在关闭的套接字上设置超时时会引发异常。套接字超时时不会抛出它!
  • 没有。该方法是设置套接字超时,而不是得到一个,并且它在这样做时遇到了一个关闭的套接字。如果出现读取超时,则会出现SocketTimeoutException。这完全是从前到后。
【解决方案3】:

我认为你最好试试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)

【讨论】:

  • 超时到期会导致 SocketTimeoutException,而不是关闭。
  • @EJP,感谢您的评论。但是根据文档,可以异步关闭连接。
  • @EJP - 你能否详细说明导致此关闭的原因,更重要的是,我该怎么做?
  • 我认为您最好尝试将显式超时设置为“0”或至少大于两个小时。例如,创建ClientConfiguration 对象,调用setSocketTimeout(0) 给它,并在创建AmazonHttpClient 对象时将其作为参数传递。有意义吗?
  • @ByungjoonLee 您引用的文档中没有出现“异步”这个词,也没有任何关于抛出 OP 异常而不是 SocketTimeoutException 的内容。并且OP的异常发生在设置超时时,这意味着它没有被设置,这意味着它不是由于超时到期。你有这个完全回到前面。
【解决方案4】:

此异常只有一个原因。您或您的框架关闭了套接字,然后继续使用它。

【讨论】:

  • 我不知道 JVM 会任意关闭套接字。是什么导致 JVM 关闭它,更重要的是,我如何防止它这样做?
  • 请支持您的JVM正在关闭套接字的说法。我从来没有听说过这个。
  • @SRobertJames 我没有说过 JMV '任意'关闭套接字。他们没有。您的应用程序确实如此,或者一些错误的库。 Javadoc 支持该断言。
  • (其实原来的答案确实是“JVM关闭了socket”吧。在我的cmets之后,它被编辑为“你关闭了socket”。)
  • @SRobertJames 它没有说“任意”。那是你的贡献。
猜你喜欢
  • 2011-11-10
  • 1970-01-01
  • 2013-07-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-26
  • 2012-01-25
  • 2017-09-06
  • 1970-01-01
相关资源
最近更新 更多