Skip to content

필사 모드: 리눅스 성능 도구 완전 가이드: 출력의 숫자를 해석하는 법

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며

성능 도구를 배우는 것과 성능 도구의 출력을 읽는 것은 다른 일입니다. iostat -x를 칠 줄 아는 사람은 많지만, %util이 100퍼센트라는 결과를 보고 "그래서 이 디스크가 포화인가"에 정확히 답할 수 있는 사람은 적습니다. man 페이지는 그 값이 최신 SSD에서는 포화를 뜻하지 않는다고 명시하고 있는데도 그렇습니다.

이 블로그에는 리눅스 성능 엔지니어링 가이드가 이미 있고, 그 글은 프로파일링 기법과 eBPF, 플레임 그래프, 커널 튜닝을 폭넓게 다룹니다. 이 글은 그와 겹치지 않는 지점을 파고듭니다. 각 도구가 찍는 열 하나하나가 무슨 뜻이며, 어떤 값이 착시를 만드는가가 주제입니다. 도구를 새로 소개하는 글이 아니라, 이미 아는 도구의 출력을 오독하지 않게 만드는 글입니다.

기준 환경은 sysstat 12 이상, 커널 5.x 이상입니다. 열 이름은 sysstat 버전에 따라 바뀌므로(예: 예전의 avgqu-szaqu-sz로 변경) 출력이 다르면 설치된 버전의 man 페이지를 확인하세요.


1. 도구를 고르는 순서 — USE 방법론

무작정 top부터 띄우는 습관을 고치는 가장 쉬운 방법은 USE 체크리스트입니다. 모든 자원에 대해 사용률(Utilization), 포화도(Saturation), 오류(Errors) 세 가지를 묻습니다.

자원사용률포화도오류
CPUmpstat -P ALLvmstatr, pidstat%waitdmesg(MCE)
메모리free -mvmstatsi/so, 페이지 스캔dmesg(OOM)
디스크iostat -xzaqu-sz, awaitdmesg, smartctl
네트워크sar -n DEVnstat의 재전송/드롭ip -s link
파일 핸들/proc/sys/fs/file-nrulimit -n 도달로그의 EMFILE

이 표의 가치는 포화도 열에 있습니다. 사용률만 보면 "CPU 60퍼센트니까 여유 있다"고 판단하지만, 실행 큐가 코어 수의 세 배라면 이미 지연이 발생하고 있습니다. 사용률은 평균이고 포화도는 대기입니다. 사용자가 느끼는 것은 대기 쪽입니다.


2. top과 htop — 착시를 만드는 세 가지 지점

top은 가장 먼저 띄우는 도구지만 오독하기도 가장 쉽습니다.

top -b -n 1 | head -20
top -H -p 1234
top -o %MEM

-b는 배치 모드로 로그에 남기기 좋고, -H는 스레드 단위 표시, -o는 정렬 기준 지정입니다.

착시 1: %CPU는 코어 하나 기준입니다. 8코어 시스템에서 한 프로세스가 800퍼센트를 찍을 수 있습니다. 100퍼센트를 넘는 값을 보고 놀랄 필요가 없습니다. top 실행 중 Shift+I를 누르면 Irix 모드가 꺼지고 전체 코어 기준 값으로 바뀝니다.

착시 2: VIRT는 예약된 가상 주소 공간입니다. 자바나 Go 런타임은 실제로 쓰지 않는 큰 영역을 미리 매핑합니다. 메모리 판단은 RES로, 더 정확하게는 PSS로 해야 합니다.

착시 3: 첫 화면의 %CPU는 부팅 이후 누적값입니다. top을 열자마자 캡처한 값은 의미가 없고, 최소 두 번째 갱신부터 읽어야 합니다.

메모리를 프로세스별로 정확히 보려면 공유 페이지를 안분 계산하는 PSS가 낫습니다.

sudo grep -H '^Pss:' /proc/1234/smaps_rollup

RSS는 그 프로세스가 물리 메모리에 올려 둔 페이지의 총량인데, 여러 프로세스가 공유하는 라이브러리 페이지를 각각 전부 세어 버립니다. 워커 프로세스를 20개 띄우는 웹 서버에서 RSS를 단순 합산하면 실제 메모리 사용량의 몇 배가 나오는 이유가 이것입니다. PSS는 공유 페이지를 참조 프로세스 수로 나눠 배분하므로, PSS의 합은 실제 사용량에 훨씬 가깝습니다. 용량 산정이나 컨테이너 메모리 한도를 정할 때는 반드시 PSS 기준으로 판단하세요.

htop을 쓴다면 표시 옵션에서 스레드 표시와 계층 구조 표시를 켜 두는 편이 좋습니다. 특히 컨테이너 안에서 실행하면 호스트 전체가 아니라 네임스페이스 안의 프로세스만 보이므로, 호스트 관점의 자원 경합을 판단할 때는 호스트에서 다시 확인해야 합니다.


3. vmstat — 시스템 전체를 한 줄로 요약하기

vmstat 1은 성능 도구 중 정보 밀도가 가장 높습니다. man 페이지가 명시하듯 첫 리포트는 마지막 재부팅 이후의 평균값이므로 반드시 둘째 줄부터 읽습니다.

vmstat -w 1 10
vmstat -s
vmstat -d

-w는 넓은 출력, -s는 이벤트 카운터 테이블(반복 없음), -d는 디스크 통계입니다.

읽는 규칙을 정리하면 이렇습니다.

  • r이 코어 수보다 크게, 지속적으로 크면 CPU 포화입니다. 순간적으로 튀는 것은 정상입니다.
  • b가 0이 아니면 I/O 완료를 기다리는 프로세스가 있다는 뜻입니다.
  • si/so가 0이 아니면 스왑이 실제로 일어나는 중입니다. swpd가 크더라도 si/so가 0이면 과거에 밀려 나간 페이지가 그대로 있는 것일 뿐 현재 문제가 아닙니다. 이 구분이 중요합니다.
  • bi/bo는 블록 장치 읽기·쓰기(KiB/s)입니다.
  • cs(컨텍스트 스위치)가 비정상적으로 크면 락 경합이나 과도한 스레드를 의심합니다.
  • in(인터럽트)이 크면 네트워크 트래픽이나 타이머를 봅니다.
  • st는 하이퍼바이저에 빼앗긴 시간입니다. 게스트 안에서는 해결할 수 없는 문제이므로, 이 값이 계속 높으면 인스턴스 타입 변경이나 이전이 답입니다.

ussy의 비율도 유용합니다. syus보다 크다면 애플리케이션 로직이 아니라 시스템 콜, 컨텍스트 스위치, 인터럽트 처리에서 시간을 쓰고 있다는 신호입니다.


4. mpstat과 pidstat — 범위를 좁히는 두 도구

mpstat은 코어별로 나눠 봅니다. 이 도구의 존재 이유는 평균이 감추는 불균형을 드러내는 것입니다.

mpstat -P ALL 1 5

8코어 중 하나만 100퍼센트라면 전체 평균은 12.5퍼센트로 한가해 보이지만 실제로는 단일 스레드 병목입니다. 인터럽트가 한 코어에 몰리는 경우도 여기서 보입니다(%irq, %soft 열).

pidstat은 프로세스 단위 구간 통계입니다. top과 달리 화면을 지우지 않고 계속 찍어 주므로 파일로 남기기에 적합합니다.

pidstat -u 1 5
pidstat -r 1 5
pidstat -d 1 5
pidstat -w 1 5
pidstat -t -p 1234 1 5

각 모드의 열은 다음과 같습니다.

  • -u: %usr, %system, %guest, %wait, %CPU, CPU. 여기서 %wait는 "실행 준비가 되었으나 CPU를 기다린 비율"입니다. 이 값이 높으면 프로세스가 느린 것이 아니라 CPU 경합이 심한 것이므로 대응이 완전히 달라집니다.
  • -r: minflt/s, majflt/s, VSZ, RSS, %MEM. majflt/s(메이저 폴트)가 핵심입니다. 이것은 디스크에서 페이지를 읽어와야 했던 횟수이므로, 0이 아니면 메모리가 부족하거나 파일 캐시가 밀려나는 중입니다. 마이너 폴트는 정상적으로 늘 발생합니다.
  • -d: kB_rd/s, kB_wr/s, kB_ccwr/s, iodelay. kB_ccwr/s는 쓰기가 취소된 양으로, 파일을 썼다가 지운 경우 등에서 나타납니다.
  • -w: 컨텍스트 스위치 통계. 자발적 전환(cswch/s)은 대기 때문이고, 비자발적 전환(nvcswch/s)은 타임 슬라이스 소진 때문입니다. 후자가 많으면 CPU 경합입니다.
  • -t: 스레드 단위로 분해합니다.

5. iostat — await를 보고 %util은 의심하기

iostat -xz 1 5
iostat -xmdz -p ALL 1 3

-x 확장 통계, -z 비활동 장치 생략, -m MiB 단위, -p ALL 파티션까지, -y 첫 리포트 생략입니다.

핵심 열의 정의는 다음과 같습니다.

  • r/s, w/s: 병합 이후 완료된 초당 읽기·쓰기 요청 수.
  • rrqm/s, wrqm/s: 초당 병합된 요청 수. 이 값이 크면 커널이 순차 I/O를 잘 합치고 있다는 뜻입니다.
  • r_await, w_await: 큐 대기 시간을 포함한 평균 서비스 시간(밀리초). 사용자가 체감하는 값에 가장 가깝습니다.
  • aqu-sz: 평균 큐 길이.
  • rareq-sz, wareq-sz: 평균 요청 크기(KiB). 4KiB 근처면 랜덤 I/O, 수백 KiB면 순차 I/O입니다.
  • %util: 장치에 요청이 발행되어 있던 시간 비율.

%util에 대한 man 페이지의 경고는 그대로 인용할 가치가 있습니다. 요청을 직렬로 처리하는 장치에서는 100퍼센트 근처가 포화를 뜻하지만, RAID 배열이나 최신 SSD처럼 병렬 처리하는 장치에서는 이 값이 성능 한계를 반영하지 않습니다. NVMe는 수십 개의 큐를 동시에 굴리므로 %util 100퍼센트에서도 여유가 많습니다.

실무 판단 기준은 이렇게 세우는 편이 안전합니다.

상황해석
await 평소 수준, %util 100퍼센트정상. 장치가 잘 일하는 중
await 급증, aqu-sz 급증진짜 포화
await 급증, aqu-sz 낮음장치 자체가 느려짐(펌웨어, 원격 볼륨, 스로틀링)
r/s+w/s 낮은데 await클라우드 볼륨 IOPS 크레딧 소진 의심

클라우드 환경에서는 마지막 항목이 특히 흔합니다. 버스트 크레딧이 소진되면 IOPS가 갑자기 기준선으로 떨어지면서 요청 수는 적은데 응답이 느려집니다.


6. sar — 지나간 시간을 되감기

성능 문제의 절반은 사람이 로그인했을 때 이미 끝나 있습니다. sar는 그 순간을 되감기 위한 도구입니다.

sar -u -s 03:00:00 -e 04:00:00
sar -r
sar -q
sar -b
sar -n DEV
sar -n EDEV
sar -W
sar -f /var/log/sa/sa14 -u ALL
  • -u CPU, -r 메모리, -q 실행 큐와 부하, -b I/O 전송률, -n DEV 인터페이스 처리량, -n EDEV 인터페이스 오류, -W 스와핑 통계.
  • -s/-e로 시간 구간을, -f로 날짜별 파일을 지정합니다.

수집 파일 경로는 배포판마다 다릅니다. RHEL 계열은 /var/log/sa/, Debian/Ubuntu 계열은 /var/log/sysstat/ 입니다. Debian 계열은 /etc/default/sysstat에서 수집을 켜야 데이터가 쌓이기 시작합니다. 수집 주기와 보존 기간은 /etc/sysstat/sysstat(Debian) 또는 /etc/sysconfig/sysstat(RHEL)에서 조정합니다.

기본 10분 주기는 순간 스파이크를 놓칩니다. 초 단위 이벤트를 잡아야 한다면 수집 주기를 1분으로 줄이거나, 별도의 상시 수집을 붙여야 합니다. 대신 디스크 사용량과 수집 부하가 늘어난다는 점을 감안하세요.


7. 네트워크 — 처리량, 큐, 재전송

처리량은 sar -n DEV, 오류는 sar -n EDEV, 소켓 상태는 ss, 커널 카운터는 nstat입니다.

sar -n DEV 1 5
ip -s link show eth0
nstat -az | grep -i -E 'retrans|listen|prune|collapse'
ss -tin state established | head -20

ss -i는 소켓별 TCP 내부 정보를 보여 줍니다. 여기서 rtt, cwnd, retrans 값을 읽을 수 있습니다. RTT가 크고 cwnd가 작으면 대역폭이 남아도 처리량이 안 나옵니다. 지연-대역폭 곱이 창 크기에 갇힌 전형적인 상황입니다.

nstat의 카운터 중 실무에서 자주 쓰는 것은 다음입니다.

  • TcpExtListenOverflows, TcpExtListenDrops: accept 큐가 넘쳤습니다. 애플리케이션이 accept를 못 따라가거나 백로그가 작습니다.
  • TcpRetransSegs: 재전송. 전체 송신 대비 비율로 봐야 의미가 있습니다.
  • TcpExtTCPRcvCollapsed, TcpExtPruneCalled: 수신 버퍼 압박.

인터페이스 수준 드롭은 ip -s linkRX errors/dropped에서 봅니다. 여기가 늘어나면 커널 위쪽이 아니라 NIC나 링 버퍼를 봐야 합니다.


8. perf — 어느 함수에서 시간을 쓰는가

여기까지 왔는데 "CPU를 쓰는 건 알겠는데 안에서 무엇을 하는지 모르겠다"면 perf 차례입니다.

sudo perf top
sudo perf stat -d -p 1234 -- sleep 10
sudo perf record -F 99 -g -p 1234 -- sleep 30
sudo perf report --stdio | head -40
  • perf top: 실시간으로 가장 많은 CPU를 쓰는 심볼을 보여 줍니다.
  • perf stat: 명령 실행 구간의 하드웨어 카운터를 요약합니다. IPC(instructions per cycle), 캐시 미스, 분기 예측 실패를 봅니다. IPC가 1보다 한참 낮으면 CPU가 메모리를 기다리는 중이라는 강한 신호입니다.
  • perf record -g: 콜 스택을 포함해 샘플을 파일로 남깁니다. -F 99는 초당 99회 샘플링으로, 타이머와 박자가 겹치는 것을 피하려고 100 대신 99를 씁니다.

컨테이너나 클라우드에서 perf가 동작하지 않는다면 커널의 관측 허용 수준 때문일 수 있습니다.

cat /proc/sys/kernel/perf_event_paranoid

값이 2 이하여야 일반적인 프로파일링이 가능하며, 컨테이너에서는 별도의 권한 부여가 필요합니다. 운영 서버에서 이 값을 낮추는 것은 보안 결정이므로 임의로 바꾸지 말고 정책에 따라 처리하세요. 정확한 권한 요건은 사용 중인 배포판과 커널 버전의 문서에서 확인하세요.

심볼이 물음표로만 보인다면 디버그 심볼 패키지가 없는 것입니다. RHEL 계열은 debuginfo 패키지, Debian 계열은 dbgsym 저장소를 추가해야 합니다.


9. 도구 선택 요약표

증상에서 출발해 도구를 고르는 표입니다. 실제로는 이 순서대로 내려가면 대부분 답이 나옵니다.

증상1차 도구확인할 값다음 단계
전체적으로 느림vmstat 1r, wa, si/so, st해당 자원 전용 도구
특정 프로세스만 느림pidstat -u -t%wait, %systemperf record -g
응답 지연이 튐iostat -xz 1r_await, w_awaitpidstat -d
메모리 부족 같음free -m, pidstat -ravailable, majflt/ssmaps_rollup의 PSS
커넥션이 안 맺힘ss -s, nstatListenOverflows백로그와 워커 수 조정
CPU는 노는데 부하만 높음ps D 상태 필터wchan스토리지 계층 조사
과거 시점 재현 불가sar -f해당 시각 구간상시 수집 주기 단축

이 표를 벽에 붙여 두는 것보다 좋은 방법은, 팀에서 실제로 겪은 장애를 한 줄씩 추가해 나가는 것입니다. 조직마다 자주 겪는 병목이 다르기 때문에 그 목록이 훨씬 정확해집니다.

측정에서 흔히 빠뜨리는 마지막 조각은 비교 대상입니다. 지금 응답 시간이 200밀리초라는 사실만으로는 좋은지 나쁜지 알 수 없습니다. 평소 값이 40밀리초였다면 심각한 상황이고, 평소가 220밀리초였다면 아무 일도 아닙니다. 그래서 성능 도구를 도입할 때 가장 먼저 해야 하는 일은 임계치를 정하는 것이 아니라 평상시 값을 며칠간 기록해 기준선을 만드는 것입니다. 기준선이 없으면 모든 숫자가 해석 불가능한 상태로 남습니다.

컨테이너 환경에서는 한 겹이 더 필요합니다. 컨테이너 안에서 본 freenproc은 호스트 값을 그대로 보여 주는 경우가 많고, 실제 제한은 cgroup에 걸려 있습니다. 제한과 실제 사용량은 cgroup v2 파일에서 직접 읽는 것이 확실합니다.

cat /sys/fs/cgroup/memory.max
cat /sys/fs/cgroup/memory.current
cat /sys/fs/cgroup/cpu.max
cat /sys/fs/cgroup/cpu.stat

cpu.stat의 스로틀 관련 카운터가 계속 증가한다면, 호스트 CPU가 한가하더라도 컨테이너는 주기적으로 멈춰 서고 있는 것입니다. 이 경우 호스트에서 관측한 CPU 사용률은 낮게 나오므로, 컨테이너 안의 지연 원인을 호스트 지표만으로는 절대 찾을 수 없습니다.


퀴즈: 실력을 확인해 보세요

퀴즈 1: vmstat에서 swpd가 2GB인데 si와 so는 계속 0입니다. 메모리 문제일까요?

정답: 현재 진행 중인 문제는 아닙니다

설명: swpd는 스왑에 들어가 있는 총량이고, si/so는 초당 스왑 인/아웃 속도입니다. 과거 어느 시점에 밀려 나간 페이지가 그대로 남아 있을 뿐 지금 스와핑이 일어나지 않는다면 성능에 영향이 없습니다. 오히려 잘 쓰지 않는 페이지가 스왑으로 나가고 그 자리를 페이지 캐시가 쓰는 것은 바람직한 상태입니다. 문제는 si/so가 지속적으로 0이 아닐 때 시작됩니다.

퀴즈 2: pidstat -u에서 %wait가 40퍼센트입니다. 이 프로세스에 CPU를 더 주면 해결될까요?

정답: 이 프로세스의 문제가 아니라 시스템 전체의 CPU 경합 문제입니다

설명: %wait는 "실행 준비가 되었는데 CPU를 받지 못하고 기다린 비율"입니다. 즉 이 프로세스는 일할 준비가 되어 있는데 다른 프로세스에 밀린 것입니다. 대응은 이 프로세스를 최적화하는 것이 아니라, 전체 부하를 줄이거나 코어를 늘리거나 스케줄링 우선순위를 조정하는 쪽입니다.

mpstat -P ALL 1 5
pidstat -u 1 5
퀴즈 3: NVMe 디스크의 %util이 100퍼센트로 고정되어 있습니다. 스토리지를 증설해야 할까요?

정답: 아직 판단할 수 없습니다. await와 aqu-sz를 봐야 합니다

설명: iostat man 페이지는 "요청을 병렬로 처리하는 RAID 배열이나 최신 SSD에서는 %util이 성능 한계를 반영하지 않는다"고 명시합니다. NVMe는 다중 큐로 동작하므로 항상 요청이 하나쯤 발행되어 있고, 그 결과 %util이 쉽게 100퍼센트가 됩니다. 판단 기준은 응답 시간입니다.

iostat -xz 1 5

r_awaitw_await가 평소 수준이면 증설할 이유가 없습니다.

퀴즈 4: 8코어 서버의 부하 평균이 4인데 사용자는 느리다고 합니다. 무엇을 확인하나요?

정답: 코어별 분포와 단일 코어 포화 여부를 먼저 확인합니다

설명: 부하 4는 8코어 기준으로 절반이지만, 그 부하가 한 코어에 몰려 있다면 그 코어를 쓰는 요청은 모두 대기합니다.

mpstat -P ALL 1 5
pidstat -t -p <PID> 1 5

mpstat에서 특정 코어만 100퍼센트라면 단일 스레드 병목이며, 코어를 늘려도 해결되지 않습니다. 인터럽트가 한 코어에 몰린 경우라면 %soft 열이 높게 나옵니다.

퀴즈 5: perf stat 결과에서 IPC가 0.3입니다. 무엇을 의미하나요?

정답: CPU가 명령을 실행하지 못하고 메모리를 기다리는 시간이 길다는 뜻입니다

설명: IPC(instructions per cycle)가 낮다는 것은 사이클을 소비하면서도 명령을 적게 처리했다는 의미입니다. 주된 원인은 캐시 미스, 메모리 지연, 분기 예측 실패입니다. 이 경우 알고리즘 자체의 명령 수를 줄이는 것보다 데이터 접근 패턴을 개선하는 쪽(자료 구조 배치, 순차 접근, 캐시 지역성)이 효과적입니다.

sudo perf stat -d -p 1234 -- sleep 10

-d 옵션이 캐시 관련 카운터를 함께 보여 줍니다.

퀴즈 6: 장애가 새벽 3시에 발생했고 아침에 출근했습니다. 어떤 도구부터 쓰나요?

정답: sar로 해당 시간대의 수집 데이터를 되감습니다

설명: 실시간 도구는 이미 지나간 사건에 무력합니다.

sar -q -s 02:50:00 -e 03:30:00
sar -u -s 02:50:00 -e 03:30:00
sar -r -s 02:50:00 -e 03:30:00
sar -n DEV -s 02:50:00 -e 03:30:00
journalctl --since '2026-08-15 02:50' --until '2026-08-15 03:30' -p warning

수집 파일이 없다면 이번 장애로는 아무것도 알 수 없습니다. 그래서 sysstat 수집을 켜 두는 것이 사후 대응이 아니라 사전 준비인 것입니다.


마치며

성능 도구의 출력은 사실을 말해 주지만 결론을 말해 주지는 않습니다. %util 100퍼센트는 사실이고, "디스크가 포화다"는 해석입니다. 그 해석이 장치 종류에 따라 틀릴 수 있다는 것을 아는 것이 도구를 쓰는 능력입니다.

기억할 원칙 세 가지로 정리합니다. 첫째, 사용률보다 포화도를 먼저 본다. 둘째, 평균이 감추는 불균형을 코어별·프로세스별로 쪼개서 본다. 셋째, 지나간 시간을 볼 수 없으면 아무 도구도 소용없으므로 상시 수집을 켜 둔다.


참고 자료


이어서 읽기

현재 단락 (1/166)

성능 도구를 배우는 것과 성능 도구의 출력을 읽는 것은 다른 일입니다. `iostat -x`를 칠 줄 아는 사람은 많지만, `%util`이 100퍼센트라는 결과를 보고 "그래서 이...

작성 글자: 0원문 글자: 9,719작성 단락: 0/166