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);
  }

}

Этот OutputStream представляет собой новый BufferedOutputStream (новый FileOutputStream (файл)). Я использую последнюю версию клиента Amazon S3 Java, и этот вызов повторяет четыре раза, прежде чем сдаваться. Итак, попробовав это 4 раза, он все равно не работает.

Любые подсказки или советы о том, как я могу улучшить это, будут оценены.

Ответ 1

Мне просто удалось преодолеть очень похожую проблему. В моем случае исключение, которое я получал, было идентичным; это произошло для больших файлов, но не для небольших файлов, и это никогда не происходило при переходе через отладчик.

Основная причина проблемы заключалась в том, что объект AmazonS3Client собирал мусор в середине загрузки, что вызвало разрыв сетевого соединения. Это произошло потому, что я создавал новый объект AmazonS3Client с каждым вызовом для загрузки файла, в то время как предпочтительным вариантом использования является создание долговременного клиентского объекта, который выживает во всех вызовах - или, по крайней мере, гарантируется, что он будет находиться во время всей скачать. Итак, простое средство состоит в том, чтобы убедиться, что ссылка на AmazonS3Client поддерживается так, чтобы она не получала GC'd.

Ссылка на форумы AWS, которые помогли мне, здесь: https://forums.aws.amazon.com/thread.jspa?threadID=83326

Ответ 2

Сеть закрывает соединение, прежде чем клиент получит все данные по той или иной причине, что происходит.

Часть любого HTTP-запроса - это длина содержимого, ваш код получает заголовок, говорящий "привет", здесь данные и его большая его часть.., а затем соединение удаляется, прежде чем клиент прочитает все данные.. поэтому его бомбардировка исключается.

Я бы посмотрел ваши настройки времени ожидания подключения к ОС /NETWORK/JVM (хотя JVM обычно наследуется от ОС в этой ситуации). Ключ должен выяснить, какая часть сети вызывает проблему. Это ваши настройки на уровне компьютера, говорящие, что не собираюсь ждать больше пакетов. Это то, что вы используете неблокирующее чтение, которое имеет тайм-аут в вашем коде, где он говорит, эй, не получил любые данные с сервера дольше, чем я должен ждать, поэтому я собираюсь удалить соединение и исключение. etc и т.д.

Лучше всего на низком уровне отслеживать трафик пакетов и трассировать назад, чтобы увидеть, где происходит переключение соединения, или посмотреть, можете ли вы использовать тайм-ауты в вещах, которые вы можете контролировать, например, ваше программное обеспечение и ОС/JVM.

Ответ 3

Прежде всего, ваш код работает нормально, если (и только если) вы испытываете проблемы с подключением между собой и Amazon S3. Как указывает Майкл Слейд , применяется стандартный отладочный совет на уровне соединения.

Что касается вашего фактического исходного кода, я отмечаю несколько запахов кода, о которых вы должны знать. Аннотирование их непосредственно в источнике:

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

  byte[] buffer = new byte[1024]; // !! Abstract 1024 into a constant to make 
                                  //  this easier to configure and understand.

  int read = -1;

  try {

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

    stream.close(); // !! Unexpected side effects: closing of your passed in 
                    //  InputStream. This may have unexpected results if your
                    //  stream type supports reset, and currently carries no 
                    //  visible documentation.

    output.flush(); // !! Violation of RAII. Refactor this into a finally block, 
    output.close(); //  a la Reference 1 (below).

  } catch (IOException e) {
    throw new RuntimeException(e); // !! Possibly indicative of an outer 
                                   //   try-catch block for RuntimeException. 
                                   //   Consider keeping this as IOException.
  }
}

(Ссылка 1)

В противном случае сам код кажется прекрасным. Исключения IO следует ожидать в ситуациях, когда вы подключаетесь к неустойчивому удаленному хосту, и ваш лучший курс действий - это разработать правильную политику для кэширования и повторного подключения в этих сценариях.

Ответ 4

  • Попробуйте использовать wireshark, чтобы увидеть, что происходит на проводе, когда это произойдет.

  • Попробуйте временно заменить S3 собственным веб-сервером и посмотреть, не исчезла ли проблема. Если это делает ваш код, а не S3.

Тот факт, что он случайный, предлагает сетевые проблемы между вашим хостом и некоторыми узлами S3.

Ответ 5

Также S3 может закрыть медленные соединения в соответствии с моим опытом.

Ответ 6

Я бы очень внимательно рассмотрел сетевое оборудование, ближайшее к вашему клиентскому приложению. Эта проблема поражает некоторое сетевое устройство, отбрасывающее пакеты между вами и службой. Посмотрите, была ли начальная точка, когда проблема впервые возникла. Были ли какие-либо изменения, такие как обновление прошивки для маршрутизатора или замена коммутатора в это время?

Проверьте использование полосы пропускания на сумму, приобретенную у вашего интернет-провайдера. Бывают ли дни дня, когда вы приближаетесь к этому пределу? Можете ли вы получить графики использования полосы пропускания? Посмотрите, могут ли преждевременные окончания коррелировать с использованием высокой пропускной способности, особенно если это приближается к известному пределу. Кажется, проблема заключается в том, чтобы выбирать файлы меньшего размера и на больших файлах только тогда, когда они почти полностью загружаются? Покупка большей пропускной способности у вашего интернет-провайдера может решить проблему.