Defender 높은 CPU 문제 진단 및 조정
이 스킬이 해결하는 문제
Windows 개발 머신에서 Microsoft Defender의 실시간 보호는 모든 파일 읽기를 스캔합니다. 특정 프로세스가 대량의 파일을 읽을 때 (IDEA 인덱싱, Codex 프로젝트 스캔, find / 전체 디스크 탐색, Maven 의존성 다운로드, WSL/Docker 내부 IO), Defender는 끊임없는 스캔 파이프라인으로 전환되어 MsMpEng.exe CPU 사용률이 50% 이상으로 치솟고 시스템이 전체적으로 느려집니다.
이 워크플로우의 핵심 통찰은: Defender 높은 CPU는 거의 항상 Defender 자체의 문제가 아니라, 특정 파일 IO 집약적 프로세스가 실시간 보호를 지속적으로 유발하기 때문입니다. 따라서 문제 해결의 핵심은 "Defender 매개변수 조정"이 아니라 트리거 소스를 식별하고 정확한 제외 항목으로 스캔 경로에서 제거하는 것입니다. 이렇게 하면 성능 문제는 해결하면서 전체 보안 태세는 유지됩니다.
문제 해결 프로세스
0단계: Defender 문제인지 확인 및 "측정 기준" 이해
작업 관리자(Task Manager)의 프로세스 CPU 열과 성능 카운터 \Process(*)\% Processor Time의 측정 기준이 다릅니다: 카운터는 멀티코어 머신에서 단일 프로세스가 100%를 초과할 수 있으며 (코어당 100% 합산), 작업 관리자는 카운터 값을 코어 수로 나누어 표시합니다. 따라서 "작업 관리자 61.2%"는 카운터로 766% (20코어 머신)에 해당할 수 있습니다. 두 값 모두 정확하므로 잘못된 기준으로 결론을 내리지 마십시오.
현재 MsMpEng의 실제 사용량을 빠르게 확인합니다 (작업 관리자 기준):
$cores = $env:NUMBER_OF_PROCESSORS
$c = (Get-Counter '\Process(MsMpEng*)\% Processor Time').CounterSamples | Where-Object { $_.InstanceName -like 'msmpeng*' } | Select-Object -First 1
"MsMpEng: 카운터=$([math]::Round($c.CookedValue,1))% 작업 관리자 환산=$([math]::Round($c.CookedValue/$cores,1))% ($cores 코어 머신)"
작업 관리자에 높은 값이 표시되지만 카운터가 지속적으로 0이면, 작업 관리자의 오래된 표시 값이 갱신되지 않은 것입니다. 작업 관리자를 다시 열기만 하면 되며, Defender를 건드릴 필요가 없습니다.
1단계: 트리거 소스 식별 (직감이 아닌 상관 관계 기반)
Defender 높은 CPU의 근본 원인은 세 가지 유형이며, 식별 방법이 다릅니다:
| 근본 원인 | 특징 | 확인 방법 |
|---|---|---|
| 실시간 보호가 외부 프로세스에 의해 트리거됨 (가장 일반적) | MsMpEng CPU가 맥박처럼 변동하며, 동시에 높은 IO를 발생시키는 외부 프로세스가 있음 | 지속적으로 샘플링하여 "MsMpEng가 높을 때 어떤 프로세스의 IO도 높은지" 찾기 |
| 예약/백그라운드 검사 | CPU가 지속적으로 높고 변동이 적음; ScanRunning에 값이 있거나 예약 작업이 실행 중 | Get-MpComputerStatus로 ScanRunning 확인; Get-ScheduledTask -TaskPath '\Microsoft\Windows\Windows Defender\*' |
| Defender 자체 백그라운드 작업 (정의 업데이트 후 검증, 클라우드 샘플링 등) | MsMpEng 자체의 읽기 IO가 가장 높지만, 해당하는 외부 고 IO 프로세스가 없음 | MsMpEng 자체 IO가 다른 프로세스보다 훨씬 높은지 샘플링하여 확인 |
핵심 진단 도구: scripts/diag-mpcpu.ps1을 실행합니다. 이 스크립트는 몇 초 동안 지속적으로 샘플링하며 MsMpEng CPU와 각 프로세스의 IO Data Bytes/sec를 동시에 기록합니다. 해석 방법:
- 특정 프로세스 IO가 높을 때 MsMpEng도 높아짐 → 해당 프로세스가 트리거 소스이며, 2단계로 이동하여 근본적으로 해결
- MsMpEng 자체의 읽기가 가장 높고 외부 고 IO가 없음 → 3단계로 이동 (백그라운드 작업/검사)
- MsMpEng가 전체적으로 0에 가까움 → 문제가 더 이상 Defender에 있지 않으므로 다른 곳에서 원인을 찾으십시오 (사용자가 작업 관리자의 오래된 값을 보고 있을 수 있음)
2단계: 근본적인 해결 — 트리거 소스에 제외 항목 추가
제외 항목에는 두 가지 유형이 있으며, 차이점을 이해하는 것이 중요합니다:
- 프로세스 제외 (ExclusionProcess): 프로세스 이름을 지정합니다 (예:
idea64.exe). 해당 프로세스가 파일을 읽을 때 스캔을 트리거하지 않지만, 다른 프로세스가 해당 파일에 접근하면 여전히 스캔합니다. 정확하고 안전하며 우선적으로 사용합니다. - 경로 제외 (ExclusionPath): 디렉토리를 지정합니다. 해당 디렉토리의 모든 파일은 모든 프로세스 (브라우저, EDR 포함)가 접근해도 스캔되지 않습니다. 캐시/가상 디스크와 같이 '단지 데이터 파일이고 누가 접근하든 스캔하면 안 되는' 시나리오에 적합합니다. 프로젝트 소스 코드 디렉토리에는 사용하지 마십시오 — 프로젝트 소스 코드는 프로세스 제외로 보호되어야 합니다 (개발 도구가 읽을 때만 스캔을 건너뛰고, 브라우저가 동일 디렉토리에 다운로드한 파일은 여전히 스캔됩니다). 이것이
gen-exclusions.ps1경로 유도가 캐시/가상 디스크/도구 설치 루트만 출력하고 절대 프로젝트 디렉토리를 자동 제외하지 않는 이유이기도 합니다.
왜 프로세스 제외가 우선인가: 경로 제외는 디렉토리 내 모든 파일이 '모든 프로세스'에 대해 실시간 보호를 상실하게 만듭니다. 반면 프로세스 제외는 '특정 도구'에 대해서만 보호를 완화하므로 공격 표면이 훨씬 작습니다. 예를 들어 codex.exe 프로세스를 제외하면 Codex가 프로젝트를 읽을 때는 스캔을 건너뛰지만, 브라우저가 동일한 디렉토리로 다운로드한 파일은 여전히 스캔됩니다 — 이것이 바로 우리가 원하는 상태입니다.
scripts/gen-exclusions.ps1을 실행하십시오. 이 스크립트는 현재 실행 중인 개발 관련 프로세스를 스캔하고 알려진 도구 패턴과 일치시켜 자동으로 권장 프로세스 + 경로 제외 항목을 생성합니다. 기본적으로 DryRun 모드로 미리보기 (제안 및 이유 포함)를 표시하며, 확인 후 -Apply 옵션을 추가하여 Defender에 기록합니다. 이 작업은 멱등성을 가지며 실행 전에 현재 제외 항목을 백업합니다.
3단계: 백그라운드 검사 유형 근본 원인 처리
예약 검사/자동 유지 관리가 실행 중인 경우 (ScanRunning에 값이 있거나 예약 작업 상태가 Running), 일반적으로 완료될 때까지 기다리는 것이 좋으며 강제로 종료해서는 안 됩니다. 이는 Defender가 필요한 보안 유지 관리를 수행하는 중입니다. 불편한 시간에 반복적으로 트리거되는 경우, 일정을 조정하십시오:
# 예약 검사 확인
Get-ScheduledTask -TaskPath '\Microsoft\Windows\Windows Defender\*'
# 빠른 검사 시간 조정 (예: 매일 오전 3시) — 기존 예약 검사 구성을 덮어씁니다
Set-MpPreference -ScanScheduleQuickScanTime 03:00:00
정의 업데이트 후 전체 검증이 발생하는 경우 (드물게 발생), 일반적으로 일회성이며 완료되면 끝납니다.
4단계: 검증
제외 항목을 추가한 후, 원래의 높은 IO 부하를 다시 트리거하고 (IDE 재개방, find 다시 실행, Codex로 프로젝트 다시 스캔), diag-mpcpu.ps1을 다시 실행합니다. 성공 기준은: 동일한 IO 부하에서 MsMpEng가 원래의 높은 수치에서 0에 가깝게 떨어지는 것입니다. 감소하지 않았다면 제외 항목이 실제 트리거 소스를 포괄하지 못한 것입니다. 1단계로 돌아가서 진단 출력에서 어떤 프로세스가 여전히 동시에 높은 CPU를 보이는지 확인하십시오.
보안 경계 — 절대 제외하지 않는 항목
제외 항목은 해당 경로/프로세스의 실시간 보호를 낮추므로 경계가 필요합니다. 다음은 절대 제외 항목에 포함되어서는 안 됩니다. 아무리 "CPU를 절약"해 보여도 마찬가지입니다 (완전하고 권위 있는 목록은 scripts/gen-exclusions.ps1의 $denyProcs 및 $denyPathPrefix가 단일 진실 공급원이며, 이 문서 목록은 설명 목적으로만 제공됩니다):
- 시스템 프로세스:
svchost.exe,dllhost.exe,smartscreen.exe,conhost.exe,lsass.exe,csrss.exe등 - 브라우저 및 WebView:
msedge.exe,chrome.exe,msedgewebview2.exe— 브라우저 다운로드는 주요 악성코드 진입 경로이므로 스캔을 유지합니다. - 보안/관리 클라이언트: 회사에서 설치한 EDR, VPN 클라이언트 (예: 深信服 ECAgent, CrowdStrike, SentinelOne) — 이를 변경하면 규정 준수 경고가 발생할 수 있으며, 이는 보안 방어선입니다.
- 전체 사용자 디렉토리 / 시스템 드라이브 루트: 세분화 정도가 너무 낮아 사실상 무방비 상태가 됩니다.
*.jar,*.exe,*.dll,*.ps1등 실행 가능한 확장자: 실행 가능하므로 스캔을 유지합니다. 확장자 제외는 순수 컴파일 산출물 (*.class)이나 로그 (*.log)와 같이 실행 불가능한 파일에만 사용해야 합니다.
판단 원칙: 제외 항목은 '신뢰할 수 있는 개발 도구가 본연의 작업을 수행할 때 읽는 파일'을 목표로 해야 하며, 'CPU를 절약하기 위해 모든 것을 제외'해서는 안 됩니다.
고급 진단: Performance Recorder
진단 스크립트가 여전히 정확하게 식별하지 못하는 경우, Defender 공식 성능 기록기 (관리자 권한 필요)를 사용하십시오. 이 도구는 MsMpEng가 시간을 어떤 특정 경로/프로세스에 소비하는지에 대한 정확한 보고서를 제공합니다:
New-MpPerformanceRecord -RecordTo C:\perf.mpdr # 60초 수집 (높은 CPU를 재현하는 동안)
# 보고서는 가장 CPU를 많이 소비하는 경로와 프로세스를 지적하므로, 이를 기반으로 정확한 제외 항목을 추가합니다.
참조 파일
references/common-exclusions.md— 일반적인 개발 도구에 대한 권장 제외 항목 분류 목록 (IDE/Java/Node/WSL/Docker/AI 코딩 어시스턴트/빌드 캐시)으로, 각 분류의 보안 절충에 대한 설명을 포함합니다. 제외 항목 생성 시 이 파일을 사용하여 범위를 확인합니다.scripts/diag-mpcpu.ps1— 진단 샘플링 스크립트scripts/gen-exclusions.ps1— 제외 항목을 자동 생성하고 적용합니다 (기본적으로 미리보기)