Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 2개 있습니다.)

MEF가 적용된 ASP.NET 웹 사이트를 제니퍼 닷넷으로 모니터링 해본 결과!

지인 한 분이, 이번 참에 MEF(Managed Extensibility Framework)를 공부할 겸 간단하게 prototype 형식의 웹 사이트를 하나 만들었다고 하시면서... MEF 적용 자체는 Biz 계층과 Dac 계층에 모두 적용을 했는데, 속도가 너무 안 나와서 Biz만 MEF를 적용하는 것이 나을지, 아니면 Dac 쪽만 MEF를 적용하는 것이 나을 지에 대해서 제게 의견을 구했습니다.

사실 ^^ 저도 MEF는 자료로 보기만 하고 직접 사용해 본적은 없기 때문에 ... 마침 잘 되었다 싶어서 그 분께 관련 테스트 소스를 요청해서 받았습니다. 그런 후 '제니퍼 닷넷'으로 검사해 보았는데요... 이번 글은 그에 대한 결과를 공유하는 차원에서 써 봅니다. ^^




최대한 재현을 잘 해내기 위해 소스 코드를 요청했지만, 비슷한 뼈대의 구성으로 ASP.NET에 MEF를 적용한 예제가 아래의 글에도 공개되어 있으니 이 글을 읽으시는 분들도 쉽게 재현을 할 수 있을 것입니다.

MEF with ASP.NET - "Hello World!"
; http://www.codeproject.com/KB/aspnet/MEFwithASPNET.aspx

소스 코드를 살펴보면 다음과 같은데요.

protected void Page_Load(object sender, EventArgs e) 
{
    DirectoryCatalog catalog = new DirectoryCatalog(
        System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
    CompositionContainer container = new CompositionContainer(catalog);
    container.ComposeParts(this);
}

지인이 보내주신 코드도 위의 방법과 크게 다르지 않았습니다.

실행하고 곧바로 default 웹 페이지를 방문했는 데, 과연 다음과 같이 3초 가까운 시간이 흐른 것을 확인할 수 있었습니다.

mef_perf_1.png

위의 화면에서 발견할 수 있는 또 다른 문제는 "CPU_T" 열에 있는 2,606ms 수치입니다. 즉, default.aspx 웹 페이지가 응답까지 걸린 시간이 2,789ms가 걸렸는데 그동안 계속해서 CPU가 거의 100% 일을 한 것이나 다름없다는 의미입니다. 보통, 데이터베이스 조회 시에 DB가 무거워서 GAP 시간이 수 초가 넘게 걸려도 웹 서버의 CPU는 50ms 이하로 일을 하는 경우가 대부분이어서 웹 서버 자체는 사실 부하가 심하지 않은 경우가 대부분입니다.

그런데, 위의 경우는 웹 페이지가 방문되는 횟수가 늘어날 수록 CPU는 더욱 심하게 일하게 되어 웹 서버 자체의 운영에 심각한 영향을 줄 수 있음을 보여주는 것입니다.

아쉽게도, 제니퍼 닷넷이 보여주는 '기본 프로파일 정보'에는 DB/WCF/COM+/ASMX/.NET Remoting 이외에는 어떤 부분에서 시간이 걸렸다는 것을 보여주지 않기 때문에 위의 X-View 상세 보기 화면에서는 더 이상의 단서를 발견할 수는 없었습니다.

그래도 ^^ 여기서 이야기가 끝이면 아마 이 글을 쓰지도 않았겠지요.

아직 많은 분들이 모르시지만 ^^ '제니퍼 닷넷'은 사용자 어셈블리의 모든 메서드 호출을 프로파일링 할 수 있는 기능이 추가되어 있습니다. 이 기능을 활성화 하려면 '제니퍼 닷넷 에이전트'가 설치된 폴더의 'profile.ini' 파일에서 제공되는 "application_allmethods" 옵션 값을 "1"로 바꿔주어야 합니다.

[methodprofile]
application_allmethods=1

이렇게 변경하고 웹 사이트를 재생(recycle)해주면 이제 사용자 어셈블리의 (생성자를 제외한) 모든 메서드 호출에 대해서 프로파일링을 남겨줍니다. 아래는 위의 MEF 웹 사이트를 방문했을 때 남겨진 프로파일링 기록입니다.

mef_perf_2.png

훨씬 자세해졌지요. ^^ 보시는 것처럼, 전체적인 ASP.NET 웹 페이지의 ProcessRequest 처리에는 3,655ms가 걸렸고 그 이하 Page_Load와 UserControl의 Page_Load에서 각각 1.5초씩 지연된 것을 볼 수 있습니다.

아하... 결국 MEFManager.Compose가 재귀 호출되면서 한 번 호출될 때마다 약 90ms씩 CPU를 사용하면서 지연이 된 것임을 위의 프로파일 결과로 한 눈에 알 수 있습니다.




정리해 보면, 웹 사이트의 'bin' 폴더에는 총 650KB 용량의 DLL 파일들이 놓여 있었고 MEF가 적용된 웹 페이지는 Page_Load 시마다 그 DLL을 모두 로드하고 .NET Reflection으로 Export 특성이 적용된 타입들을 찾아내는 작업을 하고 있는 것이었습니다.

위와 같은 상황을 전달해 드렸더니, 그 분은 MEF가 적용된 DLL을 별도의 폴더로 분리하고 DirectoryCatalog를 그 폴더로 지정해서 속도 향상을 보았다고 합니다.

그런데, 일단 제 의견은 "(DirectoryCatalog를 쓰는 한) MEF는 ASP.NET에 적용해서는 안된다"입니다. 왜냐하면, 프로젝트가 진행되면서 점점 더 MEF가 적용된 DLL은 늘어갈 것이고 그때 쯤이면 또다시 성능 문제가 불거져 나올 것이기 때문입니다.
(결국,,, 이 글을 통해서 제니퍼 닷넷의 application_allmethods 옵션에 대한 자연스러운 홍보가 된 것 같습니다. ^^)

추가: MEF의 DirectoryCatalog를 cache 해두면 위의 성능 문제를 개선할 수 있습니다.




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

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

비밀번호

댓글 작성자
 



2011-12-21 11시52분
[짜두] DirectoryCatalog 를 사용할때 느려지는건 MEF 뿐만 아니라 CAG 에서도 마찬가지 였던거 같아요. DLL 갯수가 많을 수록 그리고 해당 DLL 에 화면이 많을수록 시간이 기하급수적으로 늘어났던거 같은데...
[guest]
2011-12-22 08시33분
그렇죠. ^^ CAG도 DirectoryCatalog 비슷한 형식으로 DLL을 읽어들이는 방식을 지원하고, 대개 그것을 쓰죠. 그런데... CAG를 ASP.NET에 사용하려는 노력은 없었기 때문에 Page_Load 시마다 발생하는 성능 저하 현상은 겪을 수 없었지만, MEF는 ASP.NET에 적용하려고 시도하고 있다는 점이 다릅니다. ^^ (사실... Global.asax 정도에서 처음 한번 느려지는 거라면 ASP.NET에서도 쓸만할 수 있겠지요.)
정성태
2011-12-22 08시44분
[짜두] 이것도 동적로딩 머 이런 방식으로 회피할 수 있는 방법이 먼가 있지 않을까요? 흠 ASP.NET 이라 그것도 좀 애매하긴 하네요. 어떤페이지가 언제 호출될 줄 알고... 저도 Kevin 님 의견에 전적 동의입니다~ㅎ
[guest]
2011-12-22 10시17분
[엄준일] 저도 이와 관련하여 여러 가지 테스트를 해 보니,
문제는 DI Container 가 문제더군요.

웹 사이트에 DI Container나 Injection 과 같은 프레임워크를 쓴다는 것은 성능을 일부 포기할 수 밖에 없더라구요.
CPU 꽤 잡아먹어요.
[guest]
2011-12-22 11시42분
"짜두" 님과 대화하다 보니... 왠지 DirectoryCatalog를 cache하라는 하늘의 메시지가 내려와서... 테스트해 보니 잘 되는군요. ^^ 다음의 글을 참고하세요.

MEF를 ASP.NET에 성능 손실 없이 적용하려면?
; http://www.sysnet.pe.kr/2/0/1204
정성태
2011-12-22 05시03분
[lancers] Page_Load마다 Catalog를 재구성한다는 건 엄청난 오버일 듯...
거기다 그 중에서도 가장 Cost가 쓴 DirectoryCatalog는 더 답이 안 나오겠죠.
그 분이 사용하셨다는 꽁수대로 한다면, 가장 성능을 높일 수 있는 방법은 폴더를 점점 더 잘게 찢어서 궁극적으로는 DLL당 폴더 하나씩 하는 수 밖에 없을 듯..
(그럴바엔 차라리 AssemblyCatalog를 쓰겠지만)

Cache를 하는 것이 당연히 방법인데, 이것마저도 런타임에 매번 최초 Discovery를 하는 것은 상당한 부담이 됩니다.
그래서 예전에 적용했던 방법이 DirectoryCatalog를 구성한 후 이 정보를 바탕으로 XML로 떨구는 툴을 하나 만들었습니다.
말하자면 DirectoryCatalog를 사전에 생성해두는 것과 같은 효과랄까..
그래서 이후 DirectoryCatalog가 아닌 Custom하게 만든 ConfigurationCatalog를 쓰는 형태로 하고..
실제 어셈블리 로딩은 특정 Type이 MEF에서 최초로 요청될 때 일어나는 것으로..

이론상 이렇게 해두고..
정말로 동적인 변경이 필요한 경우에는 새로운 어셈블리를 로딩한 후 Recomposition을 하면 됩니다. ㅋㅋㅋ
[guest]

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13610정성태4/28/2024218닷넷: 2251. C# - 제네릭 인자를 가진 타입을 생성하는 방법 - 두 번째 이야기
13609정성태4/27/2024251닷넷: 2250. PInvoke 호출 시 참조 타입(class)을 마샬링하는 [IN], [OUT] 특성파일 다운로드1
13608정성태4/26/2024443닷넷: 2249. C# - 부모의 필드/프로퍼티에 대해 서로 다른 자식 클래스 간에 Reflection 접근이 동작할까요?파일 다운로드1
13607정성태4/25/2024579닷넷: 2248. C# - 인터페이스 타입의 다중 포인터를 인자로 갖는 C/C++ 함수 연동
13606정성태4/24/2024732닷넷: 2247. C# - tensorflow 연동 (MNIST 예제)파일 다운로드1
13605정성태4/23/2024827닷넷: 2246. C# - Python.NET을 이용한 파이썬 소스코드 연동파일 다운로드1
13604정성태4/22/2024872오류 유형: 901. Visual Studio - Unable to set the next statement. Set next statement cannot be used in '[Exception]' call stack frames.
13603정성태4/21/2024964닷넷: 2245. C# - IronPython을 이용한 파이썬 소스코드 연동파일 다운로드1
13602정성태4/20/2024983닷넷: 2244. C# - PCM 오디오 데이터를 연속(Streaming) 재생 (Windows Multimedia)파일 다운로드1
13601정성태4/19/20241001닷넷: 2243. C# - PCM 사운드 재생(NAudio)파일 다운로드1
13600정성태4/18/20241016닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/2024951닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
13598정성태4/16/2024995닷넷: 2240. C# - WAV 파일 포맷 + LIST 헤더파일 다운로드2
13597정성태4/15/20241004닷넷: 2239. C# - WAV 파일의 PCM 데이터 생성 및 출력파일 다운로드1
13596정성태4/14/20241121닷넷: 2238. C# - WAV 기본 파일 포맷파일 다운로드1
13595정성태4/13/20241074닷넷: 2237. C# - Audio 장치 열기 (Windows Multimedia, NAudio)파일 다운로드1
13594정성태4/12/20241098닷넷: 2236. C# - Audio 장치 열람 (Windows Multimedia, NAudio)파일 다운로드1
13593정성태4/8/20241095닷넷: 2235. MSBuild - AccelerateBuildsInVisualStudio 옵션
13592정성태4/2/20241233C/C++: 165. CLion으로 만든 Rust Win32 DLL을 C#과 연동
13591정성태4/2/20241210닷넷: 2234. C# - WPF 응용 프로그램에 Blazor App 통합파일 다운로드1
13590정성태3/31/20241091Linux: 70. Python - uwsgi 응용 프로그램이 k8s 환경에서 OOM 발생하는 문제
13589정성태3/29/20241197닷넷: 2233. C# - 프로세스 CPU 사용량을 나타내는 성능 카운터와 Win32 API파일 다운로드1
13588정성태3/28/20241550닷넷: 2232. C# - Unity + 닷넷 App(WinForms/WPF) 간의 Named Pipe 통신 [2]파일 다운로드1
13587정성태3/27/20241399오류 유형: 900. Windows Update 오류 - 8024402C, 80070643
13586정성태3/27/20241616Windows: 263. Windows - 복구 파티션(Recovery Partition) 용량을 늘리는 방법
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...