Ich habe HttpClient jahrelang falsch verwendet, aber schließlich kam der Albtraum. Meine Website war instabil und meine Kunden waren sehr wütend, und mit einer einfachen Lösung wurde die Leistung deutlich verbessert und die Instabilität beseitigt.
Gleichzeitig habe ich tatsächlich die Leistung meiner Anwendung durch effizientere Socket-Nutzung verbessert.
Microservices können ein schwieriges Problem sein. Mit der Hinzufügung weiterer Dienste und dem Zerfall monolithischer Anwendungen gibt es tendenziell immer mehr Kommunikationswege zwischen Diensten. Es gibt viele Kommunikationsmöglichkeiten, aber HTTP ist eine sehr beliebte Option. Wenn der Microservice in C# oder einer beliebigen .NET-Sprache gebaut ist, nutzt du wahrscheinlich bereits HttpClient.
Das Problem liegt
Die Using-Anweisung ist eine C#-Funktion, die Einmalobjekte verarbeitet. Sobald der verwendete Block abgeschlossen ist, ist das einmalige Objekt (in diesem Fall HttpClient) außerhalb des Anwendungsbereichs und entsorgt. Rufen Sie die Entsorgungsmethode auf und reinigen Sie alle verwendeten Ressourcen. Das ist ein sehr typisches Muster in .NET, das wir für alles verwenden, von der Datenbank bis zum Flow Writer. Tatsächlich verwendet jedes Objekt mit einer externen Ressource, die bereinigt werden muss, diese IDisposable Schnittstelle.
Und man kann es dir nicht verübeln, es mit Konsum einwickeln zu wollen. Erstens gilt dies als gute Praxis. Tatsächlich verwendet Microsofts offizielle Dokumentation:
Im Allgemeinen sollte ein IDisposable-Objekt deklariert und in der using Statement instanziiert werden. Zweitens, all der Code, den du vielleicht gesehen hast...... Der Anfang des HttpClient sagt Ihnen, dass Sie den Blöckchen using Statement verwenden sollen, einschließlich der neuesten Dokumentation ASP.NET der Seite selbst. Dasselbe steht im Artikel im Internet.
Aber HttpClient ist anders. Obwohl es die IDisposable-Schnittstelle implementiert, handelt es sich tatsächlich um ein gemeinsames Objekt. Das bedeutet, dass es hinter den Kulissen wiedereinandergeht und thread-sicher ist. Sie sollten eine Instanz von HttpClient während der gesamten Lebensdauer Ihrer Anwendung teilen, anstatt für jede Ausführung eine neue Instanz zu erstellen. HttpClient, schauen wir uns an, warum.
Überzeugen Sie sich selbst
Hier ist ein einfaches Programm, um HttpClient zu demonstrieren:
Dies wird an http://aspnetmonsters.comÖffne 10 Anfragen und mache GET, wir drucken einfach den Statuscode, damit wir wissen, dass es funktioniert. Die Ausgabe lautet:
Warte, da ist noch mehr!
Alles Arbeit und alles ist richtig für die Welt. Nur ist es das nicht. Wenn wir das Netstat-Tool herausnehmen und den Socket-Status der Maschine ansehen, sehen wir:
C:\code\socket>NETSTAT.EXE ... Proto Lokale Adresse Auslandsadresse Bundesstaat 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 ETABLIERT ... Nun, es ist seltsam...... Die Anwendung wurde beendet, aber es gibt immer noch viele dieser Verbindungen zur Azure-Maschine, die die ASP.NET Monsters-Website hostet. Sie sind drinTIME_WAITStatus, was bedeutet, dass die Verbindung auf einer Seite (unserer) geschlossen wurde, aber wir warten noch darauf, ob noch andere Pakete eingehen, da sie möglicherweise irgendwo im Netzwerk verspätet wurden. Hier ist ein Diagramm des TCP/IP-Status:
Windows bleibt in diesem Zustand für 240 Sekunden verbunden (wie festgelegt durch die Einstellung von [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]). Windows hat eine Begrenzung, wie schnell du einen neuen Socket öffnen kannst, daher kannst du, wenn dir die Verbindungspools ausgehen, einen Fehler wie diesen sehen:
Keine Verbindung zum entfernten Server möglich
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted. Wenn du bei Google danach suchst, bekommst du schlechte Tipps, wie du die Verbindungszeitabzeiten reduzieren kannst. Tatsächlich kann das korrekte Ausführen von Timeouts auf einem Server mit HttpClient oder einer ähnlich konstruierten Anwendung zu weiteren negativen Folgen führen. Wir müssen verstehen, was "richtig" bedeutet, und das zugrundeliegende Problem lösen, nicht an Variablen auf Maschinenebene herumbasteln.
Reparier es
Wenn wir eine Instanz von HttpClient teilen, können wir Socket-Abfall reduzieren, indem wir sie wiederverwenden:
Beachten Sie, dass wir für die gesamte Anwendung nur eine gemeinsame Instanz haben. HttpClient funktioniert immer noch wie zuvor (tatsächlich etwas schneller wegen der Wiederverwendung des Sockets). Netstat zeigt jetzt nur noch an:
TCP 10.211.55.6:12254 waws-prod-bay-017:http ETABLIERT In einem Produktionsszenario liegt meine Socket-Anzahl im Durchschnitt bei etwa 4000 und erreicht einen Höhepunkt bei über 5000, was die verfügbaren Ressourcen auf dem Server effektiv ausschöpft und den Service abstürzen lässt. Nach der Umsetzung der Änderung sank die Anzahl der verwendeten Sockeln von durchschnittlich über 4000 auf konstant weniger als 400, typischerweise etwa 100.
Dies ist Teil eines Diagramms aus unserem Monitoring-Tool, das zeigt, was passiert, nachdem wir eine begrenzte Anzahl von Fix-Proofs auf eine ausgewählte Anzahl von Microservices bereitgestellt haben.
Es war dramatisch. Wenn Sie irgendeine Art von Last haben, müssen Sie folgende zwei Dinge im Hinterkopf behalten:
Mach deinen HttpClient statisch. Verwerfen oder verpacken Sie Ihre Nutzung nicht, es sei denn, Sie suchen explizit nach einem bestimmten Verhalten (zum Beispiel zum Ausfall Ihres Dienstes). HttpClient
Zusammenfassung
Das Problem mit der Erschöpfung der Steckdosen, mit dem wir seit Monaten zu kämpfen haben, ist verschwunden, und unsere Kunden haben eine virtuelle Parade. Ich kann nicht unterschätzen, wie unoffensichtlich dieser Fehler ist. Im Laufe der Jahre sind wir es gewohnt, mit implementierten Objekten, IDisposable und vielen Refactoring-Tools wie R# und CodeRush zu arbeiten, die dich tatsächlich warnen, wenn du es nicht tust. In diesem Fall ist die Entsorgung von HttpClient der falsche Ansatz. HttpClient implementiert IDisposable und fördert schlechtes Verhalten ist bedauerlich
Original:Der Hyperlink-Login ist sichtbar.
|