Я неправильно користувався 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.
Це частина діаграми з нашого інструменту моніторингу, яка показує, що відбувається після розгортання обмеженої кількості proofproofs для вибраної кількості мікросервісів.
Це було драматично. Якщо у вас є будь-яке навантаження, слід пам'ятати про ці дві речі:
Зробіть свій HttpClient статичним. Не відкидайте і не пакуйте своє використання, якщо тільки ви не шукаєте конкретну поведінку (наприклад, спричинити збій вашого сервісу). HttpClient
зведення
Проблема виснаження суглобів, з якою ми боремося місяцями, зникла, і наші клієнти мають віртуальний парад. Я не можу недооцінювати, наскільки ця помилка неочевидна. За ці роки ми звикли працювати з реалізованими об'єктами, IDisposable, і багато інструментів рефакторингу, таких як R# і CodeRush, насправді попереджають, якщо ви цього не зробите. У цьому випадку позбавлення HttpClient є неправильним підходом. HttpClient реалізує IDisposable і заохочує погану поведінку, на жаль
Оригінальний:Вхід за гіперпосиланням видно.
|