이 글은 기계 번역의 미러 문서이며, 원본 기사로 바로 이동하려면 여기를 클릭해 주세요.

보기: 6079|회답: 4

[출처] HttpClient를 잘못 사용하면 소프트웨어가 망가질 수 있습니다

[링크 복사]
게시됨 2022. 5. 14. 오후 5:11:56 | | | |
저는 수년간 HttpClient를 잘못 사용해왔지만, 결국 악몽이 찾아왔습니다. 제 웹사이트가 불안정했고 고객들은 매우 분노했으며, 간단한 수정으로 성능이 크게 향상되고 불안정성이 사라졌습니다.



동시에 소켓 사용을 더 효율적으로 하여 애플리케이션 성능도 향상시켰습니다.

마이크로서비스는 다루기 어려운 문제일 수 있습니다. 더 많은 서비스가 추가되고 모놀리식 애플리케이션이 분해됨에 따라 서비스 간 통신 경로가 점점 더 많아지는 경향이 있습니다. 다양한 통신 옵션이 있지만, HTTP가 매우 인기 있는 선택입니다. 마이크로서비스가 C#이나 다른 .NET 언어로 만들어졌다면, 아마도 이미 HttpClient를 사용하고 있을 가능성이 큽니다.


문제는

using 문은 일회용 객체를 처리하는 C# 기능입니다. 사용 블록이 완료되면, 일회용 객체(이 경우 HttpClient)는 범위 밖으로 처리됩니다. 폐기 방법을 호출해 사용 중인 자원을 정리하세요. 이것은 .NET에서 데이터베이스부터 플로우 라이터까지 모든 것에 사용하는 매우 일반적인 패턴입니다. 사실, 정제해야 할 외부 자원을 가진 객체는 그 IDisposable 인터페이스를 사용합니다.

그리고 그것을 사용하면서 포장하고 싶어 하는 당신을 탓할 수는 없습니다. 첫째, 그렇게 하는 것이 좋은 관행으로 여겨집니다. 실제로 마이크로소프트의 공식 문서는 다음과 같습니다:


일반적으로 IDisposable 객체를 사용할 때는 using 문에서 선언하고 인스턴스화해야 합니다.
둘째, 여러분이 본 모든 코드입니다...... HttpClient 시작 부분에는 사이트 자체 ASP.NET 최신 문서를 포함한 using 문장 블록을 사용하도록 안내합니다. 인터넷에 올라온 기사에서도 같은 내용이 나와 있습니다.

하지만 HttpClient는 다릅니다. IDisposable 인터페이스를 구현하지만, 실제로는 공유 객체입니다. 즉, 무대 뒤에서는 재진입 가능하고 스레드 안전하다는 뜻입니다. 애플리케이션의 수명 동안 HttpClient 인스턴스를 공유하는 것이 좋으며, 각 실행마다 새로운 인스턴스를 생성하는 것이 좋습니다. HttpClient, 이유를 살펴보겠습니다.

직접 확인해 보세요

다음은 HttpClient를 시연하는 간단한 프로그램입니다:

이 글은  http://aspnetmonsters.com10개의 요청을 열고 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 설립
...
음, 이상하네...... 애플리케이션은 종료되었지만, ASP.NET Monsters 웹사이트를 호스팅하는 Azure 기기에 연결된 연결이 여전히 많이 열려 있습니다. 그들은 이미TIME_WAIT상태는 한쪽(우리 쪽)에서 연결이 종료되었음을 의미하지만, 네트워크 어딘가에서 지연되었을 가능성이 있어 다른 패킷이 들어오는지 아직 기다리고 있습니다. TCP/IP 상태의 다이어그램은 다음과 같습니다:



Windows는 이 상태로 240초 동안 연결되어 있습니다([HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]를 설정하여 설정한 상태). 윈도우에는 새 소켓을 열 수 있는 속도에 제한이 있어서, 연결 풀이 다 떨어지면 다음과 같은 오류가 발생할 수 있습니다:

원격 서버에 연결할 수 없습니다
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
구글에서 검색해보면 연결 타임아웃을 줄이는 데 도움이 안 되는 조언을 얻을 수 있습니다. 실제로 HttpClient나 유사하게 구성된 애플리케이션이 설치된 서버에서 실행될 때, 타임아웃을 줄이면 다른 부정적인 결과가 발생할 수 있습니다. 우리는 '옳다'가 무엇을 의미하는지 이해하고 근본적인 문제를 해결해야 하며, 기계 수준 변수를 만지는 것이 아닙니다.

고쳐

HttpClient 인스턴스를 공유하면 소켓 낭비를 줄일 수 있습니다:

전체 애플리케이션 전체에서 공유 인스턴스는 단 하나뿐이라는 점에 유의하세요. HttpClient는 여전히 이전과 동일하게 작동합니다(사실 소켓 재사용으로 인해 조금 더 빠릅니다). 넷스탯은 이제 다음과 만 표시합니다:

TCP 10.211.55.6:12254 waws-prod-bay-017:http 설립됨
운영 환경에서 소켓 수는 평균 약 4000개이고 5000개를 넘는 높이에 달해 서버의 자원이 꽉 차서 서비스가 다운됩니다. 변경 후 사용 중인 소켓 수는 평균 4000개 이상에서 꾸준히 400개 미만으로 줄었으며, 보통 약 100개 정도였습니다.

이것은 제한된 수의 수정 증명을 일부 마이크로서비스에 배포한 후 어떤 일이 일어나는지 보여주는 모니터링 도구의 차트 일부입니다.




정말 극적이었어요. 어떤 종류의 부하가 있다면, 다음 두 가지를 꼭 염두에 두어야 합니다:

HttpClient를 정적으로 만드세요.
특정 동작(예: 서비스 장애 발생)을 명확히 원하지 않는 한 사용을 버리거나 포장하지 마세요. Http클라이언트


요약

몇 달째 고생해온 소켓 고진 문제는 사라졌고, 고객들은 가상 퍼레이드를 갖게 되었습니다. 이 실수가 얼마나 명백하지 않은지 과소평가할 수 없습니다. 수년간 우리는 구현된 객체, IDisposable, 그리고 R#이나 CodeRush 같은 많은 리팩토링 도구를 다루는 데 익숙해져 왔습니다. 그렇지 않으면 경고를 줍니다. 이 경우 HttpClient를 폐기하는 것은 잘못된 접근법입니다. HttpClient가 IDisposable을 구현하고 나쁜 행동을 조장하는 것은 안타깝습니다

원문 언어:하이퍼링크 로그인이 보입니다.




이전의:ASP.NET 코어는 IIS에서 프로세스 중(in-process) 및 프로세스 종료(out-of-process) 모델을 호스팅합니다
다음:ASP.NET 코어(XV)는 HTTP 요청을 보낼 때 HttpClient를 사용합니다
 집주인| 게시됨 2022. 5. 14. 오후 5:25:22 |
TCP TIME_WAIT는 일반적인 TCP 프로토콜 동작으로, 마지막 FIN-ACK가 통과된 후 클라이언트는 최대 수명(MSL) 시간이 두 배 이상 지나 원격 TCP가 연결 종료 요청에 대한 확인 신호를 받도록 기다립니다. 기본적으로 MSL은 2분입니다. TIME_WAIT에서 최대 4분까지 머물 수 있는데, 이를 두 번의 MSL이라고 합니다.

https://docs.microsoft.com/en-us ... t-from-netstat.html
게시됨 2022. 5. 14. 오후 10:35:22 |
배우기 위해 배우세요
게시됨 2022. 5. 19. 오전 9:39:05 |
모두 중국어인데, 문장으로 연결되면 이해가 안 돼요
 집주인| 게시됨 2023. 11. 6. 오전 7:16:05 |
테스트
면책 조항:
Code Farmer Network에서 발행하는 모든 소프트웨어, 프로그래밍 자료 또는 기사는 학습 및 연구 목적으로만 사용됩니다; 위 내용은 상업적 또는 불법적인 목적으로 사용되지 않으며, 그렇지 않으면 모든 책임이 사용자에게 부담됩니다. 이 사이트의 정보는 인터넷에서 가져온 것이며, 저작권 분쟁은 이 사이트와는 관련이 없습니다. 위 내용은 다운로드 후 24시간 이내에 컴퓨터에서 완전히 삭제해야 합니다. 프로그램이 마음에 드신다면, 진짜 소프트웨어를 지원하고, 등록을 구매하며, 더 나은 진짜 서비스를 받아주세요. 침해가 있을 경우 이메일로 연락해 주시기 바랍니다.

Mail To:help@itsvse.com