Že leta uporabljam HttpClient nepravilno, a na koncu je prišla nočna mora. Moja spletna stran je bila nestabilna, stranke zelo jezne, z enostavno rešitvijo pa se je zmogljivost močno izboljšala in nestabilnost odpravila.
Hkrati sem dejansko izboljšal zmogljivost svoje aplikacije z učinkovitejšo uporabo socketov.
Mikroservisi so lahko zahtevna težava za reševanje. Ko se doda več storitev in se razgradijo monolitne aplikacije, je običajno vedno več komunikacijskih poti med storitvami. Obstaja veliko možnosti za komunikacijo, vendar je HTTP zelo priljubljena možnost. Če je mikroservis zgrajen v C# ali katerem koli .NET jeziku, je velika verjetnost, da že uporabljate HttpClient.
Težava je
Ukaz using je funkcija C#, ki obravnava enkratne objekte. Ko je uporaba bloka končana, je enkratni objekt (v tem primeru HttpClient) izven obsega in odstranjen. Pokliči metodo odstranjevanja in očisti vse uporabljene vire. To je zelo tipičen vzorec v .NET, ki ga uporabljamo za vse od baze podatkov do pisalnika tokov. Pravzaprav vsak objekt z zunanjim virom, ki ga je treba očistiti, uporablja ta IDisposable vmesnik.
In ne moreš biti kriv, če želiš to zaviti v uporabo. Prvič, to velja za dobro prakso. Pravzaprav Microsoftova uradna dokumentacija uporablja:
Na splošno je treba pri uporabi IDisposable objekta ta deklarirati in instancirati v ukazu upotrebe. Drugič, vsa koda, ki ste jo morda videli...... Začetek HttpClient vam bo povedal, da uporabite blok ukazov upotrebovanja, vključno z najnovejšo dokumentacijo ASP.NET sami strani. Enako je zapisano v članku na internetu.
A HttpClient je drugačen. Čeprav implementira IDisposable vmesnik, je v resnici deljeni objekt. To pomeni, da je v ozadju ponovna in varna za teme. Skozi celotno življenjsko dobo aplikacije bi morali deliti instanco HttpClient, namesto da za vsako izvedbo ustvarjate novo instanco. HttpClient, poglejmo zakaj.
Prepričaj se sam
Tukaj je preprost program za prikaz HttpClient:
To bo usmerjeno na http://aspnetmonsters.comOdpremo 10 zahtevkov in naredimo GET, natisnemo samo statusno kodo, da vemo, da deluje. Izhod bo:
Počakaj, je še več!
Vse delo in vse je prav za svet. razen da ni. Če vzamemo orodje netstat in pogledamo stanje socketa na računalniku, ki ga poganja, bomo videli:
C:\code\socket>NETSTAT.EXE ... Proto Lokalni naslov Tuji naslov Država 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 USTANOVLJEN ... No, čudno je...... Aplikacija je zaključena, vendar je še vedno veliko teh povezav odprtih do Azure računalnika, ki gosti spletno stran ASP.NET Monsters. So notriTIME_WAITstatus, kar pomeni, da je povezava na eni strani (naša) zaprta, vendar še vedno čakamo, če pridejo še kakšni drugi paketi, ker so morda bili na omrežju kje zamujani. Tukaj je diagram stanja TCP/IP:
Windows ostanejo povezani v tem stanju 240 sekund (kot je nastavljeno z nastavitvijo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]). Windows ima omejitev, kako hitro lahko odprete novo vtičnico, tako da če vam zmanjka povezovalnih bazenov, se lahko pojavi napaka, kot je ta:
Ni mogoče vzpostaviti povezave z oddaljenim strežnikom
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted. Če ga poiščete na Googlu, boste dobili slab nasvet glede zmanjšanja časovnih izpadov povezave. Pravzaprav lahko zmanjšanje časovnih omejitev, če se strežnik pravilno izvaja na strežniku s HttpClient ali podobno zasnovano aplikacijo, povzroči tudi druge negativne posledice. Moramo razumeti, kaj pomeni "prav" in rešiti osnovni problem, ne pa se ukvarjati s strojnimi spremenljivkami.
Popravi to
Če delimo instanco HttpClient, lahko zmanjšamo odpadke vtičnikov z njihovo ponovno uporabo:
Upoštevajte, da imamo za celotno aplikacijo le eno skupno instanco. HttpClient še vedno deluje kot prej (pravzaprav nekoliko hitreje zaradi ponovne uporabe socketov). Netstat zdaj prikazuje samo:
TCP 10.211.55.6:12254 waws-prod-bay-017:http VZPOSTAVLJENO V produkcijskem scenariju je povprečno število vtičnic okoli 4000 in doseže vrh pri več kot 5000, kar učinkovito iztisne razpoložljive vire na strežniku in povzroči sesutje storitve. Po uvedbi spremembe se je število uporabljenih vtičnic zmanjšalo s povprečno več kot 4000 na dosledno manj kot 400, običajno okoli 100.
To je del grafikona našega orodja za spremljanje, ki prikazuje, kaj se zgodi po namestitvi omejenega števila dokazov popravkov na izbrano število mikroservisov.
Bilo je dramatično. Če imate kakršnokoli obremenitev, morate imeti v mislih ti dve stvari:
Naj bo vaš HttpClient statičen. Ne zavračaj ali pakiraj svoje uporabe, razen če izrecno iščeš določeno vedenje (na primer povzročiti odpoved storitve). HttpClient
Povzetek
Težava z izčrpanostjo vtičnice, s katero se borimo že mesece, je izginila, naše stranke pa imajo virtualno parado. Ne morem podcenjevati, kako neočitna je ta napaka. Skozi leta smo bili vajeni delati z implementiranimi objekti, IDisposable, in številna orodja za refaktoriranje, kot sta R# in CodeRush, vas dejansko opozorijo, če tega ne storite. V tem primeru je odstranitev HttpClient napačen pristop. HttpClient implementira IDisposable in spodbuja slabo vedenje, kar je žalostno
Izvirno:Prijava do hiperpovezave je vidna.
|