第一次出現:是thrift的python client去請求server,發現偶爾出現這個問題
第二次:接入第三方的api,去請求數據時,發現一個接入方的api第一次總是報這個錯,當時又沒有做處理,導致獲得信息置空,入緩存后數據就是錯誤的。做了一個更改就是retry三次,得到解決。
第三次:最近去抓appstore的應用指數又重新出現該問題,使用HttpRequestRetryHandler 重試,設置到20次都無一次成功。
堆棧錯誤信息:
[app][index-error]: ScreenAnts HD ; priority empty 2014-01-26 14:59:30,668 - I/O exception (java.net.SocketException) caught when processing request: Connection reset 2014-01-26 14:59:30,703 - Retrying request 2014-01-26 14:59:30,668 - [SimpleHttpClient] myRetryHandler, IOException:Connection reset 2014-01-26 14:59:30,668 - I/O exception (java.net.SocketException) caught when processing request: Connection reset 2014-01-26 14:59:30,704 - Retrying request 2014-01-26 14:59:30,668 - I/O exception (java.net.SocketException) caught when processing request: Connection reset 2014-01-26 14:59:30,704 - Retrying request 2014-01-26 14:59:30,704 - [SimpleHttpClient] myRetryHandler, IOException:Connection reset 2014-01-26 14:59:30,704 - [SimpleHttpClient] read http://search.itunes.apple.com/WebObjects/MZSearchHints.woa/wa/hints?q=Deadliest+Animals failed java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:185) at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:136) at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:152) at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:270) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:140) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57) at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260) at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:161) at sun.reflect.GeneratedMethodAccessor19.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:616) at org.apache.http.impl.conn.CPoolProxy.invoke(CPoolProxy.java:138) at $Proxy7.receiveResponseHeader(Unknown Source) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:271) at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:253) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:194) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:85) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106) at com.fanxer.aso.index.utils.SimpleHttpClient.getContent(SimpleHttpClient.java:135) at com.fanxer.aso.index.task.AppIndexTask.getXmlBytesFromSearchLink(AppIndexTask.java:163) at com.fanxer.aso.index.task.AppIndexTask.access$000(AppIndexTask.java:40) at com.fanxer.aso.index.task.AppIndexTask$1.call(AppIndexTask.java:98) at com.fanxer.aso.index.task.AppIndexTask$1.call(AppIndexTask.java:93) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:679)
http://bbs.csdn.net/topics/210061352 解釋了四種socket異常:
java.net.SocketException: (Connection reset或者Connect reset by peer:Socket write error)。該異常在客戶端和服務器端均有可能發生,引起該異常的原因有兩個,第一個就是如果一端的Socket被關閉(或主動關閉或者因為異常退出而引起的關閉),另一端仍發送數據,發送的第一個數據包引發該異常(Connect reset by peer)。另一個是一端退出,但退出時並未關閉該連接,另一端如果在從連接中讀數據則拋出該異常(Connection reset)。簡單的說就是在連接斷開后的讀和寫操作引起的。
經多次測試發現,50個線程並發,最大的連接時間超過了90秒,平均請求結果僅有400KB,很奇怪的現象。猜測是appstore端連接時間過長直接斷開連接(是我被連90s也要斷啊)。修改下超時,只能讓請求更快恢復,
RetryExec.execute 時仍然無法正常連接。
查看源碼,InternalHttpClient繼承了CloseableHttpClient 實現了父類的抽象方法
protected abstract CloseableHttpResponse doExecute(HttpHost target, HttpRequest request,
HttpContext context) throws IOException, ClientProtocolException;
對request做了封裝,host、config和route確定后,轉入execChain
execChain是一系列責任鏈
RedirectExec ->RetryExec ->ProtocolExec->MainClientExec
轉給 HttpRequestExecutor 執行請求, 通過DefaultBHttpClientConnection把結果寫入response,看程序沒發現問題,終於無意中使用curl做測試,發現也是失敗
curl: (56) Failure when receiving data from the peer
目前只能通過降低請求頻率或優化降低請求次數或者發現錯誤時多停頓一段時間去解決。