[英]Java OKHTTP SocketTimeoutException with concurrent multithreaded requests
My Java application uses a variety of proxy servers to collect data from a particular domain.我的 Java 应用程序使用各种代理服务器从特定域收集数据。 The special application requires the following procedure:
特殊申请需要以下程序:
So that the loading of the information (due to the 5 second pause) doesn't take forever, I work with a total of 400 threads.为了使信息的加载(由于 5 秒暂停)不会永远持续,我总共使用了 400 个线程。 Each of these threads uses its own proxy server, ie also with its own OKHTTP client:
这些线程中的每一个都使用自己的代理服务器,即也使用自己的 OKHTTP 客户端:
MyHTTPClient = new OkHttpClient.Builder()
.connectTimeout(7, TimeUnit.SECONDS)
.writeTimeout(7, TimeUnit.SECONDS)
.readTimeout(7, TimeUnit.SECONDS)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ProxyIP, ProxyPort)))
.proxyAuthenticator((Route route, Response response) - > {
return response.request().newBuilder().header("Proxy-Authorization", Credentials.basic(ProxyUser, ProxyPass)).build();
})
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((String hostname, SSLSession session) - > true)
.addNetworkInterceptor(new LoggingInterceptor())
.retryOnConnectionFailure(true)
.build();
Each thread has to use its own proxy, so each thread has its own OKHTTP client.每个线程都必须使用自己的代理,因此每个线程都有自己的 OKHTTP 客户端。 In total there are 400 OKHTTP clients.
总共有 400 个 OKHTTP 客户端。
Each thread now processes its queries as follows:每个线程现在按如下方式处理其查询:
while (true) {
MyAnswer = MyHTTPClient.newCall(
new Request.Builder().url(https://www.example.com)
.addHeader("referer", SomeReferrer)
.addHeader("cache-control", "no-cache")
.addHeader("pragma", "no-cache")
.get().build())
.execute();
Body = MyAnswer.body().string();
MyAnswer.body().close();
Thread.sleep(5000);
}
And that works great too, for about a minute.这也很有效,大约一分钟。 Then suddenly the following error messages appear for each individual request on every single thread:
然后突然为每个线程上的每个单独请求出现以下错误消息:
java.net.SocketTimeoutException: connect timed out
at java.base/java.net.PlainSocketImpl.waitForConnect(Native Method)
at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:107)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.base/java.net.Socket.connect(Socket.java:608)
at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:120)
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
at okhttp3.internal.connection.RealConnection.connectTunnel(RealConnection.kt:261)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:201)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
Caused by: java.net.SocketTimeoutException: Read timed out
at java.base/java.net.SocketInputStream.socketRead0(Native Method)
at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
at okio.InputStreamSource.read(JvmOkio.kt:90)
at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
... 22 more
WHAT I TRIED SO FAR我到目前为止所做的尝试
I've done a bit of research and found out that there might be some kind of limit in terms of concurrent connections.我做了一些研究,发现在并发连接方面可能存在某种限制。 I found out, that whenever this error occurs, there are no idle connections in the connection pool:
我发现,每当发生此错误时,连接池中都没有空闲连接:
MyHTTPClient.connectionPool().idleConnectionCount() //Always 0 when the Timeout-Exception occurs
So i tried to increase the size of the connection pool for every single okhttpclient but that seemed to have absolutely no effect:因此,我尝试为每个 okhttpclient 增加连接池的大小,但这似乎完全没有效果:
.connectionPool(new ConnectionPool(5000, 100, TimeUnit.MILLISECONDS))
I also tried to increase and decrease the timeout-values of the httpclient and that actually seemed to make a difference in terms of how long the application would run without this error but it actually didn't prevent this to happen.我还尝试增加和减少 httpclient 的超时值,这实际上似乎对应用程序在没有此错误的情况下运行的时间产生了影响,但实际上并没有阻止这种情况的发生。
I also tried to increase the amount of simultaneous connections and decrease the amount of time a connection stays in "TIME_WAIT" status as mentioned here: https://docs.microsoft.com/en-us/answers/questions/482793/tcpip-cuncurrent-connections.html我还尝试增加同时连接的数量并减少连接保持在“TIME_WAIT”状态的时间,如下所述: https : //docs.microsoft.com/en-us/answers/questions/482793/tcpip- cuncurrent-connections.html
I also tried to add a Dispatcher to the OKHTTPClient, as follows:我也尝试在OKHTTPClient中添加一个Dispatcher,如下:
Dispatcher MyDispatcher = new Dispatcher(Executors.newCachedThreadPool());
MyDispatcher.setMaxRequests(9999999);
MyDispatcher.setMaxRequestsPerHost(9999999);
If you have any ideas about what could be the cause or what else I could try, please let me know.如果您对可能的原因或我可以尝试的其他方法有任何想法,请告诉我。 I am also happy to send you further information, if needed.
如果需要,我也很乐意向您发送更多信息。
Thank you in advance!先感谢您!
Create one OkHttpClient initially and then use OkHttpClient.newBuilder()
to customize the proxy.首先创建一个 OkHttpClient,然后使用
OkHttpClient.newBuilder()
自定义代理。 This will cause the clients to share thread pools and connection pools.这将导致客户端共享线程池和连接池。 That might not fix your problem on its own, but it'll make it more efficient.
这本身可能无法解决您的问题,但会使其更有效率。
final OkHttpClient sharedHttpClient = new OkHttpClient.Builder()
.connectTimeout(7, TimeUnit.SECONDS)
.writeTimeout(7, TimeUnit.SECONDS)
.readTimeout(7, TimeUnit.SECONDS)
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((String hostname, SSLSession session) - > true)
.addNetworkInterceptor(new LoggingInterceptor())
.retryOnConnectionFailure(true)
.build();
MyHTTPClient = sharedHttpClient.newBuilder()
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ProxyIP, ProxyPort)))
.proxyAuthenticator((Route route, Response response) - > {
return response.request().newBuilder().header("Proxy-Authorization", Credentials.basic(ProxyUser, ProxyPass)).build();
})
.build();
I have met a similar situation last day.我昨天遇到了类似的情况。 Here are my ideas about these problem:
以下是我对这些问题的看法:
I have a little trick to accomplish this goal: Change the settings of timeout in OkHttpClient.Builder()
, let different kind of timeout vary from each one others.我有一个小技巧来实现这个目标:更改
OkHttpClient.Builder()
的超时设置,让不同类型的超时彼此不同。 And then print the actual timeout duration in log, so you can find out which one it truely match.然后在日志中打印实际超时持续时间,以便您可以找出它真正匹配的那个。
# each state of connection
netstat -n| awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
# connection to specifed port
netstat -ntap|grep :PORT
Check the response time in server side.检查服务器端的响应时间。 Depends on your web container, you can see if there is any request take too long to return.
取决于您的 Web 容器,您可以查看是否有任何请求需要太长时间才能返回。 But it may not be your answer, since you have confirm another computor doesn't have the same issue.
但这可能不是您的答案,因为您已确认另一台计算机没有同样的问题。
Check the network itself.检查网络本身。 Use this script to check if any package take too long(
-w
param specified the timeout duration) to return:使用此脚本检查是否有任何包花费太长时间(
-w
param 指定超时持续时间)返回:
for i in {1..10000}; do nc -vnz IP PORT -w 1 2>&1 |grep "timed out"; done
That's all, hope that may help you.就这些,希望能帮到你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.