Я использую Apache HttpClient 4.1.2 для отправки сжатых двоичных данных (сериализованных объектов Java) на сервер.
Иногда (20% времени) клиент теряет время ожидания при получении ответа, даже после того, как сервер правильно ответил и зарегистрировал ответ «200» в своей собственной регистрации.
Последовательность событий:
- клиент отправляет данные на сервер (T0).
- сервер регистрирует получение данных (T2, то есть T + 2 секунды).
- сервер обрабатывает данные.
- Сервер регистрирует успешное завершение обработки (T45).
- журнал доступа к серверу показывает, что завершенный ответ выходит с состоянием «200» (T46).
- клиент блокирует чтение заголовков ответов.
- время ожидания клиента (T1800, т. Е. Через 30 минут после запроса POSTing, что является стандартным временем ожидания, которое я использую).
Тело ответа, которое возвращает сервер, представляет собой небольшую, например, пять байтов или менее, текстовую строку, например "OK".
Что здесь может происходить? Я мог бы понять время ожидания, если сервер не ответил; но сервер ответил и записал правильный ответ своевременно, задолго до истечения времени ожидания клиента. Кажется, что клиент «пытается» прочитать ответ, но блокирует и, в конце концов, время ожидания истекло.
Клиент работает на компьютере с Windows XP; сервер является Ubuntu. Оба работают под управлением Java 6 (прямо сейчас 1.6.29).
Я создаю новый объект DefaultHttpClient
при каждом запросе и закрываю его (и освобождаю другие ресурсы соответствующим образом) после каждого запроса.
Клиент потребляет и удаляет тело объекта ответа после успешного завершения запроса, но мы еще не достигли этого момента - истекло время ожидания в контексте вызова httpclient.execute
(метода).
Трассировка стека:
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:149)
at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:110)
at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:264)
at org.apache.http.impl.conn.LoggingSessionInputBuffer.readLine(LoggingSessionInputBuffer.java:115)
at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:98)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:252)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:281)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:247)
at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:219)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:298)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:645)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:464)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at foo.StreamerClient.sendRequest(StreamerClient.java:312)
at foo.StreamerClient.compressAndPostBinaryDataToFooServer(StreamerClient.java:287)
at foo.StreamerClient.compressAndPostObjectsToFooServer(StreamerClient.java:238)
Вот регистрация уровня проводки из успешного запроса. Единственное отличие от неудачных запросов заключается в том, что неудачные запросы останавливаются после регистрации двоичных данных, а через полчаса снова всплывают и регистрируют тайм-аут.
[12-06 14:07:22.359][scheduler-3] D DefaultClientConnection Sending request: POST /foo/bar HTTP/1.1
[12-06 14:07:22.359][scheduler-3] D wire >> "POST /foo/bar HTTP/1.1[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "Accept-Encoding: gzip,deflate[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "Content-Type: application/octet-stream[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "Content-Length: 401[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "Host: foo.com[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "Connection: Keep-Alive[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "User-Agent: Apache-HttpClient/4.1.2 (java 1.5)[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "Authorization: Basic fobar[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "[\r][\n]"
[12-06 14:07:22.359][scheduler-3] D wire >> "[several lines of binary data]"
[12-06 14:07:24.265][scheduler-3] D wire << "HTTP/1.1 200 OK[\r][\n]"
[12-06 14:07:24.265][scheduler-3] D wire << "Date: Tue, 06 Dec 2011 03:07:23 GMT[\r][\n]"
[12-06 14:07:24.265][scheduler-3] D wire << "Content-Type: text/plain;charset=ISO-8859-1[\r][\n]"
[12-06 14:07:24.265][scheduler-3] D wire << "Content-Length: 2[\r][\n]"
[12-06 14:07:24.265][scheduler-3] D wire << "Connection: close[\r][\n]"
[12-06 14:07:24.265][scheduler-3] D wire << "[\r][\n]"
Спасибо.