이 문서는 .NET Core 3.1 SDK 이상 버전에 적용됩니다 ✔️.
이 자습서에서는 과도한 CPU 사용 시나리오를 디버그하는 방법을 알아봅니다. 제공된 예제 ASP.NET Core 웹앱 소스 코드 리포지토리를 사용하여 의도적으로 교착 상태를 일으킬 수 있습니다. 엔드포인트는 응답을 중지하고 스레드 누적을 경험합니다. 다양한 도구를 사용하여 진단 데이터의 몇 가지 주요 부분을 사용하여 이 시나리오를 진단하는 방법을 알아봅니다.
이 자습서에서는 다음을 수행합니다.
- 높은 CPU 사용량 조사
- dotnet-counters를 사용하여 CPU 사용량 확인
- 추적 생성에 dotnet-trace 사용
- PerfView의 프로필 성능
- 과도한 CPU 사용량 진단 및 해결
필수 조건
이 자습서에서는 다음을 사용합니다.
- .NET Core 3.1 SDK 이상 버전.
- 시나리오를 트리거하는 샘플 디버그 대상입니다.
- dotnet-trace 를 사용하여 프로세스를 나열하고 프로필을 생성합니다.
- cpu 사용량을 모니터링하는 dotnet-counters입니다.
CPU 카운터
이 자습서를 시도하기 전에 최신 버전의 dotnet-counters를 설치하세요.
dotnet tool install --global dotnet-counters
앱이 .NET 9보다 오래된 .NET 버전을 실행하는 경우 dotnet-counters의 출력 UI는 약간 다르게 표시됩니다. 자세한 내용은 dotnet-counters를 참조하세요 .
진단 데이터를 수집하기 전에 높은 CPU 상태를 관찰해야 합니다. 프로젝트 루트 디렉터리에서 다음 명령을 사용하여 샘플 애플리케이션 을 실행합니다.
dotnet run
현재 CPU 사용량을 확인하려면 dotnet-counters 도구 명령을 사용합니다.
dotnet-counters monitor -n DiagnosticScenarios --showDeltas
출력은 다음과 유사해야 합니다.
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value Last Delta
[System.Runtime]
dotnet.assembly.count ({assembly}) 111 0
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 8 0
gen1 1 0
gen2 0 0
dotnet.gc.heap.total_allocated (By) 4,042,656 24,512
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 801,728 0
gen1 6,048 0
gen2 0 0
loh 0 0
poh 0 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,512 0
gen1 562,024 0
gen2 1,095,056 0
loh 98,384 0
poh 24,528 0
dotnet.gc.last_collection.memory.committed_size (By) 5,623,808 0
dotnet.gc.pause.time (s) 0.019 0
dotnet.jit.compilation.time (s) 0.582 0
dotnet.jit.compiled_il.size (By) 138,895 0
dotnet.jit.compiled_methods ({method}) 1,470 0
dotnet.monitor.lock_contentions ({contention}) 4 0
dotnet.process.cpu.count ({cpu}) 22 0
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.109 0
user 0.453 0
dotnet.process.memory.working_set (By) 65,515,520 0
dotnet.thread_pool.queue.length ({work_item}) 0 0
dotnet.thread_pool.thread.count ({thread}) 0 0
dotnet.thread_pool.work_item.count ({work_item}) 6 0
dotnet.timer.count ({timer}) 0 0
값Last Delta에 dotnet.process.cpu.time 초점을 맞추면 새로 고침 기간(현재 기본값인 1초로 설정됨) 내에 CPU가 활성화된 시간(초)이 표시됩니다. 웹앱이 실행되면 시작 직후 CPU가 전혀 소비되지 않으며 이러한 델타는 둘 다 0됩니다.
api/diagscenario/highcpu 경로 매개 변수로 경로 60000 로 이동합니다.
https://localhost:5001/api/diagscenario/highcpu/60000
이제 dotnet-counters 명령을 다시 실행합니다.
dotnet-counters monitor -n DiagnosticScenarios --showDeltas
아래와 같이 CPU 사용량이 증가해야 합니다(호스트 머신에 따라 다양한 CPU 사용량이 예상됨).
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value Last Delta
[System.Runtime]
dotnet.assembly.count ({assembly}) 111 0
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 8 0
gen1 1 0
gen2 0 0
dotnet.gc.heap.total_allocated (By) 4,042,656 24,512
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 801,728 0
gen1 6,048 0
gen2 0 0
loh 0 0
poh 0 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,512 0
gen1 562,024 0
gen2 1,095,056 0
loh 98,384 0
poh 24,528 0
dotnet.gc.last_collection.memory.committed_size (By) 5,623,808 0
dotnet.gc.pause.time (s) 0.019 0
dotnet.jit.compilation.time (s) 0.582 0
dotnet.jit.compiled_il.size (By) 138,895 0
dotnet.jit.compiled_methods ({method}) 1,470 0
dotnet.monitor.lock_contentions ({contention}) 4 0
dotnet.process.cpu.count ({cpu}) 22 0
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.344 0.013
user 14.203 0.963
dotnet.process.memory.working_set (By) 65,515,520 0
dotnet.thread_pool.queue.length ({work_item}) 0 0
dotnet.thread_pool.thread.count ({thread}) 0 0
dotnet.thread_pool.work_item.count ({work_item}) 6 0
dotnet.timer.count ({timer}) 0 0
요청 기간 동안 CPU 사용량은 증가된 값을 가리킵니다.
팁 (조언)
더 높은 CPU 사용량을 시각화하려면 동시에 여러 브라우저 탭에서 이 엔드포인트를 연습할 수 있습니다.
이 시점에서 CPU가 예상보다 높게 실행되고 있다고 안전하게 말할 수 있습니다. 문제의 영향을 식별하는 것이 원인을 찾는 데 중요합니다. 문제의 원인을 찾기 위해 진단 도구 외에도 높은 CPU 사용량의 효과를 사용합니다.
프로파일러를 사용하여 높은 CPU 분석
CPU 사용량이 높은 앱을 분석할 때 코드가 수행하는 작업을 파악할 수 있는 진단 도구가 필요합니다. 일반적인 선택은 프로파일러이며 선택할 수 있는 프로파일러 옵션이 서로 다릅니다.
dotnet-trace 는 모든 운영 체제에서 사용할 수 있지만 안전 지점 바이어스 및 관리 전용 호출 스택의 제한으로 인해 Linux용 'perf' 또는 Windows용 ETW와 같은 커널 인식 프로파일러에 비해 더 일반적인 정보가 생성됩니다. 성능 조사에 관리 코드만 포함된 경우 일반적으로 dotnet-trace 충분합니다.
이 perf 도구를 사용하여 .NET Core 앱 프로필을 생성할 수 있습니다. dotnet 추적도 사용할 수 있지만 이 도구를 보여 줍니다.
샘플 디버그 대상의 이전 인스턴스를 종료합니다.
.NET 앱이 DOTNET_PerfMapEnabled 디렉터리에 파일을 만들도록 환경 변수를 map/tmp 설정합니다. 이 map 파일은 이름으로 JIT 생성 함수에 CPU 주소를 매핑하는 데 사용됩니다 perf . 자세한 내용은 성능 맵 및 jit 덤프 내보내기를 참조하세요.
동일한 터미널 세션에서 샘플 디버그 대상 을 실행합니다.
export DOTNET_PerfMapEnabled=1
dotnet run
높은 CPU API 엔드포인트()를https://localhost:5001/api/diagscenario/highcpu/60000 다시 실행합니다. 1분 요청 내에서 실행되는 동안 프로세스 ID를 사용하여 perf 명령을 실행합니다.
sudo perf record -p 2266 -g
이 perf 명령은 성능 수집 프로세스를 시작합니다. 약 20-30초 동안 실행한 다음 Ctrl+C 를 눌러 컬렉션 프로세스를 종료합니다. 동일한 perf 명령을 사용하여 추적의 출력을 볼 수 있습니다.
sudo perf report -f
다음 명령을 사용하여 화염 그래프 를 생성할 수도 있습니다.
git clone --depth=1 https://github.com/BrendanGregg/FlameGraph
sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
이 명령은 성능 문제를 조사하기 위해 브라우저에서 볼 수 있는 항목을 생성 flamegraph.svg 합니다.
Visual Studio를 사용하여 높은 CPU 데이터 분석
모든 *.nettrace 파일은 Visual Studio에서 분석할 수 있습니다. Visual Studio에서 Linux *.nettrace 파일을 분석하려면 필요한 다른 문서 외에도 *.nettrace 파일을 Windows 컴퓨터로 전송한 다음 Visual Studio에서 *.nettrace 파일을 엽니다. 자세한 내용은 CPU 사용량 현황 데이터 분석을 참조하세요.
참고하십시오
- 프로세스를 나열하는 dotnet-trace
- 관리되는 메모리 사용량을 확인하기 위한 dotnet-counters
- 덤프 파일을 수집하고 분석하는 dotnet-dump
- dotnet/diagnostics
다음 단계
.NET