parca-agent 내부 구조 분석
eBPF 기반 수집 메커니즘
Parca를 “설치해 보는 도구”가 아니라
신뢰할 수 있는 성능 분석 도구로 받아들이기 위해서는
반드시 한 번은 짚고 넘어가야 할 질문이 있다.
parca-agent는 정확히 무엇을,
어떤 방식으로,
얼마나 자주 수집하는가?
이번 편에서는 이 질문에 답한다.
parca-agent의 역할 다시 정리
먼저 역할을 다시 명확히 하자.
parca-agent는:
- CPU 사용량을 계산하지 않는다
- 병목을 판단하지 않는다
- Flamegraph를 만들지 않는다
parca-agent가 하는 일은 단 하나다.
“CPU가 인터럽트된 순간의
실행 스택을 샘플링한다.”
모든 분석은
이 단순한 행위의 반복 위에 쌓인다.
전체 수집 흐름 한눈에 보기



parca-agent의 내부 동작을 흐름으로 단순화하면 다음과 같다.
| CPU 주기적 인터럽트 ↓ perf_event 발생 ↓ eBPF 프로그램 실행 ↓ 유저 스택 + 커널 스택 수집 ↓ stack trace ID 생성 ↓ user space(agent)로 전달 ↓ protobuf 직렬화 ↓ Parca Server 전송 |
핵심은
**“이 모든 과정이 커널 안전성 검증 하에서,
짧은 시간 안에 끝난다”**는 점이다.
perf_event 기반 샘플링
왜 타이머가 아니라 perf_event 인가?
parca-agent는 CPU profiling을 위해
Linux의 perf_event 서브시스템을 사용한다.
이 방식의 장점은 다음과 같다.
- 하드웨어 성능 이벤트와 자연스럽게 연계
- 커널 스케줄링과 정합성 유지
- 이미 검증된 고성능 인터페이스
개념적으로는 다음과 같다.
“CPU가 일정 주기마다
‘지금 뭐 하고 있니?’ 하고 묻는다”
perf_event 설정 개념 예시 (단순화)
struct perf_event_attr attr = {
.type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_CPU_CLOCK,
.sample_freq = 19,
.freq = 1,
};
- sample_freq = 19
→ 초당 약 19회 샘플링 - 이 값이 parca-agent의 기본 철학을 보여준다
(정밀함보다 지속성)
eBPF 프로그램은 언제 실행되는가?
perf_event가 발생하면
연결된 eBPF 프로그램이 실행된다.
이 eBPF 프로그램은 매우 짧고 단순해야 한다.
이유는 명확하다.
- 커널 컨텍스트에서 실행
- verifier 제한
- 실행 시간 상한 존재
스택 트레이스 수집의 핵심
1. 커널 스택 수집
커널 스택은 비교적 단순하다.
bpf_get_stackid(ctx, &stack_map, BPF_F_KERNEL_STACK);
- 현재 CPU가 커널 모드라면
- syscall, scheduler, lock 경로 등이 잡힌다
2. 유저 스택 수집
유저 스택은 훨씬 까다롭다.
bpf_get_stackid(ctx, &stack_map, BPF_F_USER_STACK);
문제는 여기서 발생한다.
- 프레임 포인터가 없을 수 있음
- JIT 언어 (Go, Java)는 스택 구조가 다름
- 심볼 해석은 커널에서 불가능
parca-agent는 이 문제를 역할 분리로 해결한다.
eBPF는 “주소만” 수집
심볼 해석은 user space에서
eBPF Map의 역할


eBPF 프로그램은 다음과 같은 map을 사용한다.
- stack trace map
- count / histogram map
- temporary aggregation map
개념적 구조는 다음과 같다.
struct {
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
__uint(max_entries, 16384);
} stack_map SEC(".maps");
이 map은:
- 동일한 call stack을 하나의 ID로 관리
- 중복 저장 방지
- 메모리 사용량 제한
user space(parca-agent)에서 하는 일
eBPF는 여기까지다.
이제 baton은 user space로 넘어간다.
parca-agent(user space)는 다음을 수행한다.
- stack ID 수신
- 주소 목록 조회
- 심볼 정보 매핑
- label(node, pid, container 등) 부착
- protobuf 변환
- 서버 전송
중요한 점은:
agent는 “분석”을 하지 않는다
그저 구조를 보존한 채 전달할 뿐이다.
샘플링 기반이라는 것의 의미
여기서 흔히 나오는 질문이 있다.
“샘플링이면 정확하지 않은 것 아닌가?”
답은 다음과 같다.
- 단일 샘플 → 의미 없음
- 수천, 수만 샘플 → 통계적으로 매우 강력
Parca는:
- 순간의 정확성 ❌
- 시간 축의 누적 정확성 ⭕
을 선택했다.
오버헤드는 왜 낮은가?
parca-agent의 오버헤드가 낮은 이유는 구조적이다.
- 항상 같은 짧은 eBPF 코드
- 조건 분기 거의 없음
- 락 없음
- 메모리 접근 제한적
- 낮은 샘플링 빈도
일반적인 운영 환경에서:
- CPU 오버헤드: 수 % 미만
- latency 영향: 측정 불가 수준
- 장애 유발 가능성: 극히 낮음
이 때문에 상시 활성화가 가능하다.
왜 tracing이 아니라 profiling인가?
중요한 철학적 차이도 짚고 가자.
| 접근 | 이벤트 기반 | 샘플링 기반 |
| 비용 | 상대적으로 높음 | 낮음 |
| 정밀도 | 매우 높음 | 통계적 |
| 지속성 | 제한적 | 상시 가능 |
Parca는 의도적으로 profiling을 선택했다.
“항상 켜 두어야 의미가 있기 때문”
이 구조가 주는 실무적 의미
이제 Parca가 왜 이런 구조를 가지는지 보인다.
- 커널 안정성 유지
- 운영 환경 적용 가능
- 장애 시 blame 없음
- 장시간 비교 분석 가능
즉, parca-agent는
“운영 서버에 깔아도
죄책감이 들지 않는 eBPF 프로그램”
이라는 목표에 충실하다.
다음 편 예고
다음 편에서는
이렇게 수집된 데이터가 어떻게 Flamegraph로 변하는지,
그리고 사람이 어떻게 읽어야 하는지를 다룬다.
- Flamegraph의 진짜 의미
- Inclusive / Exclusive 비용
- 흔히 저지르는 해석 실수
- “보이는 것”과 “중요한 것”의 차이
다음 편
4편. Flamegraph 제대로 읽기 – Parca UI 해석 가이드
'Parca' 카테고리의 다른 글
| 6편. 실전 사례 ① – CPU 사용률은 정상인데, 성능은 느린 이유 (0) | 2025.12.18 |
|---|---|
| 5편. Flamegraph 제대로 읽기– Parca UI 해석 가이드 (0) | 2025.12.18 |
| 4편. Parca와 기존 APM / 모니터링 에이전트 비교– 무엇이 같고, 무엇이 다른가 (0) | 2025.12.18 |
| 2편. Parca 아키텍처 한눈에 보기 – Server, Agent, Storage 구조 (0) | 2025.12.18 |
| 1편. Parca란 무엇인가 (0) | 2025.12.18 |