Discord가 1,700개 이상의 API 엔드포인트와 700개 백그라운드 태스크를 단일 Python 코드베이스로 수백 개 Kubernetes 배포에서 운영하면서 기능별 인프라 비용을 귀속시키는 시스템을 구축했다. 클라우드 제공사가 Kubernetes 배포 단위까지만 비용을 나눠주기 때문에 메시징·스트리밍 등 개별 기능의 실제 비용을 파악하기 어려웠고, CPU 시간 직접 샘플링으로 이 문제를 해결했다.
핵심 포인트- 레이턴시 기반 비용 추정은 하위 서비스 대기 시간에 지배되어 실제 CPU 비용과 상관관계가 낮아 사용할 수 없었다.
- ITIMER_VIRTUAL로 10Hz CPU 전용 샘플링, 인터럽트마다 ContextVar에서 현재 피처를 읽어 콜스택에 레이블을 붙인다.
- 모든 엔드포인트와 백그라운드 태스크에 @route(..., feature=Feature.MESSAGING) 데코레이터로 피처를 분류했다.
- Pyroscope에 5초마다 레이블링된 프로파일 전송 후 시간당 배포/피처/엔드포인트별 CPU 비율을 계산해 데이터 웨어하우스에 적재하고 클라우드 청구 데이터와 조인한다.
- 배포 토폴로지 변경 없이 기존 샘플링 인프라만 계측해 구현한 것이 핵심 실용성 포인트다.
상세 정리- 배경: Discord는 동일 Python 코드베이스가 수백 개 Kubernetes 배포에 나뉘어 실행되며, 하나의 배포에 여러 기능이 동시에 돈다.
- 비용 귀속 문제: 클라우드 제공사 청구는 Kubernetes 배포 단위까지만 내려오고, 기능 단위 분리가 없다.
- 레이턴시 기반 추정의 한계: Python 비동기 코루틴 환경에서 DB·캐시 등 하위 서비스 대기가 CPU 실사용 시간보다 레이턴시를 지배하기 때문에 신뢰할 수 없는 비용 프록시였다.
- 피처 분류 설계: messaging, text-in-voice 등 개별 피처로 계층 구조 구성. 각 피처에 팀 소유권과 중요도 티어를 부여하고, 피처는 chat 같은 피처 그룹으로 롤업된다.
- 샘플러 확장: 기존 샘플링 프로파일러에 ITIMER_VIRTUAL 기반 10Hz 트리거를 추가. 인터럽트 발생 시 콜스택을 세미콜론 구분으로 캡처하고, ContextVar에서 현재 피처·엔드포인트를 읽어 레이블로 첨부한다.
- 데이터 전송: 레이블링된 프로파일을 5초마다 Pyroscope에 전송한다.
- 데이터 파이프라인: 커스텀 스크립트가 Pyroscope에서 시간당 쿼리 후 deployment/feature/endpoint별 CPU 비율을 계산하고 데이터 웨어하우스에 적재한다.
- 비용 계산: 데이터 웨어하우스에서 클라우드 청구 데이터와 CPU 귀속 비율을 조인해 기능별 실제 비용을 산출한다.
- 시각화: 피처 그룹 → 피처 → 엔드포인트로 세분화하는 방사형 차트로 CPU 할당 비율을 표현한다.
- 결과: 팀별 기능 비용 추세 파악, 코드 변경과 비용 변화 상관관계 분석, 개별 엔드포인트 비용 가시성, 부서별 지출 파악이 가능해졌다.
왜 읽나Kubernetes 기반 분산 서비스에서 기능·팀별 클라우드 비용 귀속 체계를 구축하려는 SRE·인프라 엔지니어에게 CPU 프로파일링 기반 비용 분석 아키텍처의 실전 설계 레퍼런스.