Olen käyttänyt HttpClientia väärin vuosia, mutta lopulta painajainen tuli. Verkkosivustoni oli epävakaa ja asiakkaani olivat hyvin vihaisia, ja yksinkertaisella korjauksella suorituskyky parani huomattavasti ja epävakaus poistui.
Samaan aikaan paransin sovellukseni suorituskykyä tehokkaammalla socketin käytöllä.
Mikropalvelut voivat olla vaikea ongelma käsitellä. Kun palveluita lisätään ja monoliittisia sovelluksia hajotetaan, palveluiden välillä on yhä enemmän viestintäreittejä. Viestintävaihtoehtoja on monia, mutta HTTP on erittäin suosittu vaihtoehto. Jos mikropalvelu on rakennettu C#:lla tai millä tahansa .NET-kielellä, todennäköisesti käytät jo HttpClientia.
Ongelma on
Käyttämislause on C#-ominaisuus, joka käsittelee kertaluonteisia objekteja. Kun käyttölohko on valmis, kertaluonteinen objekti (tässä tapauksessa HttpClient) poistetaan soveltamisalasta ja hylätään. Kutsu hävitysmenetelmä ja siivoa käytetyt resurssit. Tämä on hyvin tyypillinen kuvio .NETissä, jota käytämme kaikkeen tietokannasta virtauskirjoittajaan. Itse asiassa mikä tahansa objekti, jonka ulkoinen resurssi täytyy puhdistaa, käyttää tätä tunnistettavaa rajapintaa.
Eikä sinua voi syyttää siitä, että haluat kietoa sen käyttämiseen. Ensinnäkin sitä pidetään hyvänä käytäntönä. Itse asiassa Microsoftin virallinen dokumentaatio käytti:
Yleisesti ottaen, kun käytetään IDisposable objectia, se tulisi julistaa ja instansoitua using -lauseessa. Toiseksi, kaikki koodi, jonka olet ehkä nähnyt...... HttpClientin alussa kehotetaan käyttämään useus-lauseblokkia, mukaan lukien sivuston uusin dokumentaatio ASP.NET. Sama sanotaan myös internet-artikkelissa.
Mutta HttpClient on erilainen. Vaikka se toteuttaa IDisposable-rajapinnan, se on itse asiassa jaettu objekti. Tämä tarkoittaa, että kulissien takana peli on palaava ja lankaturvallista. Sinun tulisi jakaa HttpClient-instanssi koko sovelluksen elinkaaren ajan, sen sijaan että loisit uuden instanssin jokaiselle suoritukselle. HttpClient, katsotaan miksi.
Katso itse
Tässä on yksinkertainen ohjelma HttpClientin esittelyyn:
Tämä ohjataan osoitteeseen http://aspnetmonsters.comAvaamme 10 pyyntöä ja teemme GET:n, tulostamme vain tilakoodin, jotta tiedämme sen toimivan. Tulos on:
Odota, on vielä lisää!
Kaikki työ ja kaikki on oikein maailmalle. paitsi että se ei ole. Jos otamme netstat-työkalun esiin ja katsomme sitä ajavan koneen socket-tilan, näemme:
C:\code\socket>NETSTAT.EXE ... Proto-paikallinen osoite Ulkomainen osoitetila 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 PERUSTETTU ... No, se on outoa...... Sovellus on poistettu, mutta Azure-koneeseen, joka isännöi ASP.NET Monstersin verkkosivustoa, on edelleen useita tällaisia yhteyksiä. He ovat mukanaTIME_WAITTila, mikä tarkoittaa, että yhteys on suljettu toiselta puolelta (meidän), mutta odotamme edelleen, tuleeko muita paketteja, koska ne ovat saattaneet olla viivästyneitä verkossa jossain vaiheessa. Tässä on kaavio TCP/IP-tilasta:
Windows pysyy yhteydessä tässä tilassa 240 sekunnin ajan (kuten asetetaan [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]). Windowsilla on rajoitus sille, kuinka nopeasti voit avata uuden socketin, joten jos yhteyspoolit loppuvat, saatat nähdä tällaisen virheen:
Ei pysty yhdistämään etäpalvelimeen
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted. Googlen haku antaa huonoja neuvoja yhteyden aikakatkaisujen lyhentämiseen. Itse asiassa, kun palvelimella HttpClient tai vastaavasti rakennettu sovellus toimii oikein, aikakatkaisujen lyhentäminen voi johtaa muihin haitallisiin seurauksiin. Meidän täytyy ymmärtää, mitä "oikea" tarkoittaa, ja ratkaista taustalla oleva ongelma, ei säätää koneen tason muuttujia.
Korjaa se
Jos jaamme HttpClient-instansin, voimme vähentää socket-hukkaa käyttämällä niitä uudelleen:
Huomaa, että koko sovelluksessa meillä on vain yksi jaettu instanssi. HttpClient toimii edelleen kuten ennen (itse asiassa hieman nopeampi socketin uudelleenkäytön takia). Netstat näyttää nyt vain:
TCP 10.211.55.6:12254 waws-prod-bay-017:http PERUSTETTU Tuotantotilanteessa sokettimääräni on keskimäärin noin 4000 ja huipentuu yli 5000:een, mikä käytännössä puristaa palvelimen käytettävissä olevat resurssit ja aiheuttaa palvelun kaatumisen. Muutoksen jälkeen käytössä olevien pistorasioiden määrä laski keskimäärin yli 4000:sta johdonmukaisesti alle 400:aan, tyypillisesti noin 100:aan.
Tämä on osa seurantatyökalumme kaaviota, joka näyttää, mitä tapahtuu sen jälkeen, kun olemme ottaneet käyttöön rajallisen määrän korjaustodisteita valitulle määrälle mikropalveluita.
Se oli dramaattista. Jos sinulla on minkäänlainen kuorma, sinun tulee pitää nämä kaksi asiaa mielessä:
Tee HttpClientistasi staattinen. Älä hylkää tai paketoi käyttöäsi, ellei sinulla ole nimenomaista haetaan tiettyä käyttäytymistä (kuten palvelun epäonnistumista). HttpClient
yhteenveto
Hylsyjen uupumisongelma, jonka kanssa olemme kamppailleet kuukausia, on poissa, ja asiakkaillamme on virtuaalinen paraati. En voi aliarvioida, kuinka ilmeinen tämä virhe on. Vuosien varrella olemme tottuneet käsittelemään toteutettuja objekteja, IDisposablea, ja monet refaktorointityökalut kuten R# ja CodeRush varoittavat, jos et tee niin. Tässä tapauksessa HttpClientin hävittäminen on väärä lähestymistapa. HttpClient toteuttaa IDisposablen ja kannustaa huonoon käytökseen, mikä on valitettavaa
Alkuperäinen:Hyperlinkin kirjautuminen on näkyvissä.
|