Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

눈으로 확인하는 connectionManagement의 maxconnection 설정값


"눈으로 확인하는..." 시리즈 물이 될 것 같군요. ^^

눈으로 확인하는 maxWorkerThreads, minFreeThreads 설정값
; https://www.sysnet.pe.kr/2/0/983

이번에는 connectionManagement 노드에서 제공되는 maxconnection 값에 대한 테스트를 해보겠습니다. 이 값은 .NET 응용 프로그램에서 특정 호스트로 보내는 "동시 연결 수"를 제어합니다. 쉽게 풀어보면, 여러분들의 .NET 응용 프로그램에서 HttpWebRequest를 이용하여 다음과 같이 연결을 한다고 가정할 때,

string url = "http://testhost/test.aspx";
HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
                
using (HttpWebResponse httpResponse = req.GetResponse() as HttpWebResponse)
using (Stream stream = httpResponse.GetResponseStream())
using (StreamReader sr = new StreamReader(stream, Encoding.Default))
{
    string txt = sr.ReadToEnd();
}

만약, test.aspx 내의 코드 수행 시간이 10초가 걸리는 상황에서 위의 코드를 스레드 100개로 돌리면 maxconnection에 지정된 수의 스레드만 testhost 컴퓨터에 연결이 되고 나머지 스레드들의 HttpWebRequest 개체들은 10초가 지난 후 기존 연결들이 해제되고 나서야 하나씩 차례대로 접속할 수 있는 효과가 있습니다.

덧붙여, 아래의 문서에 보면 maxconnection에 대한 설명이 잘 나와 있습니다.

<add> Element for connectionManagement (Network Settings)
; https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/add-element-for-connectionmanagement-network-settings

Don't forget to tune your application 
; http://weblogs.asp.net/johnbilliris/archive/2010/06/30/don-t-forget-to-tune-your-application.aspx

대부분의 app/web.config 파일에는 connectionManagement 설정이 없는데요. 그렇다면 기본값은 몇일까요?




확인을 위해 간단한 테스트 환경을 구성했습니다.

A, B 호스트를 마련했고, A 호스트의 test.aspx는 B 호스트의 delay.aspx를 호출하도록 했습니다. delay.aspx는 일부러 Page_Load에서 Thread.Sleep(60 * 1000)을 해서 60초의 지연 시간을 갖고!

(별다른 의미는 없지만, B 호스트는 Web Garden == 2로 설정했습니다.)

부하 발생기를 이용해서 A 호스트의 test.aspx에 요청을 집중했더니 아래와 같이 maxconnection == 10의 결과가 나왔습니다.

maxconnection_settings_affect_1.png

위의 그림에서 "W11"이 "A 호스트"이고, "W21", "W22"는 "Web Garden"이 2개로 설정된 "B 호스트"의 웹 응용 프로그램을 나타냅니다.

보시는 것처럼, test.aspx에서 HttpWebRequest를 이용하여 "http://bhost/delay.aspx"로 호출했을 때 최대 10개의 연결만 맺어지는 것을 볼 수 있습니다. 즉, connectionManagement의 maxconnection 기본값은 10이 됩니다.

확실히 하기 위해 이 값을 30으로 바꿔보았습니다.

<system.net>
    <connectionManagement>
        <add address="*" maxconnection="30" />
    </connectionManagement>
</system.net>

자, 그럼 결과가 어떻게 나올까요? ^^ 예상하시는 것처럼 "B 호스트"로의 연결은 각각 15개씩 총 30개의 연결로 제한이 됩니다.

maxconnection_settings_affect_2.png




한 가지 짚고 넘어가야 할 것이 있는데요. 문서가 약간 혼동스럽다는 점입니다. maxconnection이 지정되어 있지 않으면 기본값이 2라고 되어 있는데요.

maxconnection - The maximum number of connections allowed to a server. If not supplied, the default is 2.


"%Program Files%\Microsoft Visual Studio 10.0\xml\Schemas\DotNetConfig35.xsd" 파일에 명시된 바에 의하면 maxconnection은 생략할 수 없는 "required" 속성을 가지고 있습니다.

<xs:element name="connectionManagement" vs:help="configuration/system.net/connectionManagement">
    <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="add" vs:help="configuration/system.net/connectionManagement/add">
                <xs:complexType>
                    <xs:attribute name="address" type="xs:string" use="required" />
                    <xs:attribute name="maxconnection" type="xs:int" use="required" />
                    <xs:attribute name="lockAttributes" type="xs:string" use="optional" />
            ...[생략]...

그런데, 실제로 ^^; 생략이 되어 다음과 같이 설정하는 것이 가능합니다.

<system.net>
    <connectionManagement>
        <add address="*" />
    </connectionManagement>
</system.net> 

다시 부하 발생기로 테스트해 보면 값이 어떻게 나올까요?

예상했던 2가 아니라... 1입니다. (혹시, 제가 테스트를 잘못한 것 같다면 덧글 부탁드립니다.)

maxconnection_settings_affect_3.png




고객사에서 오류 문의가 왔습니다. 제니퍼 닷넷에서 다음과 같은 오류가 보고된 것입니다.

...[생략]...
[0005][13:39:23 477][ 15][ 15] TX-CALL[WebReq.http://[...this_public_domain_name...]/top.aspx] [15 ms]
[0006][13:39:23 477][ 0][ 0] SOCKET-CLOSE R=52174,W=106,uid=7568243 
[0007][13:40:03 523][40,046][ 16] TX-CALL[WebReq.http://[...this_public_domain_name...]/bottom.aspx] [40,046 ms]
[0008][13:40:03 523][ 0][ 0] TX-EXCEPTION [System.Net.WebException: 작업 시간이 초과되었습니다. ...[이하 콜스택 생략]... 

그런데... 가만 보면 해당 웹 페이지의 구성 자체가 재미있습니다. 보통 웹 페이지를 만들면 내부에 레이아웃을 구성하게 되는데요. 위의 고객 사이트는 웹 페이지의 top과 bottom에 해당하는 내용을 별도의 aspx로 빼고 사용자로부터 요청이 왔을 때 HttpWebRequest 개체를 이용해서 직접 top/bottom 관련해서 aspx를 호출하여 내용을 가져온 후 화면에 추가하는 것이었습니다.

위와 같은 구성이 성능에 어떤 영향을 미칠까요?

1) 우선, 해당 고객 사이트가 web.config에 connectionManagement / maxconnection 설정을 하지 않았다고 가정해 보겠습니다. 이 글의 처음에 설명했던 것처럼 특정 호스트에 대해 동시 연결이 기본값 10으로 동작하기 때문에, 위의 웹 사이트는 마치 10개의 상한을 가진 세마포어를 사용하는 효과를 가지게 됩니다. 동시 연결 10개 이후부터는 쓰레드들이 대기 현상이 발생하게 되고 사용자가 폭주하는 시간에는 그 현상이 더욱 심하게 됩니다.

게다가 위에서는 top과 bottom에 대해 각각 요청을 보냈기 때문에 스레드 대기 현상은 더욱 심해집니다.

2) 두 번째 문제는, HttpWebRequest 요청의 URL에 내부 IP가 아닌, 일반 사용자들이 접근할 때와 동일한 공용 DNS 이름을 사용했다는 것입니다. 이렇게 되면 내부 IP가 아닌 외부 공용 IP가 구해지게 되고, 방화벽/NAT/L4 장비를 거쳐서 호출이 되어 응답 시간이 늘어나게 됩니다.

3) 세 번째 문제는, dead-lock 문제에 빠질 수 있습니다. 이에 대해서는 지난번에도 한번 사례를 설명했었습니다.

제니퍼 닷넷 적용 사례 (2) - 웹 애플리케이션 hang의 원인을 알려주다.
; https://www.sysnet.pe.kr/2/0/1117

위의 글에서는 config.xml 파일 하나를 서비스하는 유형이라서 간단하게 AppPool을 별도로 생성하여 스레드 풀을 새롭게 할당함으로써 해결을 했는데요. System.Net.WebException 예외가 발생한 이번 글의 고객사 경우에는 문제가 좀 복잡해 질 수 있습니다. 왜냐하면, top/bottom.aspx 요청을 받는 그 웹 사이트는 그 외에도 많은 요청을 받아서 처리할 수 있는 구조였기 때문입니다.

가정을 해볼까요? 사용자가 갑자기 몰려서 L4로 묶인 호스트 중에서 "192.168.0.10" 서버가 동시에 1,200개의 요청을 받았다고 해보겠습니다. 그 서버는 maxWorkerThreads == 100 상태에서 쿼드 코어라면 총 400개의 동시 요청만을 처리할 수가 있습니다. 나머지 800개는 IIS가 요청 대기 큐에 쌓아두고 앞서의 처리가 끝나면 차례대로 처리를 할 텐데요. 설상 가상으로 DB까지 지연되면서 하나의 aspx 처리 시간이 5초가 걸리는 상황이 발생한다고 하면?

그런 와중에 "192.168.0.11" 서버로 top/bottom.aspx를 포함한 웹 페이지 요청이 발생했고 하필 그것이 "192.168.0.10" 서버로 전달되었다고 하면 어떤 일이 벌어질까요? 현재 10번 서버에 발생한 요청만 처리하는데 1,200 / 400 = 3 * 5초 == 15초가 소요되어 11번 서버로 요청을 보냈던 사용자는 11번 서버가 한가로운데도 불구하고 15초를 대기한 후에야 정상적인 aspx 웹 페이지를 볼 수 있게 됩니다.

결론적으로, 아무리 어떤 이유를 갖다댄다 해도... 하나의 aspx에서 top/bottom.aspx의 내용을 별도의 HTTP 요청으로 분리해서 구하는 것은 꽤나 불합리한 구조입니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 6/26/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2017-12-26 09시45분
[몬난아] 예전글이라 답변이 달릴지 모르겠군요..
https://docs.microsoft.com/en-us/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45 게시글을 보다가 여기까지 왔습니다.

하단에 maxconnection관련 해서 12 * 4(cpu) = 48 부분인데요.

이게 기본설정이면 2008r2이상에서는 4cpu에서 48개정도의 동시 처리가 불가능한것인가요? 좀 혼란스러운게.. IIS같은경우는 1개의 프로세스에 25개의 Thread설정이 기본값인데. 이것과상관관계가 어떻게 되는지 머리속에 그려지지 않내요..

이럴경우 서비스 4.0으로 서비스하고 있는 프로젝트들은 좀 수동으로 늘려주는게 유리한것인지 해서 질문드립니다. 4.5가 5000이 기본값이면, 48이 아닌 여유있게 1000~3000을 줘도 여유로울것 같은설정인데..

그리고 .NET 4.5이상에서는 5000개가 기본값인것도 갭이 상당하내요..

질문이 두서없군요.. 저는 여태까지는 IIS에 1개의 어플리케이션은 별도로 옵션을 수정하지 않는다면
1개프로세스안에서 > 25개의 Thread가 대기중인상태이고 3000개 까지 큐를 받을수 있으며 큐에 쌓인순서대로 25개의 Thread 25개가 순차적으로 처리해나간다였는데.
여기 개념사이에 CPU별로 12개씩 동시 처리 여부가 어디에? 들어가야하는걸로 계산해야하는지... 그게 좀 혼란스럽내요..
[guest]
2017-12-26 09시53분
[몬난아] 큐길이 설정이.. IIS에서도 ASP 하위에 큐길이의 기본값은 3천이고.. 응용프로그램풀의 기본값은 1000이군요.
이럴경우 ASP쪽의 설정은 Classic ASP에서이고.. 닷넷은 응용프로그램풀의 큐설정을 따르는것인가요... 이게 질문의 범위가 커져버렸습니다.

만약그런것이라면 ASP 하위에 프로세스 당 Thread제한역시 ASP전용이 되는것이고 .NET은 maxconnection 인것인지..
몇가지가 기존에 알던것과 틀리고 중복된.. 혼란스럽네요.. 시간이 나시면 간단히 답변부탁드립니다
수고하세요
[guest]
2017-12-26 02시03분
[몬난아] 아 다시 차근히 읽으니 해당설정은 응용에서 특정호스트로 보내는 작업에 제한이군요....
[guest]
2019-07-30 12시57분
C:\Windows\Microsoft.NET\Framework\v2.0.50727\Aspnet.config

<system.web>
  <applicationPool
       maxConcurrentRequestsPerCPU="12"
       maxConcurrentThreadsPerCPU="0"
       requestQueueLimit="5000"/>
</system.web>
정성태

1  2  3  4  5  6  7  [8]  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13434정성태11/1/20232703스크립트: 62. 파이썬 - class의 정적 함수를 동적으로 교체
13433정성태11/1/20232407스크립트: 61. 파이썬 - 함수 오버로딩 미지원
13432정성태10/31/20232505오류 유형: 878. 탐색기의 WSL 디렉터리 접근 시 "Attempt to access invalid address." 오류 발생
13431정성태10/31/20232844스크립트: 60. 파이썬 - 비동기 FastAPI 앱을 gunicorn으로 호스팅
13430정성태10/30/20232710닷넷: 2153. C# - 사용자가 빌드한 ICU dll 파일을 사용하는 방법
13429정성태10/27/20232997닷넷: 2152. Win32 Interop - C/C++ DLL로부터 이중 포인터 버퍼를 C#으로 받는 예제파일 다운로드1
13428정성태10/25/20233070닷넷: 2151. C# 12 - ref readonly 매개변수
13427정성태10/18/20233260닷넷: 2150. C# 12 - 정적 문맥에서 인스턴스 멤버에 대한 nameof 접근 허용(Allow nameof to always access instance members from static context)
13426정성태10/13/20233420스크립트: 59. 파이썬 - 비동기 호출 함수(run_until_complete, run_in_executor, create_task, run_in_threadpool)
13425정성태10/11/20233208닷넷: 2149. C# - PLinq의 Partitioner<T>를 이용한 사용자 정의 분할파일 다운로드1
13423정성태10/6/20233185스크립트: 58. 파이썬 - async/await 기본 사용법
13422정성태10/5/20233332닷넷: 2148. C# - async 유무에 따른 awaitable 메서드의 병렬 및 예외 처리
13421정성태10/4/20233408닷넷: 2147. C# - 비동기 메서드의 async 예약어 유무에 따른 차이
13420정성태9/26/20235621스크립트: 57. 파이썬 - UnboundLocalError: cannot access local variable '...' where it is not associated with a value
13419정성태9/25/20233241스크립트: 56. 파이썬 - RuntimeError: dictionary changed size during iteration
13418정성태9/25/20233938닷넷: 2146. C# - ConcurrentDictionary 자료 구조의 동기화 방식
13417정성태9/19/20233475닷넷: 2145. C# - 제네릭의 형식 매개변수에 속한 (매개변수를 가진) 생성자를 호출하는 방법
13416정성태9/19/20233280오류 유형: 877. redis-py - MISCONF Redis is configured to save RDB snapshots, ...
13415정성태9/18/20233778닷넷: 2144. C# 12 - 컬렉션 식(Collection Expressions)
13414정성태9/16/20233533디버깅 기술: 193. Windbg - ThreadStatic 필드 값을 조사하는 방법
13413정성태9/14/20233730닷넷: 2143. C# - 시스템 Time Zone 변경 시 이벤트 알림을 받는 방법
13412정성태9/14/20237025닷넷: 2142. C# 12 - 인라인 배열(Inline Arrays) [1]
13411정성태9/12/20233521Windows: 252. 권한 상승 전/후 따로 관리되는 공유 네트워크 드라이브 정보
13410정성태9/11/20235061닷넷: 2141. C# 12 - Interceptor (컴파일 시에 메서드 호출 재작성) [1]
13409정성태9/8/20233902닷넷: 2140. C# - Win32 API를 이용한 모니터 전원 끄기
13408정성태9/5/20233866Windows: 251. 임의로 만든 EXE 파일을 포함한 ZIP 파일의 압축을 해제할 때 Windows Defender에 의해 삭제되는 경우
1  2  3  4  5  6  7  [8]  9  10  11  12  13  14  15  ...