LLM WikiAccess-protected knowledge portal
← 스터디 홈
6편 · 약 26분

성능 분석 도구(perf/strace/eBPF)

관측성의 계층

시스템이 느리거나 이상 동작할 때 원인을 찾으려면 올바른 계층에서 관측해야 한다. 증상이 "애플리케이션 레이턴시 급증"이라면 원인은 CPU 과부하, 컨텍스트 스위치 폭증, 비효율적인 시스템 콜, I/O 대기, 메모리 할당 지연 등 어디서든 나올 수 있다. Linux는 이를 탐색하는 공개된 도구 계층을 제공한다.

strace 시스템 콜 추적
ptrace 기반
⚠ 10~100x 오버헤드
개발/디버깅 전용
perf CPU 프로파일링
하드웨어 카운터
샘플링 기반
오버헤드 낮음
eBPF
(bpftrace / BCC)
동적 커널 계측
거의 제로 오버헤드
프로덕션 안전
가장 강력
보완 도구 vmstat / iostat / mpstat: 시스템 전역 자원 현황 (1초 단위) top / htop / pidstat: 프로세스별 CPU·메모리 현황 lsof / ss / netstat: 파일 디스크립터, 소켓 상태
Linux 관측성 도구 계층

strace: 시스템 콜의 현미경

straceptrace 시스템 콜을 사용해 대상 프로세스의 모든 시스템 콜 진입·반환을 인터셉트한다. 프로세스가 시스템 콜을 하면 커널은 실행을 멈추고 strace 프로세스로 제어를 넘긴다. 이 구조 탓에 시스템 콜당 컨텍스트 스위치가 두 번(진입·반환) 발생해 10~100배의 속도 저하가 생긴다. 따라서 프로덕션 환경에서는 단명(短命) 진단 외에는 사용하지 않는다.

# 기본: 모든 시스템 콜 출력
strace ls /tmp

# 특정 시스템 콜만 필터링
strace -e trace=openat,read,write curl https://example.com

# 타이밍 포함 (각 syscall 실행 시간)
strace -T -e trace=network curl https://example.com
# connect(3, ...) = 0 <0.123456>

# 실행 중인 프로세스에 붙이기
strace -p 12345

# 시스템 콜 요약 통계
strace -c -p 12345 & sleep 5; kill %1
# % time   seconds   usecs/call  calls  syscall
# 68.00     0.034      17       2000    futex
# 22.00     0.011       5       2200    read

# 파일 관련 시스템 콜만 (어떤 파일을 여는지 추적)
strace -e trace=file nginx -t 2>&1 | grep "No such file"

언제 strace를 쓰는가

  • 설정 파일을 어디서 읽는지 모를 때 (-e trace=openat)
  • 프로세스가 실행 직후 죽는 이유를 찾을 때
  • 시스템 콜이 어디서 막히는지(블로킹) 확인할 때
  • 외부 라이브러리가 어떤 커널 자원을 요청하는지 이해할 때

perf: CPU 병목의 X레이

perf는 Linux의 공식 성능 분석 프레임워크로, 커널 perf_events 서브시스템 위에 구축되어 있다.

perf의 이벤트 유형

유형예시용도
Hardware countercpu-cycles, cache-misses, branch-mispredictionsCPU 마이크로아키텍처 병목
Software countercontext-switches, page-faults, cpu-migrations커널 소프트웨어 이벤트
Tracepointssched:sched_switch, syscalls:sys_enter_read정적 커널 훅
kprobes / uprobes임의의 커널·유저 함수동적 함수 추적

CPU 프로파일링과 FlameGraph

# 전체 시스템 CPU 사용 샘플 (99 Hz, 30초)
perf record -F 99 -a -g -- sleep 30

# 특정 프로세스만
perf record -F 99 -p 12345 -g -- sleep 30

# 수집된 데이터 분석
perf report --stdio

# FlameGraph 생성 (Brendan Gregg의 도구 필요)
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg
main() process_request() json_parse() malloc()
db_query() network_send()
FlameGraph 해석 규칙 X축: 스택 샘플 비율 (넓을수록 CPU 점유 많음) Y축: 스택 깊이 (아래→위 = 호출자→피호출자) 가장 넓은 탑 레벨 함수 = 실제 CPU 소비의 주범 평탄한 상단 = "On-CPU" 핫스팟, 긴 수직 탑 = 깊은 콜체인
perf FlameGraph 읽는 법

하드웨어 카운터로 캐시 미스 분석

# 캐시 미스 상세 (L1/LLC)
perf stat -e cache-misses,cache-references,cycles,instructions ./myapp

# Performance counter stats for './myapp':
#   2,345,678  cache-misses   #   12.34% of all cache refs
#  19,012,345  cache-references
# 500,000,000  cycles
# 450,000,000  instructions   #   0.90  insn per cycle

# LLC(Last Level Cache) 미스 = 메모리 접근 → 데이터 구조 레이아웃 재검토

eBPF: 커널 안으로 들어가는 안전한 코드

eBPF(extended Berkeley Packet Filter)사용자가 작성한 코드를 커널 컨텍스트에서 안전하게 실행하는 메커니즘이다. 1992년의 BPF(tcpdump 패킷 필터)에서 시작해 Linux 3.18(2014)에서 범용 실행 환경으로 확장되었다.

① 작성 C로 eBPF 프로그램
작성
bpftrace 스크립트 또는
libbpf C 코드
② 컴파일 LLVM/Clang
→ eBPF 바이트코드
제한된 ISA
(11개 레지스터, 512B 스택)
③ 검증 Kernel Verifier 무한루프 없음
OOB 메모리 없음
안전한 헬퍼만 호출
④ 실행 JIT 컴파일
→ 네이티브 코드
훅 포인트에서
이벤트 발생 시 실행
BPF Maps: 커널 ↔ 유저스페이스 데이터 교환 Hash, Array, RingBuffer, PerCPU — bpf() syscall로 조회·수정 eBPF 프로그램이 이벤트당 맵 업데이트 → 유저스페이스 툴이 집계 결과 읽기
eBPF 아키텍처

eBPF 프로그램 유형과 훅

프로그램 유형훅 포인트주요 용도
kprobe임의의 커널 함수 진입/반환커널 내부 동작 추적
tracepoint커널 정적 트레이스포인트안정적·버전 독립적 추적
uprobe유저스페이스 함수 진입/반환Go/Java/Ruby 앱 추적
XDPNIC 드라이버 직후고성능 패킷 처리, DDoS 방어
TC (Traffic Control)네트워크 큐패킷 분류·수정
socket filter소켓 수신/송신패킷 필터링 (tcpdump 원리)
LSMLinux Security Module 훅보안 정책 집행

bpftrace: 한 줄로 커널 계측

bpftrace는 awk와 유사한 고수준 언어로 eBPF 프로그램을 작성한다. LLVM이 이를 eBPF 바이트코드로 컴파일한다.

# 슈퍼 원라이너: 프로세스별 syscall 카운트 (5초)
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' & sleep 5; pkill bpftrace

# open() 호출 파일 추적
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'

# 함수 레이턴시 히스토그램 (vfs_read 지연 분포)
bpftrace -e '
kprobe:vfs_read { @start[tid] = nsecs; }
kretprobe:vfs_read /@start[tid]/  {
    @latency_us = hist((nsecs - @start[tid]) / 1000);
    delete(@start[tid]);
}'

# 결과 예시:
# @latency_us:
# [0]       3000 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
# [1]       1200 |@@@@@@@@@@@@@               |
# [10, 20)   180 |@@                           |
# [1000, ...)  4 |                             |

# 네트워크 연결별 송수신 바이트 집계
bpftrace -e '
kprobe:tcp_sendmsg { @sent_bytes[comm] = sum(arg2); }
kprobe:tcp_recvmsg { @recv_bytes[comm] = sum(arg2); }
interval:s:5 { print(@sent_bytes); clear(@sent_bytes); }'

BCC: 복잡한 eBPF 도구 모음

BCC(BPF Compiler Collection)는 Python/Lua 프론트엔드로 C eBPF 코드를 작성·로드하는 프레임워크다. /usr/share/bcc/tools/에 검증된 도구들이 있다.

# opensnoop: 어떤 프로세스가 어떤 파일을 여는가
opensnoop -p 12345

# execsnoop: 프로세스 생성 추적 (fork + exec)
execsnoop

# biolatency: 블록 I/O 레이턴시 분포
biolatency -D

# tcpconnect: TCP 아웃바운드 연결 추적
tcpconnect

# runqlat: Run Queue 대기 시간 (CPU 포화 진단)
runqlat 5 1
# Tracing run queue latency... Hit Ctrl-C to end.
# usecs               : count     distribution
# 0 -> 1             : 8000      |@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
# 2 -> 3             : 1200      |@@@@                         |
# 16 -> 31           :  200      |                             |
# > 1000             :    5      | ← CPU 과부하 신호

# funclatency: 임의 함수 레이턴시
funclatency 'ext4:ext4_sync_file'

통합 진단 워크플로

실제 장애 상황에서의 순서.

① 시스템 전반 확인
vmstat / top / iostat
CPU 포화? I/O 대기?
메모리 부족?
② CPU 병목이면
perf record + FlameGraph
핫 함수 식별
캐시 미스 확인
③ I/O 병목이면
biolatency / runqlat
레이턴시 분포
이상치(outlier) 확인
④ 미지의 동작이면
strace / opensnoop
어떤 syscall?
어떤 파일/소켓?
⑤ 심층 분석
bpftrace 커스텀 스크립트
함수별 레이턴시
커널 내부 상태
도구 선택 기준 요약 strace: 어떤 syscall이 실패하는가 — 개발·테스트 환경 한정 perf: CPU의 어느 코드가 느린가 — 오버헤드 낮아 짧은 프로덕션 세션 가능 eBPF: 얼마나, 언제, 어디서 — 프로덕션 상시 계측 가능, 가장 강력
성능 진단 워크플로

주의사항과 제한

strace 오버헤드: 프로덕션에서 레이턴시 문제를 재현하는 목적으로 쓰면 오히려 문제를 가린다. 짧게 붙이고 빠르게 분리하라.

perf 심볼: JIT 컴파일 런타임(JVM, V8)은 컴파일된 함수명이 없어 FlameGraph에 [unknown]이 가득하다. JVM은 -XX:+PreserveFramePointer, Java Flight Recorder, async-profiler 같은 전용 도구를 사용한다.

eBPF 커널 버전: XDP는 4.8+, BTF(BPF Type Format, CO-RE 이식성 핵심)는 5.2+, Ring Buffer는 5.8+이다. RHEL 7(kernel 3.10)에서는 eBPF 기능이 심하게 제한된다.

CAP_BPF / CAP_SYS_ADMIN: 커널 5.8부터 CAP_BPF 캐퍼빌리티로 root 없이도 일부 eBPF 프로그램 실행이 가능해졌다. 컨테이너 환경에서는 seccomp 프로파일이 bpf() syscall을 차단할 수 있으니 확인이 필요하다.

# eBPF 프로그램 현황 확인
bpftool prog list

# BPF Map 목록
bpftool map list

# 특정 kprobe 이벤트 활성화 여부
cat /sys/kernel/debug/tracing/kprobe_events

References