我应该如何处理" java.net.SocketException:连接重置"在多线程AWS S3文件上传?

时间:2014-12-11 19:18:01

标签: java multithreading amazon-web-services amazon-s3

我有一个ThreadPoolExecutorService,我使用AWS Java SDK将大型(1-2 GB)文件上传的可运行作业提交到Amazon的S3文件系统。偶尔我的一个工作线程会报告一个java.net.SocketException,其中包含" Connection reset"作为原因,然后死亡。

AWS没有使用已检查的异常,因此我实际上无法直接捕获SocketException - 它必须以某种方式包装。我的问题是我应该如何处理这个问题,以便我可以重试任何有问题的上传,并提高我的程序的可靠性。

Multipart上传API会更可靠吗?

我是否能够可靠地捕获以启用重试?

这是堆栈跟踪。 com.example。*代码是我的。基本上DataProcessorAWS调用的工作是在putObject(String bucketName, String key, File file)的实例上调用AmazonS3Client,这些实例在线程之间共享。

14/12/11 18:43:17 INFO http.AmazonHttpClient: Unable to execute HTTP request: Connection reset
java.net.SocketException: Connection reset
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:118)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
    at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:377)
    at sun.security.ssl.OutputRecord.write(OutputRecord.java:363)
    at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:830)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:801)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
    at org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:169)
    at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:119)
    at org.apache.http.entity.InputStreamEntity.writeTo(InputStreamEntity.java:102)
    at com.amazonaws.http.RepeatableInputStreamRequestEntity.writeTo(RepeatableInputStreamRequestEntity.java:153)
    at org.apache.http.entity.HttpEntityWrapper.writeTo(HttpEntityWrapper.java:98)
    at org.apache.http.impl.client.EntityEnclosingRequestWrapper$EntityWrapper.writeTo(EntityEnclosingRequestWrapper.java:108)
    at org.apache.http.impl.entity.EntitySerializer.serialize(EntitySerializer.java:122)
    at org.apache.http.impl.AbstractHttpClientConnection.sendRequestEntity(AbstractHttpClientConnection.java:271)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.sendRequestEntity(ManagedClientConnectionImpl.java:197)
    at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:257)
    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:715)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:520)
    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.executeOneRequest(AmazonHttpClient.java:685)
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:460)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:295)
    at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3697)
    at com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1434)
    at com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1294)
    at com.example.DataProcessorAWS$HitWriter.close(DataProcessorAWS.java:156)
    at com.example.DataProcessorAWS$Processor.run(DataProcessorAWS.java:264)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    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)
    at java.lang.Thread.run(Thread.java:745)

4 个答案:

答案 0 :(得分:2)

javadoc表示发生此类错误时putObject()会抛出AmazonClientException。 AmazonClientException有一个名为isRetryable()的方法,您可以尝试使用它。

答案 1 :(得分:2)

为此你必须只使用AmazonS3Client而不是Trasfermanager进行上传和下载

您必须使用以下属性配置AmazonS3Client:

1. connectionTimeout=50000 in ms
2.maxConnections=500
3.socketTimeout=50000 in ms
4.maxErrorRetry=10

上传使用

AmazonS3Client.putObject(bucketName, key, inputFile);

供下载使用

S3Object s3Object = AmazonS3Client.getObject(new GetObjectRequest(bucketName, key));`
InputStream downloadStream  = s3Object.getObjectContent();  

并通过读取字节来存储该流。

答案 2 :(得分:1)

'连接重置'意味着连接被冲洗。关闭套接字,或者您正在使用的任何更高级别的构造。可能服务器已经确定上传太大,或者它已经超载,或者其他什么。您是否可以重新尝试操作只是您可以知道的事情。

答案 3 :(得分:1)

就我而言,我正在使用一些元数据保存对象。在原型期间,我们添加了系统元数据"时间创建",并且始终导致与问题中的上述类似的错误。并且它不能重试,因为它打算修改系统元数据。但根据API,如下所示,

  

抛出:

     
      
  • SdkClientException - 如果在客户端中遇到任何错误   同时制作>请求或处理响应。
  •   
  • AmazonServiceException - 如果在处理时,Amazon S3中发生任何错误>请求。
  •   

我的理解是预期的行为应该是,

  • 抛出上述异常之一,或,
  • 返回403,而不是伞形AmazonClientException,"连接关闭"。

打开S3调试时,请参阅以下日志

2017-07-11 17:12:45,163 DEBUG  [org.apache.http.wire] - http-outgoing-3 >> "**[write] I/O error: Connection has been shutdown: javax.net.ssl.SSLException: java.net.SocketException: Connection reset"**
2017-07-11 17:12:45,221 DEBUG  [org.apache.http.wire] - http-outgoing-4 >> "PUT /dev-ec-dev/neon/ECTE/CPER/2017-6/ECTE_dp0p_CPER_2017-06-05.h5 HTTP/1.1[\r][\n]"
2017-07-11 17:12:45,221 DEBUG  [org.apache.http.wire] - http-outgoing-4 >> "Host: s3.data.neonscience.org[\r][\n]"
2017-07-11 17:12:45,221 DEBUG  [org.apache.http.wire] - http-outgoing-4 >> "Authorization: AWS dev-ec-owner:dE6ouKtPpP9aftLRba4OVn6DH9M=[\r][\n]"
2017-07-11 17:12:45,222 DEBUG  [org.apache.http.wire] - http-outgoing-4 >> "x-amz-meta-site: CPER[\r][\n]"
2017-07-11 17:12:45,226 DEBUG  [org.apache.http.wire] - http-outgoing-4 >> "x-amz-meta-time-created: 2017-07-11T17:12:44.904[\r][\n]"

使用常规记录的更多日志,

2017-07-11 17:12:45,247 DEBUG  [org.apache.http.wire] - http-outgoing-4 >> "[write] I/O error: Connection has been shutdown: javax.net.ssl.SSLException: java.net.SocketException: Connection reset"
2017-07-11 17:12:45,248 ERROR  [org.battelle.neon.is.transition.ec.ECTELevelZeroPrimeJob] - Error copyDataToS3: Not getting descriptive AmazonS3Exception.
Batch runner failed.com.amazonaws.AmazonClientException: Unable to execute HTTP request: Connection reset
java.lang.RuntimeException: com.amazonaws.AmazonClientException: Unable to execute HTTP request: Connection reset
        at org.battelle.neon.is.transition.ec.ECTELevelZeroPrimeJob.runTransition(ECTELevelZeroPrimeJob.java:347)
        at org.battelle.neon.is.batch.BatchRunner.lambda$null$1(BatchRunner.java:152)
        at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)