S3 Java 客户端因“内容长度分隔消息正文过早结束”或“java.net.SocketException Socket 已关闭”而失败很多

我有一个应用程序,可以在S3上做很多工作,主要是从中下载文件。我看到很多这样的错误,我想知道这是否是我的代码上的东西,或者服务是否真的不可靠。

我用于从 S3 对象流中读取的代码如下所示:

public static final void write(InputStream stream, OutputStream output) {

  byte[] buffer = new byte[1024];

  int read = -1;

  try {

    while ((read = stream.read(buffer)) != -1) {
      output.write(buffer, 0, read);
    }

    stream.close();
    output.flush();
    output.close();
  } catch (IOException e) {
    throw new RuntimeException(e);
  }

}

这个输出流是一个新的 BufferedOutputStream( new FileOutputStream( file ) )。我正在使用最新版本的 Amazon S3 Java 客户端,此调用在放弃之前重试了四次。因此,在尝试了4次之后,它仍然失败了。

任何关于如何改善这一点的提示或技巧都值得赞赏。


答案 1

我刚刚设法克服了一个非常相似的问题。在我的情况下,我得到的例外是相同的;它发生在较大的文件上,但不发生在小文件上,并且在单步执行调试器时从未发生过。

问题的根本原因是 AmazonS3Client 对象在下载过程中被垃圾回收,从而导致网络连接中断。发生这种情况是因为我正在构建一个新的AmazonS3Client对象,每次调用加载文件,而首选用例是创建一个持久的客户端对象,该对象在调用中存活 - 或者至少保证在整个下载过程中存在。因此,简单的补救措施是确保保留对AmazonS3Client的引用,以便它不会获得GC'd。

AWS 论坛上对我有帮助的链接在这里:https://forums.aws.amazon.com/thread.jspa?threadID=83326


答案 2

由于某种原因,网络正在关闭连接,在客户端获取所有数据之前,这就是正在发生的事情。

任何HTTP请求的一部分是内容长度,你的代码正在获取标头,说嘿,哥们,这是数据,它有很多。然后在客户端读取所有数据之前断开连接。所以它的轰炸除了例外。

我会查看您的 OS/NETWORK/JVM 连接超时设置(尽管在这种情况下,JVM 通常从操作系统继承)。关键是要弄清楚网络的哪个部分导致了问题。是您的计算机级别设置在说,不,不会再等待数据包。是你正在使用一个非阻塞读取,它在你的代码中有一个超时设置,它说,嘿,没有从服务器获得任何数据,因为比我应该等待的时间长,所以我要放弃连接和异常。等等等等等等。

最好的办法是低级窥探数据包流量并向后跟踪,以查看连接断开发生的位置,或者查看是否可以在可以控制的事情(如软件和OS / JVM)中启动超时。


推荐