Infra Architecture/Compute Platforms
Compute Platforms - 10. 서버 성능 분석
"느리다"는 말에 데이터로 답한다 — 서버 성능 분석
2019년, Brendan Gregg(Netflix 수석 성능 엔지니어)가 발표한 "eBPF for Performance Analysis" 데모는 충격적이었다. 그는 단 한 줄의 명령(bpftrace)으로 — 서버의 모든 시스템 콜을 나노초 단위로 추적하고, 어느 함수가 느린지 실시간으로 보여줬다. 기존의 성능 분석 도구(perf·strace·gdb)가 "무겁고 불편하다"고 느끼던 엔지니어들에게 — eBPF는 "커널 안에서 안전하게 돌아가는 가벼운 추적 도구"라는 새 세계를 열었다. 이 글은 서버가 "왜 느린가?"라는 질문에 데이터로 답하는 도구와 방법론을 다룬다.
서버 성능 문제는 인프라 엔지니어가 가장 자주 만나는 도전이다. "서비스가 느려졌다"는 보고가 오면 — CPU인가, 메모리인가, 디스크인가, 네트워크인가? 어디서 병목이 생겼는지를 데이터로 찾아야 한다. 추측이 아니라 측정으로. 이 글은 perf·eBPF·flame graph·sar·vmstat·iostat 같은 도구로 CPU·메모리·디스크·네트워크의 성능을 분석하는 방법과 — Brendan Gregg의 USE method라는 체계적 접근 프레임워크를 다룬다. foundations 02에서 본 "측정 가능해야 개선할 수 있다"는 원칙이, 구체 도구로 번역되는 글이다.
USE method — 체계적 성능 분석의 틀
성능 문제를 분석할 때 — "일단 top를 쳐본다"는 접근은 비체계적이다. Brendan Gregg가 제안한 USE method(Utilization, Saturation, Errors) 는 — 모든 자원(CPU·메모리·디스크·네트워크)에 대해 세 가지 질문을 순서대로 던지는 체계적 방법론이다.
- Utilization(이용률) — 자원이 얼마나 바쁜가? (CPU 90% 사용, 디스크 대역폭 80% 사용 등)
- Saturation(포화도) — 자원에 대기열이 쌓이는가? (CPU 런 큐 길이, 디스크 I/O 대기 시간 등)
- Errors(오류) — 자원에서 에러가 발생하는가? (네트워크 패킷 손실, 디스크 ECC 오류 등)
이 세 가지를 각 자원에 대해 검사하면 — 어느 자원이 병목인지, 병목이라면 이용률 때문인지 포화 때문인지 에러 때문인지가 명확해진다. "CPU 이용률이 높다"는 것만으론 부족하다 — 포화(런 큐가 길어지고 있나?)와 에러(하드웨어 오류가 있나?)도 봐야 전체 그림이 나온다.
| 자원 | Utilization | Saturation | Errors |
|---|---|---|---|
| CPU | %us + %sy (top) |
런 큐 길이 (runq-sz, vmstat의 r) |
하드웨어 오류 (dmesg, MCE) |
| 메모리 | 사용률 (free, sar -r) |
swap/페이지 폴트 (vmstat의 si/so) |
ECC 오류 (edac-utils, dmesg) |
| 디스크 | %util (iostat -x) |
대기 시간 (await, iostat) |
I/O 에러 (dmesg, SMART) |
| 네트워크 | 대역폭 사용률 (sar -n DEV) |
패킷 드롭/재전송 (netstat -s) |
CRC 오류 (ethtool -S) |
이 표를 성능 분석 체크리스트로 쓴다. 성능 문제가 보고되면 — 각 자원의 세 가지 지표를 차례로 확인하고, 이상이 있는 곳을 깊이 파헤친다. "아무 이상 없음"이면 — 애플리케이션 코드(데이터베이스 쿼리·알고리즘 복잡도)를 의심한다.
USE method 실전 — "서비스가 느리다"는 보고가 왔을 때
이해를 돕기 위해, 구체적 시나리오로 USE method를 실전해 보자. "주문 서비스 응답이 평소 200ms였는데 갑자기 2초로 늘어났다"는 보고가 왔을 때.
1단계 — CPU: vmstat 1을 친다. us가 30%, id가 60% — CPU는 바쁘지 않다. r(런 큐)도 2(코어 8개 중) — 포화 없음. CPU는 범인이 아니다.
2단계 — 메모리: free -h를 친다. available이 12GB(총 16GB) — 메모리 충분. vmstat의 si/so가 0 — swap 없음. 메모리도 범인이 아니다.
3단계 — 디스크: iostat -xz 1을 친다. %util이 98%, await이 45ms! — NVMe SSD인데 await이 45ms면 비정상(정상은 1ms 이하). 범인 발견. 디스크가 포화 상태다.
4단계 — 원인 추적: 디스크가 포화된 원인은? iotop으로 "누가 디스크를 쓰고 있나"를 본다. 백업 스크립트(mysqldump)가 풀 덤프를 디스크에 쓰고 있었다. 백업과 서비스가 같은 디스크를 공유하고 있으니 — 백업이 디스크 I/O를 독점해 서비스 응답이 느려진 것이다.
5단계 — 해결: 백업을 다른 시간대로 옮기거나, 다른 디스크로 분리하거나, I/O 우선순위를 조정(ionice)한다. 근본적으로 — 백업과 서비스의 I/O 경로를 분리하는 게 정답.
이 시나리오가 보여주는 것은 — "CPU를 늘리자"라는 추측이 틀렸다는 것이다. 데이터(iostat의 await)가 "디스크"를 가리켰고, 그 디스크의 원인(iotop)이 "백업"을 가리켰다. USE method는 이런 체계적 접근을 보장한다 — 추측이 아니라 측정으로.
CPU 성능 분석
CPU 병목은 가장 흔한 성능 문제 중 하나다. 도구는 단계별로 깊어진다.
top / vmstat — 1만 미터 뷰
# CPU 사용률 전체 보기
top -bn1 | head -5
# 더 정확하게 — vmstat으로 런 큐와 CPU 분석
vmstat 1 5
확인할 것: top의 %Cpu(s) 행에서 us(사용자)·sy(시스템)·id(유휴)·wa(I/O 대기)·st(steal). vmstat의 r 열(실행 큐에 있는 프로세스 수) — 물리 코어 수보다 크면 CPU 포화.
# 예상 출력 (vmstat 1 5)
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 0 1234567 524288 890123 0 0 12 18 234 567 85 10 5 0 0
3 0 0 1234321 524288 890456 0 0 10 15 230 540 80 12 8 0 0
r(런 큐)이 3 ~ 4면 — CPU가 2코어인 서버에서는 포화 상태(런 큐 > 코어 수). us가 85%이면 — 사용자 앱이 CPU를 잡아먹고 있다. wa가 높으면 — I/O 대기(디스크 병목의 징후). st가 높으면 — 클라우드에서 다른 인스턴스의 CPU 스틸(05 글에서 본 오버커밋).
perf — 함수 수준 분석
top은 프로세스 수준의 뷰다 — "nginx가 50% CPU를 쓴다"는 건 보여주지만, nginx의 어느 함수가 50%를 쓰는지는 모른다. 그걸 보여주는 게 perf다.
# CPU를 가장 많이 쓰는 함수 (5초간 샘플링)
sudo perf top
# 특정 프로세스의 함수 프로파일
sudo perf record -p $(pgrep nginx) -g -- sleep 10
sudo perf report
확인할 것: perf top의 함수 목록. 어느 함수가 CPU를 가장 많이 점유하는지. 커널 함수(__schedule·_raw_spin_lock)가 높으면 — 커널 오버헤드(컨텍스트 스위칭·락 경합)가 원인.
Flame graph — 시각적 프로파일링
Flame graph(플레임 그래프) 는 Brendan Gregg가 만든 시각화 기법. CPU 프로파일(perf 데이터)을 — 가로는 함수 호출 수준(스택 깊이), 세로는 호출 빈도(시간)로 그린 "불꽃 모양" 그래프. 어느 함수가 왜 오래 걸리는지 한눈에 본다.
# perf 데이터로 flame graph 만들기
sudo perf record -F 99 -p $(pgrep nginx) -g -- sleep 30
sudo perf script > out.perf
# flamegraph.pl 스크립트 (별도 설치)
git clone https://github.com/brendangregg/FlameGraph
./FlameGraph/flamegraph.pl out.perf > flame.svg
# flame.svg를 브라우저로 열어 확인
확인할 것: 가장 넓은(가로 폭이 큰) 함수 블록이 — CPU를 가장 많이 쓰는 함수. 그 함수를 최적화하면 전체 성능이 가장 크게 개선된다.
메모리 성능 분석
메모리 문제는 두 가지 형태로 나타난다 — 메모리 부족(OOM, swap)과 메모리 지연(페이지 폴트, 캐시 미스).
# 메모리 사용량
free -h
# 페이지 폴트와 swap 활동
vmstat 1 5
# 세부 메모리 통계
sar -r 1 5
# OOM killer 기록
dmesg | grep -i "out of memory\|oom"
확인할 것: free의 available(실제 사용 가능한 메모리). vmstat의 si/so(swap-in/out) — 0이 아니면 메모리 부족으로 swap이 일어나고 있다는 뜻(매우 나쁨). dmesg의 OOM 기록 — 어떤 프로세스가 죽었는지.
디스크 I/O 성능 분석
# 디스크별 I/O 통계 (가장 중요한 도구)
iostat -xz 1
# 디스크 큐 깊이와 대기 시간
iostat -xz 1 5
# 파일시스템 수준
nfsstat -c 2>/dev/null || echo "NFS 미사용"
확인할 것: iostat -xz의 %util(디스크가 얼마나 바쁜가, 100%면 포화), await(I/O 요청당 대기 시간, ms 단위, 10ms 이상이면 느린 디스크), r/s·w/s(초당 읽기/쓰기 IOPS), rkB/s·wkB/s(초당 읽기/쓰기 처리량). NVMe SSD는 await가 1ms 이하, HDD는 5 ~ 20ms가 정상.
# 예상 출력 (iostat -xz 1, NVMe SSD)
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await %util
nvme0n1 0.00 5.00 2.0 8.0 32.0 128.0 32.0 0.01 0.5 0.5
await 0.5ms — 매우 빠른 NVMe SSD. %util 0.5% — 거의 쉬고 있음. 이 디스크는 병목이 아니다. 만약 %util이 95%+이고 await가 20ms+이면 — 디스크 병목.
eBPF — 차세대 성능 분석
eBPF(extended Berkeley Packet Filter) 는 2026년 성능 분석의 최전선이다. Linux 커널 안에서 안전하게 실행되는 작은 프로그램을 작성해 — 시스템 콜·네트워크 패킷·CPU 스케줄링 이벤트를 나노초 단위로 추적한다. 기존의 성능 도구(perf·strace)가 "무겁고 불편하다"고 느끼던 부담을 — eBPF는 "가볍고 안전하고 유연하게" 해결한다.
eBPF를 다루는 도구는 세 가지 층이 있다.
- bcc(BPF Compiler Collection) — Python으로 eBPF 프로그램을 작성하는 프레임워크. 미리 만들어진 도구(
biolatency·cpudist·runqlat)가 풍부. 설치 즉시 사용 가능. - bpftrace — eBPF를 한 줄 명령(one-liner)으로 실행하는 고수준 언어.
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { @[comm] = count(); }'한 줄로 — 누가 파일을 열고 있는지 실시간으로 집계한다. sed·awk의 eBPF 버전이라고 생각하면 된다. - 최상위 도구 — bcc·bpftrace 기반으로 만들어진 사용자 친화적 도구.
execsnoop(실행되는 프로세스 추적),opensnoop(파일 열기 추적),biosnoop(디스크 I/O 추적),tcplife(TCP 연결 수명 추적).
# bcc 도구 설치 (Ubuntu)
sudo apt install bpfcc-tools
# 디스크 I/O 지연 분포 (microbenchmark)
sudo biolatency-bpfcc
# TCP 연결 추적
sudo tcplife-bpfcc
# 새로 실행되는 프로세스 추적 (보안·디버깅)
sudo execsnoop-bpfcc
확인할 것: biolatency의 지연 분포 히스토그램. 어느 지연 구간이 가장 많은지. execsnoop로 — 성능 문제 시점에 어떤 프로세스가 실행됐는지.
eBPF의 혁신은 — 커널 수정 없이 커널 안에서 추적 프로그램을 실행할 수 있다는 것이다. 이전에는 커널 모듈을 작성하고(위험, 재부팅 필요) 또는 커널을 패치해야 했다. eBPF는 "커널 안의 안전한 샌드박스"에서 실행되니 — 시스템을 망가뜨릴 위험 없이 실시간 추적이 가능하다. Cilium(eBPF 기반 네트워킹), Falco(eBPF 기반 보안), Pixie(eBPF 기반 관측성) 같은 도구들이 eBPF 위에 구축돼 있다.
네트워크 성능 분석
네트워크 병목은 "느린데 어딘지 모르겠다"의 흔한 원인이다. 디스크처럼 iostat 한 방에 보이지 않으니 — 여러 도구를 조합해야 한다.
# 인터페이스별 트래픽 통계
sar -n DEV 1 3
# 소켓 상태 (TCP 연결 수, TIME_WAIT 등)
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn
# 네트워크 에러 (패킷 손실·재전송)
netstat -s | grep -E 'retrans|timeout|reset|dropped'
# 인터페이스 하드웨어 에러
ethtool -S eth0 | grep -iE 'error|drop|crc|miss'
확인할 것: sar -n DEV의 rxkB/s·txkB/s로 대역폭 사용량. ss로 TCP 상태 분포 — TIME-WAIT가 수만 개면 포트 고갈 위험. netstat -s의 segments retransmited가 높으면 네트워크 불안정(패킷 손실). ethtool -S의 CRC 에러는 물리 NIC 문제(케이블·포트).
# 예상 출력 (ss로 TCP 상태별 집계)
1250 ESTAB # 정상 연결
340 TIME-WAIT # 종료 후 대기 — 너무 많으면 포트 고갈
12 LISTEN # 서비스 포트 대기
3 CLOSE-WAIT # 앱이 close 안 함 — 코드 버그 신호
TIME-WAIT가 많으면 — 커널 파라미터 net.ipv4.tcp_tw_reuse·tcp_max_tw_buckets 조정으로 완화. CLOSE-WAIT는 — 애플리케이션이 TCP 연결을 제대로 닫지 않는 코드 버그의 징후.
패킷 캡처로 깊이 보기
더 깊이 들어가야 할 때는 tcpdump로 실제 패킷을 캡처한다.
# 특정 포트의 패킷 캡처 (HTTP)
sudo tcpdump -i eth0 -n port 80 -c 100
# TCP 핸드셰이크 과정 보기
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & tcp-syn != 0' -c 20
# 지연 분석 — 패킷 간 시간 간격
sudo tcpdump -i eth0 -n -tttt port 443 -c 50
확인할 것: SYN→SYN-ACK→ACK의 시간 간격(정상은 수 ms, 수백 ms면 네트워크 지연). 재전송(Retransmission) 패킷의 빈도. 패킷 크기가 너무 작으면(64바이트) — 애플리케이션이 데이터를 잘게 쪼개 보내고 있을 수 있음(Nagle 알고리즘 비활성화 필요).
실습 — 성능 분석 기본 명령
1. USE method 1분 체크
# CPU — 런 큐와 사용률
vmstat 1 3
# 메모리 — 사용량과 swap
free -h && cat /proc/meminfo | grep -E 'MemAvail|SwapTotal|SwapFree'
# 디스크 — I/O 대기와 사용률
iostat -xz 1 3 2>/dev/null || echo "iostat 미설치 (apt install sysstat)"
# 네트워크 — 인터페이스 통계
sar -n DEV 1 3 2>/dev/null || ip -s link show
# 에러 — 최근 커널 메시지
dmesg | tail -20
확인할 것: 이 한 묶음으로 USE method의 4가지 자원(CPU·메모리·디스크·네트워크)과 에러를 1분 안에 체크. Brendan Gregg의 "1분 성능 분석 체크리스트"를 실천하는 기본 세트.
2. CPU steal 확인 (클라우드)
# top에서 %st 확인
top -bn1 | grep Cpu
# 더 자세하게
vmstat 1 5 | awk '{print $14, $15, $18}' # us, sy, st
확인할 것: st가 0이면 정상. 5%+가 지속되면 — 같은 물리 서버의 다른 인스턴스가 CPU를 빼앗고 있다는 뜻. 더 큰 인스턴스 타입 또는 Dedicated Instance로 이전을 고려.
3. perf로 함수 프로파일
# 5초간 시스템 전체 CPU 프로파일
sudo perf record -F 99 -ag -- sleep 5
sudo perf report --stdio | head -30
확인할 것: Overhead가 높은 함수. [kernel] 함수가 높으면 커널 오버헤드, 사용자 함수가 높으면 앱 코드 최적화 필요.
4. eBPF로 디스크 지연 추적
# bcc 도구가 있으면
sudo biolatency-bpfcc 10 # 10초간 디스크 I/O 지연 측정
# bpftrace가 있으면
sudo bpftrace -e 'tracepoint:block:block_rq_issue { @start[arg->dev] = nsecs; } tracepoint:block:block_rq_complete /@start[arg->dev]/ { @usecs = hist((nsecs - @start[arg->dev]) / 1000); delete(@start[arg->dev]); }' 2>/dev/null || echo "bpftrace 미설치"
확인할 것: biolatency의 히스토그램. 지연이 1ms 이하에 몰려 있으면 NVMe SSD 정상, 10 ~ 100ms에 몰려 있으면 느린 디스크 또는 I/O 경합.
미검증:
perf는 root 권한 필요.iostat·sar는sysstat패키지 설치 필요. bcc 도구는bpfcc-tools패키지, bpftrace는 별도 설치 필요. 커널 버전 5.4+에서 eBPF가 완전히 작동. WSL2는 일부 eBPF 기능이 제한적일 수 있음.
판단 표 — 성능 분석 도구 선택
| 분석 대상 | 1차 도구 | 심화 도구 | 전형 징후 |
|---|---|---|---|
| CPU 전체 | top, vmstat |
perf top, flame graph |
us 높음, 런 큐 > 코어 수 |
| CPU 함수 수준 | perf record/report |
eBPF profile-bpfcc |
특정 함수 Overhead > 20% |
| 메모리 부족 | free, vmstat |
/proc/meminfo, sar -r |
si/so > 0, OOM 기록 |
| 메모리 지연 | perf stat -e faults |
eBPF 페이지 폴트 추적 | 높은 페이지 폴트율 |
| 디스크 I/O | iostat -xz |
eBPF biolatency |
%util > 80%, await > 10ms |
| 네트워크 | sar -n DEV, ip -s |
tcpdump, eBPF tcplife |
패킷 손실, 재전송 높음 |
| 시스템 콜 | strace (주의: 느림) |
eBPF execsnoop, opensnoop |
예상치 못한 시스템 콜 |
| 전체 시스템 | USE method (1분 체크) | 전체 eBPF 도구 세트 | 복합 병목 |
데이터 없는 최적화는 추측이다
도입의 Brendan Gregg 데모로 돌아가자. 그가 보여준 건 — "추측이 아니라 측정"이었다. "서비스가 느리다"는 보고에 — "CPU를 늘리자", "메모리를 늘리자"라고 추측하는 게 아니라 — USE method로 체계적으로 점검하고, perf로 함수를 찾고, eBPF로 실시간 추적해서 — 어디가, 왜, 얼마나 느린지를 데이터로 답하는 것. 데이터 없는 최적화는 추측이고, 추측은 돈과 시간을 낭비한다.
성능 분석을 이해하면 다른 질문에도 답이 보인다. "왜 클라우드 인스턴스가 갑자기 느려졌나" → vmstat의 %st로 CPU steal 확인. "왜 DB 쿼리가 느린가" → iostat로 디스크 await 확인. "왜 서버가 OOM으로 죽나" → dmesg로 OOM 기록 추적. "왜 네트워크가 느린가" → sar -n DEV로 패킷 손실 확인. 모든 성능 문제에는 데이터가 있고 — 그 데이터를 읽는 도구가 이 글이 다룬 것들이다.
이것으로 compute-platforms 영역이 끝난다. foundations에서 세운 어휘(품질 속성·fault domain·redundancy·TCO·IaC)를 들고 — 하드웨어(01)에서 시작해 부팅(02)·베어메탈 프로비저닝(03)·가상화(04)·VM 라이프사이클(05)·HCI(06)·컨테이너(07)·systemd(08)·이미지 빌드(09)·성능 분석(10)까지 — "한 서버에서 클라우드 네이티브까지"의 전체 스펙트럼을 다뤘다. 다음 영역에서는 패킷이 흐르는 세계로 넘어간다 — network fundamentals. OSI 7계층부터 BGP·TLS까지, 인터넷이 어떻게 굴러가는지를.
참고
- Gregg, B.
2nd ed, Addison-Wesley, 2020 — 성능 분석 정론, USE method 원전. 접근 2026-07-21 - Gregg, B. "eBPF for Performance Analysis", LSFMM 2019 — eBPF 성능 분석 데모. 접근 2026-07-21
- Gregg, B. "Brendan Gregg's Homepage" — flame graph, USE method, eBPF 도구. 접근 2026-07-21. URL: http://www.brendangregg.com/
- IO Visor Project, "BCC Tools Documentation" — bcc 도구 모음. 접근 2026-07-21. URL: https://github.com/iovisor/bcc
- IO Visor Project, "bpftrace Documentation" — bpftrace 언어·도구. 접근 2026-07-21. URL: https://github.com/iovisor/bpftrace
- Linux kernel documentation, "perf", "eBPF", kernel.org — perf·eBPF 공식 문서. 접근 2026-07-21
- Linux man pages, "vmstat(8)", "iostat(1)", "sar(1)", "perf(1)" — 공식 매뉴얼. 접근 2026-07-21
- Nemeth, E. et al.
5th ed, 2017, Ch.4·Ch.29 — 성능 분석 실무. 접근 2026-07-21 - Cilium Project, "eBPF Documentation" — eBPF 기반 네트워킹·보안. 접근 2026-07-21. URL: https://docs.cilium.io/
'Infra Architecture > Compute Platforms' 카테고리의 다른 글
| Compute Platforms - 09. 이미지 빌드와 Immutable Infrastructre (0) | 2026.07.23 |
|---|---|
| Compute Platforms - 08. 서비스 관리와 systemd (0) | 2026.07.23 |
| Compute Platforms - 07. 컨테이너 런타임 (1) | 2026.07.22 |
| Compute Platforms - 06. HCI (Hyper-Converged Infrastructure) (0) | 2026.07.22 |
| Compute Platforms - 05. VM 라이프사이클 (1) | 2026.07.22 |