AWS SDK S3 Socket Закрытое исключение

В моем приложении используется около 10 потоков, каждый из которых составляет 7000 запросов на отправку по S3 в минуту. (Я запускаю его на мощном блоке 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)

Запросы на размещение выполняются асинхронно, используя AWS SDK TransferManager. Я полагаю, что в то время, когда требуется, чтобы один запрос был полностью заполнен, около 10 были сделаны асинхронно.

Исходя из этого исключения, я нашел две возможные причины:

  • Предел MaxConnections. Я поднял его по умолчанию от 50 до 3000, но безрезультатно.
  • Преждевременный сбор мусора. Я попытался сохранить ссылку на объекты Upload, возвращаемые TransferManager (в параллельной очереди), и опять же никакой помощи.

Как я могу это исправить? Опять же, приложение работает хорошо около часа, но, последовательно, ударяет по этой стене примерно через час. (Я работаю на Amazon AMI Linux на EC2.)

Update

  • Никакой код, отличный от SDK SDK, не касается сокетов или даже не знает о них. Вся работа HTTP выполняется исключительно через AWS SDK.
  • Итак, если что-то закрывает их, это должно быть что-то в SDK AWS.
  • Код работает на сервере EC2; нет никаких оснований ожидать каких-либо проблем с подключением к сети между EC2 и S3, и, конечно, нет причин, по которым они должны происходить предсказуемо (через час в перспективе) каждый раз

Ответ 1

Я не уверен, что это ответ, но http://docs.aws.amazon.com/AmazonS3/latest/dev/request-rate-perf-considerations.html утверждает, что ", если вы ожидаете быстрого увеличения скорость запроса для ведра до более чем 300 запросов PUT/LIST/DELETE в секунду или более 800 запросов GET в секунду, мы рекомендуем открыть окно поддержки для подготовки к рабочей нагрузке и избежать временных ограничений по вашей ставке запроса" . Возможно, поскольку я превысил лимит, AWS начинает прерывать соединения; SDK, обнаруживая разъемы IDLE, закрывает их, и, вуаля!, мы получаем исключения.

ОБНОВЛЕНИЕ: Не уверен, что это правильно. Amazon, похоже, заявляет, что в этом случае вы получите явное сообщение об ошибке "Slow Down", а не неожиданное закрытие. Итак, головоломка остается.

Ответ 2

Исключение - это SocketException, вызванное методом setSoTimeout() в java.net.Socket(см. трассировку стека). Метод можно посмотреть здесь: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/net/Socket.java#Socket.setSoTimeout%28int%29

Возможная причина может заключаться в том, что запросы на S3 все еще ожидаются/неполны, в результате чего поток ожидает(). Как только время ожидания превысит тайм-аут сокета, сокет закрывается и генерируется исключение.

Ответ 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)

Ответ 4

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