Этот кусок кода выглядит нормально для вас?
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) url.openConnection();
try (InputStream in = url.getInputStream()) {
return streamToString(in);
}
} finally {
if (connection != null) connection.disconnect();
}
Выглядит хорошо — он открывает соединение, читает из него, закрывает входной поток, освобождает соединение, и все. Но, выполняя некоторые тесты производительности и пытаясь выяснить проблему узкого места, мы обнаружили, что disconnect()
это не так безобидно, как кажется — когда мы прекратили отключать наши соединения, было в два раза больше исходящих соединений. Вот этот Javadoc:
Указывает, что другие запросы к серверу маловероятны в ближайшем будущем. Вызов disnect () не должен подразумевать, что этот экземпляр HttpURLConnection может быть повторно использован для других запросов.
И в классе:
Вызов метода disconnect () может закрыть базовый сокет, если постоянное соединение в это время не используется.
Это все еще неясно, но дает нам намек на то, что есть нечто большее. После прочтения пары ответов stackoverflow и java.net ( 1 , 2 , 3 , 4 ), а также документации Android того же класса, которая фактически отличается от реализации Oracle, оказывается, что она .disconnect()
фактически закрывается (или может закрываться, в случае андроида) основной сокет.
Затем мы можем найти эту часть документации (она связана с javadoc, но не сразу очевидно, что это важно при вызове connect), что дает нам полную картину:
keep.alive
Свойство ( по умолчанию: правда) указывает на то, что сокеты могут быть повторно использованы в последующих запросах. Это работает, оставляя соединение с сервером (который поддерживает поддержание активности) открытым, и тогда больше не нужны накладные расходы на открытие сокета. По умолчанию до 5 таких сокетов используются повторно (для каждого пункта назначения). Вы можете увеличить размер пула, установив http.maxConnections
свойство. Однако после увеличения до 10, 20 и 50 видимых улучшений в количестве исходящих запросов не произошло.
Однако, когда мы перешли от HttpURLConnection
к Apache HTTP — клиент , с объединенном диспетчера соединений, у нас было в 3 раза больше исходящих соединений в секунду. И это без тонкой настройки.
Нагрузочное тестирование, то есть бомбардировка целевого сервера как можно большим количеством запросов, звучит как ниша. Но на самом деле, если ваше приложение вызывает веб-сервис, либо в вашем стеке, либо во внешнем, как часть каждого запроса, у вас возникает та же проблема — вы сможете делать меньше запросов в секунду к целевому серверу, и, следовательно, отвечайте на меньшее количество запросов в секунду для ваших пользователей.
The advice here is: almost always prefer apache http client – it has a way better API and it seems way better performance, without the need to understand how exactly it functions underneath. But be careful of the same caveats there as well – check pool size and connection reuse. If using HttpURLConnection
, do not disconnect your connections after you read their response, consider increasing the socket pool size, and be careful of related problems.