성능 분석 도구(perf/strace/eBPF)
관측성의 계층
시스템이 느리거나 이상 동작할 때 원인을 찾으려면 올바른 계층에서 관측해야 한다. 증상이 "애플리케이션 레이턴시 급증"이라면 원인은 CPU 과부하, 컨텍스트 스위치 폭증, 비효율적인 시스템 콜, I/O 대기, 메모리 할당 지연 등 어디서든 나올 수 있다. Linux는 이를 탐색하는 공개된 도구 계층을 제공한다.
ptrace 기반 ⚠ 10~100x 오버헤드
개발/디버깅 전용
하드웨어 카운터 샘플링 기반
오버헤드 낮음
(bpftrace / BCC) 동적 커널 계측
거의 제로 오버헤드 프로덕션 안전
가장 강력
strace: 시스템 콜의 현미경
strace는 ptrace 시스템 콜을 사용해 대상 프로세스의 모든 시스템 콜 진입·반환을 인터셉트한다. 프로세스가 시스템 콜을 하면 커널은 실행을 멈추고 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 counter | cpu-cycles, cache-misses, branch-mispredictions | CPU 마이크로아키텍처 병목 |
| Software counter | context-switches, page-faults, cpu-migrations | 커널 소프트웨어 이벤트 |
| Tracepoints | sched: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하드웨어 카운터로 캐시 미스 분석
# 캐시 미스 상세 (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)에서 범용 실행 환경으로 확장되었다.
작성 bpftrace 스크립트 또는
libbpf C 코드
→ eBPF 바이트코드 제한된 ISA
(11개 레지스터, 512B 스택)
OOB 메모리 없음
안전한 헬퍼만 호출
→ 네이티브 코드 훅 포인트에서
이벤트 발생 시 실행
eBPF 프로그램 유형과 훅
| 프로그램 유형 | 훅 포인트 | 주요 용도 |
|---|---|---|
kprobe | 임의의 커널 함수 진입/반환 | 커널 내부 동작 추적 |
tracepoint | 커널 정적 트레이스포인트 | 안정적·버전 독립적 추적 |
uprobe | 유저스페이스 함수 진입/반환 | Go/Java/Ruby 앱 추적 |
XDP | NIC 드라이버 직후 | 고성능 패킷 처리, DDoS 방어 |
TC (Traffic Control) | 네트워크 큐 | 패킷 분류·수정 |
socket filter | 소켓 수신/송신 | 패킷 필터링 (tcpdump 원리) |
LSM | Linux 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 대기?
메모리 부족?
perf record + FlameGraph → 핫 함수 식별
캐시 미스 확인
biolatency / runqlat → 레이턴시 분포
이상치(outlier) 확인
strace / opensnoop → 어떤 syscall?
어떤 파일/소켓?
bpftrace 커스텀 스크립트 → 함수별 레이턴시
커널 내부 상태
주의사항과 제한
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_eventsReferences
- Linux eBPF Tracing Tools — Brendan Gregg
- Linux Performance — Brendan Gregg
- Linux perf Examples — Brendan Gregg
- What is eBPF? An Introduction and Deep Dive — ebpf.io
- Mastering strace, perf, and eBPF: The Linux Debugging Cheat Sheet — techbytes.app
- eBPF for Advanced Linux Performance Monitoring and Security — TuxCare
- Analyzing system performance with eBPF — Red Hat RHEL 10 Docs
- Linux eBPF Observability with bpftrace and bcc Tools — commandinline.com
- eBPF on Linux: What It Is and How to Get Started (2026 Guide) — fosslinux.com