애플리케이션 로그, 메트릭, 트레이스만으로도 대부분의 장애는 좁혀집니다. 그런데 실제 운영에서는 꼭 빈 구간이 생깁니다. 요청 p95는 분명히 올랐는데 애플리케이션 함수별 CPU 사용은 평소와 비슷하고, DB 쿼리도 정상인데 응답 시간이 늘어나거나, 특정 노드에서만 재전송과 softirq가 급증하는 식입니다. 이럴 때 팀이 흔히 하는 실수는 도구를 더 붙이는 것입니다. 하지만 도구 수보다 중요한 건 유저 공간과 커널 공간 사이의 블라인드 스팟을 메우는 순서입니다.
이 지점에서 eBPF가 강합니다. eBPF는 커널을 다시 빌드하지 않고도 syscall, 스케줄링, 네트워크, 파일 시스템, 락 대기 같은 신호를 낮은 오버헤드로 샘플링하거나 계측할 수 있게 해 줍니다. 다만 저는 eBPF를 “관측성 만능키”로 보진 않습니다. 관측성 베이스라인과 Continuous Profiling 트렌드 글을 먼저 맞춘 팀이, 그다음 단계에서 원인 추적 시간을 줄이기 위해 선택하는 커널 레벨 확대경에 가깝습니다. 또한 리눅스 I/O 모델 심화나 백엔드 현대적 프런티어 모듈처럼 운영체제 경계를 이해할수록 eBPF의 효용이 커집니다.
이 글에서 얻는 것
- 언제 eBPF를 붙여야 투자 대비 효과가 큰지, 어떤 상황에서는 아직 이른지 판단할 수 있습니다.
- CPU 온-CPU/오프-CPU, 락 경합, TCP 재전송, syscall 지연 같은 신호를 어떤 순서로 봐야 하는지 이해할 수 있습니다.
- 샘플링 오버헤드, 권한 범위, 커널 버전 호환성까지 포함한 실무 도입 기준을 숫자로 가져갈 수 있습니다.
핵심 개념/이슈
1) eBPF는 APM을 대체하는 도구가 아니라 “커널 경계 빈칸”을 채우는 도구다
APM은 어떤 요청이 느린지, 어느 스팬에서 시간이 길어졌는지 보여주는 데 강합니다. 하지만 아래 질문은 종종 애플리케이션 계층 밖으로 나갑니다.
- CPU 사용률은 65%인데 왜 run queue 길이가 계속 늘어나는가
- 자바 스레드 덤프상 특별한 락이 없는데 왜 off-CPU 시간이 급증하는가
- 외부 API 호출 자체는 정상인데 특정 AZ에서만 tail latency가 튀는가
- 파일 I/O가 느려 보이는데 실제 병목이 스토리지인지 페이지 캐시 miss인지 구분되는가
이런 질문은 커널 스케줄러, 네트워크 스택, 블록 I/O, syscall 레벨 관측이 필요합니다. 그래서 eBPF는 관측성 베이스라인이나 APM 기본을 버리는 선택이 아니라, 이미 있는 신호를 더 짧은 시간 안에 설명 가능하게 만드는 추가 레이어로 보는 편이 맞습니다.
2) 실무에서 가장 먼저 보는 eBPF 신호는 “CPU%”가 아니라 온-CPU와 오프-CPU의 분리다
운영자가 CPU 80%만 보고 “CPU 병목”이라고 말하면 종종 틀립니다. 실제로는 두 갈래를 먼저 나눠야 합니다.
- 온-CPU(on-CPU): 실제로 코어에서 실행 중인 함수가 CPU를 많이 쓰는 경우
- 오프-CPU(off-CPU): 스레드가 잠들거나 락, I/O, 스케줄링 대기로 기다리는 경우
예를 들어 p95가 220ms에서 340ms로 늘었는데 CPU 사용률은 55% 수준이라면, 온-CPU 최적화보다 오프-CPU 분석이 먼저입니다. 이때 eBPF로 아래를 보면 바로 방향이 나옵니다.
- off-CPU 상위 스택 비중이 20% 이상이면 락 대기, 디스크 대기, 네트워크 대기를 의심
- run queue 길이가 코어 수 대비 1.5배 이상 지속되면 스케줄링 포화 또는 noisy neighbor 점검
- softirq CPU 비중이 전체 CPU의 10% 이상이면 네트워크 인터럽트 편향 가능성 검토
이 구분이 중요한 이유는, 온-CPU 문제는 코드 핫스팟이나 알고리즘 문제로 이어지고, 오프-CPU 문제는 락, syscall, 네트워크, 스토리지로 이어지기 때문입니다. 같은 “느림”이어도 대응 우선순위가 완전히 달라집니다.
3) eBPF가 특히 강한 세 가지 장면: 락 경합, 네트워크 tail latency, syscall 편향
첫째, 락 경합입니다. 애플리케이션 로그만 보면 요청이 그냥 느릴 뿐이지만, eBPF로 futex 대기나 스케줄링 지연을 보면 특정 락 주소나 스택이 반복해서 튀는 경우가 많습니다. lock wait 샘플 비중이 전체 오프-CPU의 15% 이상이면 애플리케이션 레벨 락 구조 재검토를 바로 올릴 만합니다.
둘째, 네트워크 tail latency입니다. TCP 재전송률이 요청 실패까지 바로 이어지지 않더라도 p99를 크게 흔듭니다. 노드별 retransmit 비율이 평시 대비 2배 이상, 혹은 연결 기준 재전송률이 0.5% 이상이면 NIC, MTU, 특정 경로 품질, LB idle timeout 불일치를 같이 봐야 합니다. TCP 성능 최적화나 로드밸런서/헬스체크와 이어서 보는 이유가 여기 있습니다.
셋째, syscall 편향입니다. 애플리케이션 코드는 같아도 특정 배포 이후 read, write, epoll_wait, fsync 비중이 급증하면 문제는 비즈니스 로직이 아니라 I/O 패턴 변화일 수 있습니다. syscall 평균 지연이 기준선 대비 30% 이상 오르면 최근 릴리스의 버퍼링, flush, 파일 접근 패턴을 먼저 확인하는 편이 안전합니다.
4) 운영에서 중요한 것은 “무엇을 볼 수 있나”보다 “어떤 순서로 좁히나”다
제가 추천하는 초반 디버깅 순서는 아래입니다.
- 애플리케이션 메트릭과 트레이스로 문제 시간대, 엔드포인트, 노드 범위를 좁힌다.
- eBPF 기반 CPU/오프-CPU 샘플로 계산 병목인지 대기 병목인지 먼저 가른다.
- 대기 병목이면 락, 네트워크, 디스크, syscall 중 비중이 가장 큰 축을 확인한다.
- 최근 배포, 커널 변경, 인스턴스 타입 변경, LB 설정 변경과 교차 검증한다.
- 필요하면 결정적 리플레이 + 플라이트 레코더나 부하 테스트로 재현 범위를 고정한다.
이 순서를 거꾸로 하면 eBPF 데이터가 너무 많아집니다. 커널 이벤트는 설명력이 높지만 양도 많기 때문에, 질문이 좁혀진 뒤 들어가야 신호가 됩니다.
5) eBPF는 상시 도입보다 “파일럿 대상”을 선별하는 편이 실패 확률이 낮다
모든 서비스에 무조건 붙이면 운영팀이 먼저 지칩니다. 아래 중 2개 이상이면 파일럿 가치가 높습니다.
- 성능 이슈 RCA 평균 시간이 4시간 이상 걸린다.
- p95 또는 p99 회귀가 월 2회 이상 반복된다.
- 노드별 편차가 커서 동일 배포인데 특정 인스턴스만 느리다.
- APM, 로그, DB 지표로도 원인이 1차 대응 30분 내 안 좁혀진다.
- 고트래픽 서비스의 비용이 최근 3개월 평균 대비 15% 이상 증가했다.
반대로 트래픽이 작고 장애 원인이 대부분 애플리케이션 예외나 SQL 병목으로 귀결되는 팀은 eBPF보다 부하 테스트 전략과 알람 전략을 먼저 다지는 편이 낫습니다.
실무 적용
1) 2주 파일럿은 “상시 수집 2개 + 사건 대응 2개” 조합이 적당하다
처음부터 이벤트를 다 켜지 말고 아래처럼 나누는 편이 좋습니다.
- 상시 수집: CPU 프로파일, off-CPU 샘플
- 사건 대응형: TCP retransmit, block I/O latency, futex/lock wait, syscall histogram
권장 기준은 다음 정도가 현실적입니다.
- 상시 오버헤드 목표: 노드 CPU 1~2% 이내
- 샘플 보존 기간: 핫 데이터 3~7일, 집계 데이터 14~30일
- 파일럿 대상: 전체 서비스가 아니라 상위 트래픽 또는 장애 영향 서비스 2~3개
- 경보 수: 초기에는 3개 이하로 제한
이렇게 해야 “데이터는 쌓였는데 누구도 안 보는 상태”를 피할 수 있습니다.
2) 운영 의사결정 기준(숫자·조건·우선순위)
우선순위는 보통 사용자 영향 > 반복성 > 재현 가능성 > 수집 비용 순으로 잡으면 됩니다.
실무 기준 예시는 아래처럼 둘 수 있습니다.
- 배포 후 특정 함수의 on-CPU 비중이 기준선 대비 +30% 이상이면 코드 회귀 검토
- off-CPU 비중이 20% 초과이고 상위 원인이 락이면 동시성 구조 점검 티켓 우선 생성
- retransmit rate가 평시의 2배 이상 또는 0.5% 초과면 네트워크 경로/LB 설정 우선 조사
- block I/O p95가 기준선 대비 +40% 이상이면 노드 디스크 상태와 flush 패턴 확인
- 동일 문제 RCA가 2회 이상 반복되면 ad-hoc 스크립트 대신 표준 대시보드와 런북으로 승격
핵심은 eBPF를 “깊은 기술”로 다루지 말고, 운영 의사결정을 빠르게 내리기 위한 임계치 체계로 만드는 것입니다.
3) 팀 역할 분리도 중요하다
- 플랫폼/SRE: 수집기 배포, 권한 통제, 커널 호환성, 기본 대시보드 제공
- 서비스 팀: 기준선 정의, 최근 배포 변경과의 상관분석, 개선 우선순위 결정
- 보안/컴플라이언스: 캡처 범위 점검, 민감 경로 마스킹, root 권한 사용 조건 검토
서비스 팀이 bpftrace 원라이너를 매번 새로 짜는 구조는 오래 못 갑니다. 플랫폼이 기본 경로를 주고, 서비스 팀은 자신들의 기준선을 해석하는 쪽이 지속 가능합니다.
4) 추천 운영 루틴
- 알람이 p95 상승 또는 노드 편차를 감지한다.
- 트레이스로 엔드포인트와 시간대를 좁힌다.
- eBPF 대시보드에서 on-CPU/off-CPU, retransmit, syscall 변화를 본다.
- 최근 배포 diff 또는 환경 변경과 맞물리는지 확인한다.
- 임계치 초과면 롤백, 패치, 노드 교체 중 하나를 30분 내 결정한다.
운영에서 중요한 건 완벽한 원인 설명이 아니라, 잘못된 방향으로 2시간 헤매지 않는 것입니다. eBPF는 그 지름길을 만들어 줍니다.
트레이드오프/주의점
첫째, 권한과 보안입니다. eBPF는 커널 레벨 계측이므로 배포 권한, 캡처 범위, 데이터 보존을 엄격히 분리해야 합니다. 운영 편의 때문에 모든 팀에 광범위 권한을 열어두면 오히려 위험합니다.
둘째, 커널 버전과 배포 환경 호환성입니다. 최신 커널에서는 잘 되던 스크립트가 구형 노드에서는 제한될 수 있습니다. 혼합 환경이면 “지원 커널 매트릭스”를 먼저 문서화해야 합니다.
셋째, 데이터 해석 오류입니다. 특정 syscall 증가가 바로 성능 원인이라는 뜻은 아닙니다. 상관관계가 원인이 아닌 경우가 많아서, 애플리케이션 배포와 인프라 변경 이벤트를 같이 봐야 합니다.
넷째, 상시 계측의 비용입니다. 오버헤드가 낮다고 무시할 수는 없습니다. 서비스 등급에 따라 샘플링 빈도와 보존 기간을 달리 두는 편이 안전합니다.
다섯째, 도구 과시로 흐르기 쉽다는 점입니다. flame graph가 멋져 보여도, 운영자가 10분 안에 판단할 수 없으면 실무 가치는 낮습니다. 대시보드는 예쁘기보다 결정 가능해야 합니다.
체크리스트 또는 연습
체크리스트
- APM, 로그, 트레이스로 문제 시간대와 서비스 범위를 먼저 좁힌다.
- on-CPU와 off-CPU를 분리해서 본다.
- 파일럿 대상은 고트래픽 또는 반복 장애 서비스 2~3개로 제한한다.
- retransmit, lock wait, block I/O, syscall 지연 중 초기 경보는 3개 이하로 정한다.
- 커널 호환성, 권한 범위, 데이터 보존 정책을 문서화한다.
- 임계치 초과 시 롤백/패치/노드교체 중 무엇을 택할지 런북에 연결한다.
연습 과제
- 최근 2주 안에 p95가 가장 크게 튄 서비스 1개를 골라, on-CPU와 off-CPU 중 어느 쪽이 먼저 의심되는지 가설을 적어 보세요.
- retransmit rate, run queue 길이, block I/O p95의 기준선을 각 1개 서비스에서 측정하고, “평시 대비 몇 % 변화부터 조사할지” 임계치를 정해 보세요.
- 운영 문서에
알람 → 트레이스 → eBPF → 최근 배포 비교 → 결정5단계 루틴을 추가하고 모의 장애 1회를 돌려 보세요.
💬 댓글