Java-клиент S3 часто терпит неудачу из-за «преждевременного окончания тела сообщения с разделителями-длинами» или «java.net.SocketException Socket closed» - PullRequest
12 голосов
/ 31 марта 2012

У меня есть приложение, которое много работает на 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 (файл)) . Я использую последнюю версию Java-клиента Amazon S3, и этот вызов повторяется четыре раза, прежде чем сдаться. Итак, после четырех попыток это все равно не получается.

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

Ответы [ 6 ]

15 голосов
/ 09 мая 2012

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

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

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

3 голосов
/ 10 апреля 2012

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

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

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

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

1 голос
/ 05 апреля 2012

Прежде всего, ваш код работает полностью нормально, если (и только если) вы испытываете проблемы с подключением между вами и 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 )

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

0 голосов
/ 07 апреля 2012

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

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

0 голосов
/ 07 апреля 2012

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

0 голосов
/ 04 апреля 2012
  1. Попробуйте использовать wireshark , чтобы увидеть, что происходит на проводе, когда это происходит.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...