Я годами неправильно пользовался HttpClient, но в итоге наступил кошмар. Мой сайт был нестабильным, клиенты были очень злы, и с помощью простого исправления производительность значительно улучшилась, а нестабильность исчезла.
В то же время я действительно улучшил производительность своего приложения, используя более эффективное использование сокетов.
Микросервисы могут быть сложной задачей. По мере добавления новых сервисов и распада монолитных приложений между сервисами появляется всё больше путей коммуникации. Существует множество вариантов связи, но HTTP — очень популярный вариант. Если микросервис построен на C# или любом другом языке .NET, скорее всего, вы уже используете HttpClient.
Проблема в том, что
Оператор using — это функция C#, которая обрабатывает одноразовые объекты. После завершения использования блока одноразовый объект (в данном случае HttpClient) выходит из сферы действия и уничтожается. Позвоните в службу утилизации и уберите используемые ресурсы. Это очень типичный шаблон в .NET, который мы используем для всего — от базы данных до flow writer. Фактически, любой объект с внешним ресурсом, который необходимо очистить, использует этот интерфейс IDisposable.
И тебя нельзя винить за то, что хочешь завернуть его в употребление. Во-первых, это считается хорошей практикой. Фактически, официальная документация Microsoft использует:
В целом, при использовании IDisposable объекта он должен быть объявлен и инстанциран в операторе use. Во-вторых, весь код, который вы могли видеть...... В начале HttpClient будет указано использовать блок операторов использования, включая последнюю документацию ASP.NET самом сайте. То же самое говорится в статье в интернете.
Но HttpClient — это другое. Хотя он реализует интерфейс IDisposable, на самом деле это общий объект. Это значит, что за кулисами он находится в режиме реэнтранта и безопасна для потоков. Вам следует делить экземпляр HttpClient на протяжении всего срока жизни приложения, а не создавать новый экземпляр для каждой запусковой системы. HttpClient, давайте посмотрим почему.
Убедитесь сами
Вот простая программа для демонстрации HttpClient:
Это будет адресовано http://aspnetmonsters.comОткроем 10 запросов и делаем GET, просто выводим статус кода, чтобы знать, что всё работает. Результат будет следующим:
Погоди, это ещё не всё!
Вся работа и всё это правильно для мира. Но это не так. Если мы вытащим инструмент netstat и посмотрим состояние сокета на машине, которая его запускает, мы увидим:
C:\code\socket>NETSTAT.EXE ... Прото-местный адрес — государство иностранного адреса TCP 10.211.55.6:12050 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12051 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12053 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12054 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12055 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12056 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12057 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12058 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12059 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12060 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12061 waws-prod-bay-017:http TIME_WAIT TCP 10.211.55.6:12062 waws-prod-bay-017:http TIME_WAIT TCP 127.0.0.1:1695 SIMONTIMMS742B:1696 СОЗДАНО ... Ну, это странно...... Приложение вышло из игры, но до компьютера Azure, где размещается сайт ASP.NET Monsters, всё ещё открыто множество таких соединений. Они внутриTIME_WAITстатус, что означает, что соединение с одной стороны (наше) закрыто, но мы всё ещё ждём, не поступят ли другие пакеты, так как они могли где-то задержаться в сети. Вот схема статуса TCP/IP:
Windows останется подключённым в этом состоянии 240 секунд (в соответствии с установкой [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]). В Windows есть ограничение на скорость открытия нового сокета, поэтому если у вас закончатся пулы соединений, вы можете увидеть такую ошибку:
Не удаётся подключиться к удалённому серверу
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted. Поиск в Google даст вам плохие советы по сокращению тайм-аутов соединения. На самом деле, при правильном запуске на сервере с HttpClient или аналогичным приложением сокращение тайм-аутов может привести к другим негативным последствиям. Нам нужно понять, что значит «правильно», и решить основную проблему, а не возиться с машинными переменными.
Почините
Если мы поделимся экземпляром HttpClient, то можем сократить отходы сокетов, повторно используя их:
Обратите внимание, что для всего приложения у нас есть только один общий экземпляр. HttpClient всё ещё работает как раньше (на самом деле немного быстрее из-за повторного использования сокета). Netstat теперь показывает только:
TCP 10.211.55.6:12254 waws-prod-bay-017:http УСТАНОВЛЕН В производственной ситуации мое среднее количество сокетов около 4000, а пик достигает более 5000, что фактически выжимает доступные ресурсы на сервере и приводит к сбою сервиса. После внедрения изменений количество используемых соёмов сократилось с более чем 4000 до стабильно менее 400, обычно около 100.
Это часть диаграммы из нашего инструмента мониторинга, которая показывает, что происходит после развертывания ограниченного количества доказательств исправлений в выбранном числе микросервисов.
Это было драматично. Если у вас есть какая-либо нагрузка, нужно учитывать следующие два момента:
Сделайте ваш HttpClient статичным. Не отбрасывайте и не упаковывайте своё использование, если только вы специально не ищете конкретное поведение (например, сбой сервиса). HttpClient
сводка
Проблема с истощением гнезда, с которой мы боролись уже несколько месяцев, исчезла, и у наших клиентов есть виртуальный парад. Я не могу недооценивать, насколько неочевидна эта ошибка. За эти годы мы привыкли работать с реализованными объектами, IDisposable, и многие инструменты рефакторинга, такие как R# и CodeRush, на самом деле предупреждают вас, если вы этого не делаете. В этом случае избавление от HttpClient — неправильный подход. HttpClient реализует IDisposable и поощряет плохое поведение, к сожалению
Исходный текст:Вход по гиперссылке виден.
|