Я использую OkHttp 3.5.0 для тестирования веб-приложения под нагрузкой. С помощью него я отправляю тысячи запросов на один и тот же адрес.
В доках OkHttp сказано что он использует пул соединений чтобы оптимизировать производительность. Однако если глянуть
netstat
, то мы там увидим тысячи соединений в состоянии TIME_WAIT:
TCP 127.0.0.1:80 127.0.0.1:51752 TIME_WAIT
TCP 127.0.0.1:80 127.0.0.1:51753 TIME_WAIT
TCP 127.0.0.1:80 127.0.0.1:51754 TIME_WAIT
TCP 127.0.0.1:80 127.0.0.1:51755 TIME_WAIT
TCP 127.0.0.1:80 127.0.0.1:51756 TIME_WAIT
...
То есть соединения почему-то закрываются и не переиспользуются.
Connection: keep-alive
никак не влияет.
И после нескольких тысяч запросов всё начинает падать т.к. не может получить свободный порт:
SocketException: No buffer space available (maximum connections reached?)
Код клиента (Kotlin):
val client = OkHttpClient.Builder()
.connectionPool(ConnectionPool(5, 1, TimeUnit.MINUTES))
.build()
val request = Request.Builder().url("http://192.168.0.50").build()
while (true) {
val response = client.newCall(request).execute()
response.close()
}
Если написать
response.body().string()
вместо
response.close()
, то
SocketException
выбрасываться перестанет, всё вроде будет работать, но по-прежнему будут создаваться тысячи соединений TIME_WAIT, и производительность будет сильно проседать.
Где косяк? Почему OkHttp не переиспользует соединения?
PS: При этом Apache HttpClient работает хорошо (у него есть специальный пул
PoolingHttpClientConnectionManager
). Но хочется разобраться что не так с OkHttp.