TrotVote
[IT 심층 분석]

eBPF로 프로덕션 서버 재시작 없이 실시간 성능 병목을 밝혀낸 현장 트레이싱 경험담

김민준 · IT 시스템 엔지니어|
오랫동안 납득할 수 없는 레이턴시 스파이크에 시달리던 프로덕션 API 서버가 있었습니다. 문제는 단순히 서비스를 재시작하거나 디버그 바이너리를 올리기만 해도 증상이 사라져서 원인을 특정할 수가 없었다는 것입니다. 프로파일링 도구를 붙이기 위해 서비스를 잠시라도 중단한다는 것은 수십만 명의 사용자가 영향을 받는 환경에서는 허락되지 않는 일이었습니다. 이 딜레마를 해결할 수 있는 강력한 무기가 바로 eBPF(Extended Berkeley Packet Filter)였습니다. eBPF는 원래 패킷 필터링을 위한 커널 기술이었으나 현재는 리눅스 커널의 거의 모든 실행 흐름에 훅을 걸 수 있는 범용 안전 샌드박스 런타임으로 진화했습니다. eBPF 프로그램은 커널 소스를 수정하거나 커널 모듈을 로드하지 않고도 커널 내부 함수의 진입과 반환 시점에 부착해서 실행될 수 있습니다. 가장 중요한 특성은 이 모든 것이 서비스를 중단하거나 재시작하지 않고 완전 무중단 실시간으로 이루어진다는 점입니다. BCC와 bpftrace 도구 모음을 이용해 문제의 서버에 프로브를 심었습니다. 구체적으로는 시스템 콜 수준에서 어떤 함수 호출이 오랜 시간을 소비하는지를 추적하는 funclatency 트레이서를 타깃 프로세스에 붙여 10분간 데이터를 수집했습니다. 결과를 히스토그램으로 분석하자 충격적인 패턴이 드러났습니다. 평상시에는 수 마이크로초 만에 끝나던 특정 파일 잠금 해제 함수가 간헐적으로 무려 수백 밀리초를 소비하는 이상 분포를 보이고 있었습니다. 해당 코드 경로를 역추적하자 여러 스레드가 동시에 설정 파일을 핫리로드하려는 상황에서 Mutex 충돌이 일어나고 한 스레드가 수분 간 대기에 빠지는 경합 현상임이 밝혀졌습니다. 불필요하게 전역 잠금을 사용하던 설정 로더를 읽기 전용 AtomicReference로 교체하는 것만으로도 레이턴시 스파이크는 완전히 사라졌습니다. 서비스를 단 1초도 멈추지 않고 이 복잡한 버그를 잡아낸 eBPF는 지금도 제 가장 강력한 서버 트러블슈팅 무기 중 하나입니다.