디스크 100%인데 속도는 1MB/s?|Baroit Disk LAB로 SSD·HDD 병목 직접 진단

작업 관리자를 열었는데 디스크가 활성 시간 100%에 붙어 있습니다.

그런데 전송속도를 보면 이상합니다.

활성 시간 100% 읽기 속도 0.4 MB/s 쓰기 속도 1.1 MB/s 평균 응답시간 280 ms

SSD가 초당 수백 MB를 읽을 수 있는데 1MB/s밖에 안 쓰면서 어떻게 100%가 될까요?

디스크 사용률 100%는 '최대 전송속도를 100% 사용한다'는 뜻이 아닙니다.

저장장치 입장에서는 처리하지 못한 I/O 요청 때문에 계속 바쁜 상태여도 활성 시간은 100%에 도달할 수 있습니다.

그래서 이 문제는 MB/s가 아니라 Latency → IOPS → Queue → 실제 요청 프로세스 순서로 봐야 합니다.
분해된 하드디스크 플래터와 헤드
2.5인치 HDD 내부 플래터와 헤드 / 출처: Wikimedia Commons / 저작자: Malcolm Koo(Mk2010) / CC BY 4.0

Baroit LAB 01 — 100%라는 숫자를 먼저 무시합니다

저장장치 문제를 볼 때 처음부터 SysMain이나 Windows Search를 끄지 않습니다.

먼저 현재 상태를 아래 네 값으로 바꿉니다.

BAROIT DISK SIGNATURE
Latency IOPS Throughput Queue
Latency
I/O 하나를 끝내는 데 얼마나 오래 걸렸는가?
IOPS
1초 동안 몇 개의 읽기·쓰기 요청을 처리했는가?
Throughput
실제로 초당 몇 MB를 옮겼는가?
Queue
처리되지 못하고 기다리는 요청이 있는가?

왜 1MB/s인데 디스크가 100%가 될까?

예를 들어 4KB짜리 작은 파일을 무작위 위치에서 계속 읽는 상황을 생각해보겠습니다.

4 KB × 1,000 IOPS = 약 4 MB/s

전송량은 겨우 몇 MB/s입니다.

하지만 저장장치가 초당 1,000개의 요청을 처리하느라 계속 바쁘다면 활성 시간은 매우 높아질 수 있습니다.

특히 HDD는 데이터를 읽기 위해 헤드를 실제 위치로 움직여야 하므로 순차 읽기와 무작위 작은 I/O의 성능 차이가 큽니다.

그래서 MB/s만 보면 저장장치 병목을 놓칠 수 있습니다.

100MB/s + 5ms
보다

2MB/s + 300ms

가 체감상 훨씬 심각한 상황일 수도 있습니다.

Baroit 기준값 — 먼저 응답시간을 봅니다

Microsoft의 Windows 성능 문제 해결 가이드는 PhysicalDisk와 LogicalDisk의 평균 Read/Write Latency에 다음 참고선을 제시합니다.

평균 Read/Write Latency Baroit 판정 의미
15ms 미만 정상 범위 Latency만으로 병목 증거 부족
15~25ms 관찰 워크로드와 장치 종류 함께 확인
25ms 초과 경고 지속된다면 I/O 지연 조사
50ms 초과 위험 지속적 Storage Latency 조사

중요한 조건이 하나 더 있습니다.

Microsoft도 순간적인 짧은 Spike는 허용될 수 있고, 1분 이상 지속되는 Latency를 더 중요하게 조사하도록 설명합니다.

작업 관리자를 딱 2초 보고 응답시간 80ms가 한 번 찍혔다고 SSD 불량으로 판정하면 안 됩니다.

그래서 Baroit에서는 60초 동안 측정합니다.

Baroit LAB 02 — 60초 저장장치 검사

아래 검사는 별도 프로그램이 필요 없습니다.

문제가 실제로 발생하고 있는 상태에서 PowerShell을 열고 아래 전체 코드를 한 번에 붙여넣습니다.

검사 시간은 약 60초입니다. 파일을 삭제하거나 설정을 변경하지 않습니다.

# ============================================== # BAROIT DISK LAB v1.0 # 60-second Windows storage diagnosis # ============================================== $SampleSeconds = 5 $Loops = 12 function Get-Delta32([uint32]$old,[uint32]$new){ if($new -ge $old){ return [uint64]($new-$old) } return ([uint64][uint32]::MaxValue + 1 + $new - $old) } function Get-Delta64([uint64]$old,[uint64]$new){ if($new -ge $old){ return ($new-$old) } return ([decimal][uint64]::MaxValue + 1 + $new - $old) } Write-Host "" Write-Host "========================================" Write-Host " BAROIT DISK LAB v1.0" Write-Host " 60초 동안 저장장치 I/O를 측정합니다." Write-Host " 문제가 발생한 상태를 유지하세요." Write-Host "========================================" Write-Host "" $diskInfo = @{} Get-Disk -ErrorAction SilentlyContinue | ForEach-Object { $diskInfo[[string]$_.Number] = $_ } $result = @{} $prev = Get-CimInstance Win32_PerfRawData_PerfDisk_PhysicalDisk | Where-Object {$_.Name -ne "_Total"} for($i=1; $i -le $Loops; $i++){ Start-Sleep -Seconds $SampleSeconds $curr = Get-CimInstance Win32_PerfRawData_PerfDisk_PhysicalDisk | Where-Object {$_.Name -ne "_Total"} foreach($c in $curr){ $p = $prev | Where-Object {$_.Name -eq $c.Name} if(!$p){continue} if(!$result.ContainsKey($c.Name)){ $result[$c.Name] = [ordered]@{ ReadTicks = [decimal]0 ReadOps = [decimal]0 WriteTicks = [decimal]0 WriteOps = [decimal]0 Bytes = [decimal]0 IOs = [decimal]0 Time = [decimal]0 MaxQueue = 0 } } $r = $result[$c.Name] $r.ReadTicks += Get-Delta32 $p.AvgDiskSecPerRead $c.AvgDiskSecPerRead $r.ReadOps += Get-Delta32 $p.AvgDiskSecPerRead_Base $c.AvgDiskSecPerRead_Base $r.WriteTicks += Get-Delta32 $p.AvgDiskSecPerWrite $c.AvgDiskSecPerWrite $r.WriteOps += Get-Delta32 $p.AvgDiskSecPerWrite_Base $c.AvgDiskSecPerWrite_Base $r.Bytes += Get-Delta64 $p.DiskBytesPerSec $c.DiskBytesPerSec $r.IOs += Get-Delta32 $p.DiskTransfersPerSec $c.DiskTransfersPerSec $dt = ([decimal](Get-Delta64 $p.Timestamp_PerfTime $c.Timestamp_PerfTime)) / [decimal]$c.Frequency_PerfTime $r.Time += $dt if([int]$c.CurrentDiskQueueLength -gt $r.MaxQueue){ $r.MaxQueue = [int]$c.CurrentDiskQueueLength } } $prev = $curr Write-Progress ` -Activity "BAROIT DISK LAB" ` -Status "$($i*$SampleSeconds) / $($Loops*$SampleSeconds) 초" ` -PercentComplete (($i/$Loops)*100) } Write-Progress -Activity "BAROIT DISK LAB" -Completed Write-Host "" Write-Host "============= RESULT =============" foreach($name in $result.Keys){ $r = $result[$name] $num = $null if($name -match '^(\d+)'){ $num = $matches[1] } $di = $diskInfo[$num] $readMS = 0 $writeMS = 0 if($r.ReadOps -gt 0){ $readMS = (($r.ReadTicks / [decimal]$curr[0].Frequency_PerfTime) / $r.ReadOps) * 1000 } if($r.WriteOps -gt 0){ $writeMS = (($r.WriteTicks / [decimal]$curr[0].Frequency_PerfTime) / $r.WriteOps) * 1000 } $mbps = 0 $iops = 0 if($r.Time -gt 0){ $mbps = ($r.Bytes / $r.Time) / 1MB $iops = $r.IOs / $r.Time } $maxLatency = [math]::Max([double]$readMS,[double]$writeMS) if($maxLatency -gt 50){ $grade = "CRITICAL" } elseif($maxLatency -gt 25){ $grade = "WARNING" } elseif($maxLatency -lt 15){ $grade = "NORMAL" } else{ $grade = "WATCH" } Write-Host "" Write-Host "Disk Instance : $name" if($di){ Write-Host "Model : $($di.FriendlyName)" Write-Host "Bus : $($di.BusType)" Write-Host "Health : $($di.HealthStatus)" } Write-Host ("Read Latency : {0:N1} ms" -f $readMS) Write-Host ("Write Latency : {0:N1} ms" -f $writeMS) Write-Host ("Average IOPS : {0:N0}" -f $iops) Write-Host ("Average MB/s : {0:N1}" -f $mbps) Write-Host ("Max Queue : {0}" -f $r.MaxQueue) Write-Host "BAROIT Grade : $grade" } Write-Host "" Write-Host "======= STORAGE EVENTS / 7 DAYS =======" $events = Get-WinEvent ` -FilterHashtable @{ LogName='System' Id=129,153 StartTime=(Get-Date).AddDays(-7) } ` -ErrorAction SilentlyContinue Write-Host "Event 129/153 Count : $($events.Count)" if($events.Count -gt 0){ $events | Select-Object -First 10 TimeCreated,Id,ProviderName,Message | Format-List } Write-Host "" Write-Host "========================================" Write-Host " BAROIT DISK LAB END" Write-Host "========================================"

검사 결과를 이렇게 읽습니다

예를 들어 결과가 다음과 같다고 해보겠습니다.

Disk Instance : 0 C: Model : Samsung SSD Bus : NVMe Health : Healthy Read Latency : 86.2 ms Write Latency : 71.4 ms Average IOPS : 92 Average MB/s : 1.8 Max Queue : 7 BAROIT Grade : CRITICAL Event 129/153 Count : 0

여기서 중요한 건 `Health = Healthy`가 아닙니다.

실제 증상이 발생하는 60초 동안 읽기와 쓰기 모두 50ms를 크게 넘고 있습니다.

Baroit 판정

전송량은 1.8MB/s밖에 안 되는데
Latency 70~80ms + Queue 7 발생

→ 단순히 대용량 파일을 빠르게 복사해서 디스크를 100% 사용하는 형태가 아님.

→ I/O 요청이 오래 기다리는 Storage Stall 패턴으로 분류.

→ 다음 단계는 어떤 프로세스와 파일 요청에서 지연이 발생하는지 조사.

Baroit 자동판정기

위 검사 결과나 작업 관리자·리소스 모니터에서 확인한 값을 아래에 입력하면 기본 진단 방향을 자동으로 표시합니다.

🔬 Baroit Disk Analyzer

값을 모르면 0으로 두세요.

LAB 03 — 누가 I/O를 발생시키는지 찾습니다

Storage Stall이 확인되면 그때부터 프로세스를 봅니다.

Windows 기본 기능으로는:

Win + R resmon

을 실행합니다.

디스크 탭을 선택합니다.

여기서 중요한 영역은 두 군데입니다.

영역 확인하는 것
디스크 작업이 있는 프로세스 어떤 프로세스가 I/O를 만드는가
디스크 작업 정확히 어떤 파일을 읽고 쓰는가
응답 시간 특정 파일 I/O가 몇 ms 걸리는가
읽기/쓰기 B/sec 실제 데이터 이동량

프로세스 이름보다 '파일 경로'를 봐야 하는 이유

예를 들어 `System`이 디스크를 많이 사용하는 것으로 보인다고 합시다.

여기서:

System이 디스크 많이 씀 → Windows 문제

라고 결론 내리면 안 됩니다.

System 프로세스를 통해 수행되는 커널 I/O가 많기 때문입니다.

파일 경로를 확인해야 의미가 생깁니다.

예시 A

C:\pagefile.sys

→ 메모리 압박과 Paging 연관성 조사
예시 B

C:\Windows\SoftwareDistribution\...

→ Windows Update 작업 여부 조사
예시 C

C:\ProgramData\Microsoft\Search\...

→ Search Index 관련 I/O인지 확인
예시 D

게임 폴더의 수천 개 작은 파일

→ 게임 패치·검증·압축해제 과정의 Random I/O 가능

이렇게 해야 서비스를 끌지 말아야 할 경우와 실제 문제 서비스를 구분할 수 있습니다.

Microsoft Sysinternals Process Monitor 화면
Microsoft Sysinternals Process Monitor / 출처: Wikimedia Commons / 저작자: Lordseriouspig / CC0 1.0

LAB 04 — Resource Monitor로 안 잡히면 ProcMon까지 갑니다

Microsoft Sysinternals의 Process Monitor는 파일시스템, Registry, 프로세스·스레드 활동을 실시간으로 기록합니다.

2026년 8월에도 업데이트가 계속되는 Microsoft 공식 진단 도구입니다.

이번 문제에서는 Registry 이벤트를 전부 볼 필요가 없습니다.

Baroit ProcMon 절차

1. Process Monitor 실행

2. File System Activity만 남김

3. 문제가 생길 때까지 10~30초 기록

4. 캡처 중지

5. Operation의 ReadFile / WriteFile 확인

6. Duration이 긴 요청부터 확인

7. Process Name + Path를 같이 기록
여기서 중요한 것은 “어떤 프로그램이 많이 읽었나?”보다 “어떤 요청이 오래 끝나지 않았나?”입니다.

Storage Stall에서는 총 전송량이 작아도 하나의 I/O가 수백 ms씩 걸리며 전체 시스템을 기다리게 만들 수 있습니다.

HDD라면 낮은 MB/s + 높은 사용률이 더 쉽게 발생합니다

HDD는 내부 플래터가 회전하고 헤드가 실제 데이터 위치로 이동해야 합니다.

예를 들어 큰 동영상 하나를 순차적으로 읽는 것과 수천 개 작은 파일을 여기저기 읽는 작업은 같은 50MB/s라도 부하 특성이 완전히 다릅니다.

Microsoft 성능 가이드에서도 5,400RPM HDD를 예로 들어 물리적인 회전 지연 때문에 약 11ms 수준의 시간 자체가 발생할 수 있음을 설명합니다.

HDD와 SATA SSD NVMe SSD 크기 비교
HDD·M.2 SATA SSD·NVMe SSD 비교 / 출처: Wikimedia Commons / 저작자: User5515 / CC0 1.0

SSD는 기계식 헤드가 없는데 왜 100%가 될까?

SSD에도 대기시간은 존재합니다.

내부에는:

Host I/O ↓ SSD Controller ↓ FTL / Mapping ↓ NAND Flash ↓ Garbage Collection ↓ 실제 Read / Program / Erase

과정이 있습니다.

또한 NAND는 데이터를 덮어쓰는 방식이 아니라 Erase 단위 관리가 필요하므로 SLC Cache 소진, Garbage Collection, NAND 상태, 펌웨어 동작 등에 따라 응답시간이 달라질 수 있습니다.

분해된 SATA SSD 컨트롤러와 NAND
SandForce 컨트롤러 기반 SSD 내부 / 출처: Wikimedia Commons / 저작자: Hans Haase / CC BY-SA 3.0

NVMe라고 해서 100% 사용률이 무조건 이상한 것도 아닙니다

NVMe는 PCI Express 기반으로 높은 병렬성과 Queue 처리를 지원합니다.

따라서 NVMe의 Queue 숫자와 HDD의 Queue 숫자를 똑같은 기준으로 기계적으로 비교하면 안 됩니다.

M.2 NVMe SSD
M.2 2230 NVMe SSD / 출처: Wikimedia Commons / 저작자: User5515 / CC0 1.0
그래서 Baroit Analyzer에서도 Queue 하나만으로 불량 판정을 하지 않습니다.

Queue는 Latency와 Throughput을 설명하는 보조 증거로 사용합니다.

LAB 05 — 이벤트 로그에서 'Storage가 실제로 재시도했는지' 확인

여기서 다른 일반 해결글과 진단 강도가 크게 갈립니다.

System 이벤트 로그에 129 또는 153이 있는지 확인합니다.

앞의 Baroit PowerShell은 최근 7일간 두 이벤트를 자동으로 찾습니다.

Event Microsoft 설명 Baroit 해석
129 Storport가 디스크 요청 Timeout 후 Reset 요청 스토리지 경로 Timeout 증거
153 I/O 요청이 Timeout되어 Retry됨 I/O가 제시간에 완료되지 못한 증거
157 Disk가 Surprise Removed됨 연결·전원·장치 손실도 조사

Microsoft의 현재 디스크 오류 가이드에서도 Event 153은 Storage Subsystem이 과부하되어 요청 Timeout이 발생했음을 나타낼 수 있고, 129는 Storport 단계의 요청 Timeout과 연결된다고 설명합니다.

하지만 Event 129 또는 153 = SSD 고장 확정은 아닙니다.

Storage Controller,
드라이버,
케이블,
전원,
펌웨어,
실제 과부하

등에서도 발생할 수 있습니다.

이벤트는 “I/O가 정상 시간 안에 끝나지 않았다”는 증거로 사용해야 합니다.
SATA 데이터 케이블
SATA 데이터 케이블 / 출처: Wikimedia Commons / 저작자: Evan-Amos / Public Domain

SATA SSD라면 케이블도 진단 경로에 들어갑니다

NVMe와 SATA는 저장장치가 PC와 연결되는 경로가 다릅니다.

SATA SSD·HDD에서는:

SSD / HDD ↓ SATA Data Cable ↓ Motherboard SATA Controller ↓ Driver ↓ Windows Storage Stack

경로를 사용합니다.

따라서 SATA 장치에서 반복되는 I/O Retry나 장치 인식 끊김까지 함께 나타난다면 저장장치 자체뿐 아니라 데이터 케이블·포트·전원 연결도 분리해서 테스트할 가치가 있습니다.

Baroit Failure Matrix — 이제 원인을 좁힙니다

측정 결과 우선 진단
100% + Latency 정상 + MB/s 높음 정상적인 고부하 작업 가능성
100% + Latency 정상 + 작은 I/O 다수 워크로드 특성 확인
100% + Latency 50ms↑ + Queue 증가 I/O Saturation / Stall
100% + Latency 50ms↑ + MB/s 매우 낮음 장치 응답지연·Random I/O·Storage Path 조사
Latency 높음 + Event 129/153 반복 스토리지 Timeout 계층 우선
SATA + 장치가 가끔 사라짐 SSD/HDD + SATA 케이블 + 포트 + 전원
특정 프로세스 실행 때만 발생 해당 프로세스 I/O Pattern 조사
pagefile.sys I/O + Available RAM 매우 낮음 메모리 압박을 원인 후보에 추가
재부팅 후 정상, 시간 지나면 재발 백그라운드 작업·드라이버·장치 상태 추세 분석

그래서 SysMain을 끄면 되는 건가?

아직 아닙니다.

SysMain을 중지했는데 디스크 사용률이 떨어졌다면 그 결과는 중요한 진단 데이터입니다.

하지만:

SysMain OFF → 디스크 100% 사라짐 → SysMain이 고장

으로 바로 결론 내리면 안 됩니다.

SysMain이 수행하던 I/O가 느린 HDD나 이미 문제가 있는 Storage Path의 증상을 드러냈을 수도 있기 때문입니다.

Baroit에서는 서비스를 끄기 전에 Latency와 실제 파일 I/O를 측정합니다.

그래야

“부하를 없애서 증상만 숨긴 것”인지
“해당 서비스가 비정상적인 요청을 만들고 있던 것”인지

구분할 수 있습니다.

Windows Search도 무조건 끄지 않습니다

SearchIndexer.exe가 디스크를 사용하고 있다면 다음 질문으로 넘어갑니다.

1. 인덱싱 중 Latency는 정상인가?

YES
→ 단순 백그라운드 I/O일 수 있음

NO
→ 저장장치가 요청을 처리하는 데 오래 걸리는 이유 추가 조사

즉 프로세스 이름 하나를 악당으로 지정하지 않습니다.

CHKDSK도 디스크 100% 만능 해결법이 아닙니다

`chkdsk`는 파일 시스템 무결성을 검사하는 도구입니다.

Storage Latency의 원인이 Windows 파일 시스템인지 확인할 필요가 있다면 사용할 수 있지만, SSD 컨트롤러나 SATA 케이블의 I/O Timeout을 고치는 도구는 아닙니다.

Microsoft가 현재 디스크 오류 진단에서 먼저 제시하는 변경 없는 스캔 방법은:

chkdsk /scan

입니다.

실제 디스크 오류 이벤트까지 같이 발생하는 경우 파일 시스템 검사와 Storage Hardware/Driver 분석을 따로 진행해야 합니다.

Baroit의 자가조치 종료선

아래 조건에서는 `서비스 끄기`를 계속 반복하는 것보다 데이터 백업과 저장장치 계층 점검이 우선입니다.

① 60초 평균 Latency가 반복적으로 50ms를 크게 넘음

② Event 129 또는 153이 같은 시점에 반복됨

③ SSD/HDD가 BIOS 또는 Windows에서 간헐적으로 사라짐

④ 파일 복사에서 CRC·I/O Error까지 발생

⑤ SMART / 제조사 진단에서도 오류 발생

⑥ SATA 케이블·포트 교차시험에서도 동일

⑦ 다른 정상 Storage Workload에서도 동일한 Latency 발생

이 상태에서는 중요한 데이터를 먼저 백업한 뒤 저장장치·Controller·Driver·연결경로를 점검하는 것이 맞습니다.

이번 글의 진단 흐름만 기억하면 됩니다

BAROIT DISK LAB FLOW
디스크 100%
↓

1. 60초 Latency 측정
↓

Latency 정상
→ 실제 Workload 분석

Latency 높음
→ 다음 단계

2. Throughput + IOPS + Queue 비교
↓

3. Resource Monitor에서 Process + File Path 확인
↓

4. 필요하면 ProcMon으로 긴 I/O 추적
↓

5. Event 129 / 153 확인
↓

6. SATA / NVMe 연결계층 분리
↓

7. SMART / 제조사 진단
↓

8. 원인이 확인된 뒤에만 서비스·드라이버·하드웨어 조치

결론

작업 관리자에서 디스크 100%라고 뜨는 것은 진단 결과가 아니라 증상입니다.

진짜 중요한 것은

얼마나 많은 데이터를 옮겼는가가 아니라, 각 I/O가 얼마나 오래 기다렸는가

입니다.

그래서 Baroit에서는 `디스크 100% → SysMain 끄기`로 바로 가지 않습니다.

Latency → IOPS → Throughput → Queue → Process → File → Event 순서로 증거를 쌓습니다.

이렇게 하면 SSD가 실제로 느린 것인지, 특정 프로그램이 작은 I/O를 쏟아내는 것인지, 메모리 부족 때문에 Pagefile이 바쁜 것인지, 스토리지 요청 자체가 Timeout되고 있는지를 서로 분리할 수 있습니다.

그리고 그때부터 해결방법이 하나가 아니라 측정 결과에 맞는 해결방법 하나로 좁혀집니다.

검증 자료

Microsoft Learn - Troubleshoot performance problems in Windows
· Avg. Disk sec/Read 및 Write Latency 참고 기준
· 15ms / 25ms / 50ms 수준
· 순간 Spike보다 지속되는 Latency 조사

Microsoft Sysinternals - Process Monitor v4.1
· 실시간 파일시스템·Registry·Process/Thread 활동 추적
· 2026년 8월 업데이트

Microsoft Learn - Guidance for Troubleshooting Data Corruption and Disk Errors
· Event ID 129 / 153 / 157 의미
· Storage Timeout 및 Retry 진단
· chkdsk /scan

Microsoft Learn - Win32_PerfRawData_PerfDisk_PhysicalDisk
· AvgDiskSecPerRead / Write
· Queue Length
· Disk Bytes/sec
· Disk Transfers/sec 등 Windows Performance Counter 정의

이미지 1
Hard disk drive platter, Samsung MP0402H.jpg
Malcolm Koo(Mk2010) / CC BY 4.0

이미지 2
Process Monitor Screenshot.png
Lordseriouspig / CC0 1.0

이미지 3
SEAGATE 7200.9 HDD + M.2 SATA + NVMe SSD.jpg
User5515 / CC0 1.0

이미지 4
Sf-ssd.jpg
Hans Haase / CC BY-SA 3.0

이미지 5
CL4-3D256GB-Q11.jpg
User5515 / CC0 1.0

이미지 6
SATA-cable.jpg
Evan-Amos / Public Domain

확인일: 2026년 9월 1일