Jeg har brukt HttpClient feil i flere år, men til slutt kom marerittet. Nettstedet mitt var ustabilt og kundene mine var veldig sinte, og med en enkel løsning ble ytelsen betydelig forbedret og ustabiliteten ble eliminert.
Samtidig forbedret jeg faktisk ytelsen til applikasjonen min med mer effektiv bruk av socketen.
Mikrotjenester kan være et vanskelig problem å håndtere. Etter hvert som flere tjenester legges til og monolittiske applikasjoner brytes ned, blir det en tendens til å bli flere og flere kommunikasjonsveier mellom tjenestene. Det finnes mange kommunikasjonsmuligheter, men HTTP er et veldig populært alternativ. Hvis mikrotjenesten er bygget i C# eller et annet .NET-språk, er sjansen stor for at du allerede bruker HttpClient.
Problemet ligger
Useding-setningen er en C#-funksjon som håndterer engangsobjekter. Når den brukende blokken er fullført, er engangsobjektet (i dette tilfellet HttpClient) utenfor omfang og avhendet. Kall på dispose-metoden og rydd opp i alle ressurser som brukes. Dette er et veldig typisk mønster i .NET som vi bruker for alt fra databasen til flytskriveren. Faktisk bruker ethvert objekt med en ekstern ressurs som må renses det IDisposable-grensesnittet.
Og du kan ikke klandres for å ville pakke det inn i bruk. For det første regnes det som en god praksis å gjøre det. Faktisk bruker Microsofts offisielle dokumentasjon følgende:
Generelt, når man bruker et IDisposable-objekt, bør det deklareres og instansieres i using statement. For det andre, all koden du kanskje har sett...... Begynnelsen av HttpClient vil fortelle deg å bruke using statement-blokken, inkludert den nyeste dokumentasjonen ASP.NET selve nettstedet. Det samme sies i artikkelen på Internett.
Men HttpClient er annerledes. Selv om den implementerer IDisposable-grensesnittet, er det faktisk et delt objekt. Dette betyr at det bak kulissene er reentrant og trådsikkert. Du bør dele en instans av HttpClient gjennom hele applikasjonens levetid, i stedet for å lage en ny instans for hver kjøring. HttpClient, la oss se hvorfor.
Se selv
Her er et enkelt program for å demonstrere HttpClient:
Dette vil bli rettet til http://aspnetmonsters.comÅpne 10 forespørsler og gjør GET, vi skriver bare ut statuskoden, så vi vet at det fungerer. Utgangen vil være:
Vent, det er mer!
Alt arbeid og alt er riktig for verden. Men det er det ikke. Hvis vi tar ut netstat-verktøyet og ser på socket-statusen på maskinen som kjører det, vil vi se:
C:\code\socket>NETSTAT.EXE ... Proto lokal adresse Utenlandsk adresse Delstat 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 ETABLERT ... Vel, det er rart...... Applikasjonen har avsluttet, men det er fortsatt mange av disse tilkoblingene åpne til Azure-maskinen som hoster ASP.NET Monsters-nettsiden. De er inneTIME_WAITstatus, som betyr at forbindelsen er lukket på den ene siden (vår), men vi venter fortsatt på å se om andre pakker kommer inn fordi de kan ha blitt forsinket et sted i nettverket. Her er et diagram over TCP/IP-statusen:
Windows vil forbli tilkoblet i denne tilstanden i 240 sekunder (som satt ved å sette [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]). Windows har en grense for hvor raskt du kan åpne en ny socket, så hvis du går tom for tilkoblingspooler, kan du få en feil som denne:
Kan ikke koble til den eksterne serveren
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted. Å søke etter det på Google vil gi deg dårlige råd om å redusere tilkoblingstid. Faktisk, når man kjører korrekt på en server med HttpClient eller en lignende applikasjon, kan reduksjon av tidsavbrudd føre til andre negative konsekvenser. Vi må forstå hva «riktig» betyr og løse det underliggende problemet, ikke fikle med maskinnivåvariabler.
Fiks det
Hvis vi deler en instans av HttpClient, kan vi redusere socket-sløsing ved å gjenbruke dem:
Merk at for hele applikasjonen har vi bare én delt instans. HttpClient fungerer fortsatt som før (faktisk litt raskere på grunn av socket-gjenbruk). Netstat viser nå kun:
TCP 10.211.55.6:12254 waws-prod-bay-017:http ETABLERT I et produksjonsscenario ligger socket-tellingen min i gjennomsnitt rundt 4000 og topper seg på over 5000, noe som effektivt presser de tilgjengelige ressursene på serveren og får tjenesten til å krasje. Etter å ha implementert endringen, falt antallet kontakter i bruk fra et gjennomsnitt på over 4000 til konsekvent under 400, vanligvis rundt 100.
Dette er en del av et diagram fra vårt overvåkingsverktøy som viser hva som skjer etter at vi har distribuert et begrenset antall fiksbevis til et utvalgt antall mikrotjenester.
Det var dramatisk. Hvis du har noen form for belastning, må du huske på disse to tingene:
Gjør HttpClient-en din statisk. Ikke kast eller pakk inn bruken din med mindre du eksplisitt ser etter en spesifikk oppførsel (for eksempel at tjenesten din feiler). HttpClient
sammendrag
Problemet med utmattelse av sokkelen vi har slitt med i flere måneder er borte, og kundene våre har en virtuell parade. Jeg kan ikke undervurdere hvor lite åpenbar denne feilen er. Gjennom årene har vi vært vant til å håndtere implementerte objekter, IDisposable, og mange refaktoreringsverktøy som R# og CodeRush advarer deg faktisk hvis du ikke gjør det. I dette tilfellet er det feil tilnærming å kvitte seg med HttpClient. HttpClient implementerer IDisposable og oppmuntrer til dårlig oppførsel er uheldig
Original:Innloggingen med hyperkoblingen er synlig.
|