OpenTelemetry가 2026년 3월 Continuous Profiling을 다루는 프로파일 시그널을 공개 알파로 전환했습니다. 시그널은 OpenTelemetry가 다루는 데이터 종류를 뜻합니다. 프로파일은 메트릭과 로그, 트레이스에 이어 네 번째 시그널입니다. 다만 같은 발표문에 아직 프로덕션에 그대로 쓸 단계는 아니라는 단서가 붙어 있습니다.
지금 검토할 단계인지 판단하려면 프로파일이 무엇을 남기는지부터 봐야 합니다. Continuous Profiling은 실행 중인 애플리케이션의 스택을 주기적으로 수집해 어느 코드가 CPU나 메모리 같은 자원을 사용하는지 기록하는 방식입니다. 국내 문서에서는 지속적 프로파일링으로 옮겨 부르기도 하고, 프로덕션에서 상시로 돌린다는 뜻에서 프로덕션 프로파일링이라 부르기도 합니다.
이미 메트릭과 로그, 트레이스를 모으고 있다면 장애가 났을 때 어디를 볼지는 대개 정해져 있습니다. 응답시간 그래프에서 구간을 찾고, 트레이스에서 느린 스팬을 열고, 그 시각의 로그를 봅니다. 그런데 그 스팬 안에서 어느 함수가 CPU를 쓰고 있었는지는 셋 중 어디에도 남아 있지 않습니다.
재현이 되면 로컬에서 프로파일러를 붙여 보고, 리눅스 CPU 사용률이 높은 이유에서 다룬 것처럼 스레드 덤프로 그 순간을 뜰 수도 있습니다. 다만 특정 시간대에만 나타나는 문제라면 재현 자체가 어렵습니다. 스레드 덤프가 수집한 순간의 상태를 보여 주는 한 장의 기록이라면, 프로파일은 문제가 발생하기 전부터 계속 쌓아 둔 샘플이라는 점이 다릅니다.
OpenTelemetry는 프로파일을 이렇게 정의합니다.
A profile is a collection of samples and associated metadata that shows where applications consume resources during execution.
실행 중 애플리케이션이 어디서 자원을 쓰는지 보여 주는 샘플과 메타데이터의 모음입니다. 샘플은 특정 시점에 수집한 스택 한 장을 말합니다.
프로파일을 옵저버빌리티 네 번째 시그널이라 부르는 것은 이 표의 마지막 줄 때문입니다. 앞의 셋이 답하지 못하는 질문 하나를 맡습니다. 앞의 세 시그널을 장애 상황에서 어떤 순서로 보는지는 메트릭·로그·트레이스 보는 순서에서 다뤘습니다.

CPU 프로파일링이 가장 먼저 쓰입니다. CPU 사용률이 높다는 것까지는 메트릭이 알려 주지만, 어느 코드에서 CPU 시간을 많이 썼는지는 스택 샘플을 모아야 알 수 있습니다. CPU 프로파일러는 일정한 간격으로 실행 중인 스택을 수집합니다. 같은 함수와 호출 경로가 여러 번 관찰될수록 해당 코드에서 CPU 시간을 많이 썼다고 추정할 수 있습니다. 이 샘플을 함수 호출 관계에 따라 쌓아 그린 것이 플레임 그래프(flame graph)입니다. 가로 폭은 해당 함수와 그 아래에서 호출한 함수까지 포함해 관찰된 샘플의 비중을 나타내고, 세로는 호출 깊이를 나타냅니다.
자원이 CPU만은 아닙니다. 메모리 프로파일링은 같은 방식으로 어느 코드 경로가 할당을 일으켰는지 모읍니다. 힙이 계속 차오르는데 원인 객체를 못 찾을 때 쓰는 쪽이 이쪽입니다.
메트릭과 로그, 트레이스로는 무슨 일이 일어났는지를 각각 다른 각도에서 봅니다. 프로파일로는 그 일을 일으킨 것이 어느 코드인지를 확인합니다. 그래서 프로파일은 메트릭·로그·트레이스를 대체하지 않고 그다음 단계에서 씁니다.
메모리 부족 로그에서 출발해 메모리 압박을 만든 코드 경로를 찾고, 메트릭의 CPU 스파이크에서 해당 함수로 바로 넘어가고, 트레이스의 느린 스팬에서 그 구간의 프로파일을 엽니다.
프로파일링은 실행 중인 프로그램의 스택을 표본으로 수집해 자원 사용량을 코드에 귀속시키는 작업입니다. 프로파일링 자체는 새로운 기술이 아닙니다. Go의 pprof나 Java의 JFR(Java Flight Recorder)처럼 런타임마다 도구가 오래 있었습니다. 달라진 것은 그 데이터를 다른 시그널과 같은 파이프라인으로 보내는 표준이 생기고 있다는 점입니다.
알파는 규격의 기본 구조를 공개하고 여러 구현에서 시험하며 피드백을 받는 단계입니다. 아직 변경될 수 있고, 프로덕션 안정성을 보장하는 단계는 아닙니다. 도입을 검토한다면 발표 블로그의 이 문장을 먼저 봐야 합니다.
Note that with the Alpha status of the release, the signal should not be used for critical production workloads.
핵심 프로덕션 워크로드에 쓰지 말라는 뜻입니다. 표준을 만드는 쪽이 직접 적어 둔 문장입니다.

OpenTelemetry Profiles 규격을 프로덕션 수준으로 수신해 보관하는 백엔드가 아직 갖춰지지 않았다는 것이 가장 큰 제약입니다. 발표문도 프로덕션급 백엔드가 나오지 않았다고 적고 있습니다. 일부 벤더가 지원을 예고했고, 시험용으로 쓸 수 있는 오픈소스 구현도 나와 있습니다. 보낼 수는 있는데 오래 보관하고 다시 찾아보는 단계가 아직 없습니다.
수집·전송 쪽은 상대적으로 앞서 있습니다. eBPF는 커널에서 프로그램을 안전하게 실행해 시스템 동작을 관찰하는 리눅스 기능입니다. eBPF 프로파일러는 Elastic이 기부해 opentelemetry-ebpf-profiler 저장소에서 관리되고, 리눅스에서 실행 중인 프로세스 전체의 스택을 애플리케이션 수정 없이 수집합니다. 지원 런타임은 HotSpot JVM과 Python, Ruby, PHP, Node.js의 V8, Perl, .NET처럼 널리 쓰이는 쪽을 아우릅니다. Go와 C, C++, Rust 같은 네이티브 코드도 지원합니다. 커널 공간에서 시작해 시스템 라이브러리를 지나 각 언어 런타임까지 하나의 스택으로 합쳐 보여 줍니다.
다만 런타임마다 성숙도가 다릅니다. 이번 알파에는 Go 실행 파일의 자동 심볼화, Node.js V8의 ARM64 지원, .NET 9와 10 지원, Ruby 스택 해석 개선이 들어갔고, Erlang과 Elixir를 실행하는 가상 머신 BEAM은 초기 지원 단계입니다.
심볼화는 스택에 찍힌 메모리 주소를 함수 이름으로 되돌리는 작업입니다. 심볼화가 안 되면 플레임 그래프를 열어도 함수 이름 대신 주소만 보입니다. 컴파일 언어에서 특히 문제가 되는데, 표준 API가 아직 정해지지 않았습니다. Go는 이번 알파부터 심볼화가 자동으로 됩니다.
지금 단계에서 할 수 있는 일은 도입이 아니라 평가입니다.
1. 운영 중인 런타임이 지원 목록에 있는지 확인합니다. HotSpot JVM과 Go, .NET, Ruby, Node.js의 V8은 목록에 있고 BEAM은 초기 단계입니다. 같은 언어라도 버전과 아키텍처에 따라 해석 범위가 달라 실제 운영 버전으로 확인해야 합니다.
2. 커널 조건을 확인합니다. eBPF 프로파일러는 리눅스에서 동작합니다. 커널 버전과 권한 요건을 먼저 확인합니다. eBPF 수집 방식의 제약은 eBPF 모니터링이란에서 따로 다뤘습니다. 컨테이너 환경이라면 eBPF 프로그램 실행에 필요한 커널 권한과 보안 설정도 함께 확인합니다.
3. 어디에 저장할지 정합니다. 이 단계가 지금 가장 어렵습니다. 쓰고 있는 백엔드가 프로파일을 받는지, 받는다면 보관 기간과 비용이 어떻게 되는지 확인하지 않으면 수집만 켜 두고 저장할 곳이 없습니다.
4. 수집 비용을 측정합니다. 프로덕션 프로파일링은 문제가 난 뒤 잠깐 붙이는 방식이 아니라 평소에 계속 켜 두는 것을 전제합니다. 비용이 두 군데서 나옵니다. 하나는 프로파일러 자체가 쓰는 CPU와 메모리입니다. 컨테이너로 운영한다면 프로파일러 몫까지 포함해 CPU 제한에 걸리지 않는지 함께 봅니다. 실제 오버헤드는 런타임과 워크로드에 따라 달라서, 공개된 수치보다 운영 환경에서 직접 재 본 값이 확실합니다.
다른 하나는 저장 비용입니다. 프로파일은 샘플링 주기에 따라 데이터 양이 달라집니다. 주기를 촘촘히 하면 자세히 보이지만 데이터가 늘고, 넓히면 짧게 튀는 구간을 놓칩니다. 상시 수집은 데이터가 계속 들어오므로 3번에서 정한 보관 기간이 월 비용을 좌우합니다. 해당 워크로드에서 어느 쪽이 맞는지는 실제로 켜 보고 정하는 편이 빠릅니다.
5. 기존 시그널과 연결할 지점을 정합니다. 프로파일만 따로 보면 쓸모가 크게 줄어듭니다. 트레이스의 스팬에서 같은 시각 프로파일로 바로 넘어갈 수 있어야 앞에서 본 사용 예가 성립합니다. 프로세스·스레드 컨텍스트 공유가 아직 미완이라 이 연결을 지금 그대로 구현하기는 어렵습니다.
당장 프로덕션에 넣을 단계는 아닙니다. 다만 표준이 정해지는 중이라 규격을 미리 읽어 두면 나중에 백엔드를 고를 때 판단이 빨라집니다. 지금은 시험 환경에서 한 서비스에 걸어 보고 데이터가 어떻게 생겼는지 익히는 정도가 적당합니다.
Continuous Profiling과 APM의 프로파일링은 같은 계열입니다. APM(애플리케이션 성능 모니터링) 도구들도 일정 간격으로 스택을 수집해 어느 메서드가 시간을 쓰는지 보여 주는 기능을 오래 제공했습니다. 다르다면 범위와 표준입니다.
범위부터 보면 APM 쪽은 대개 트랜잭션 단위로 계측한 애플리케이션 안을 봅니다. Continuous Profiling은 수집 방식 하나를 가리키는 말이 아닙니다. 런타임 프로파일러로 수집할 수도 있고, 리눅스라면 eBPF로 애플리케이션을 고치지 않고 시스템 수준에서 스택을 모을 수도 있습니다. OpenTelemetry 문서도 타이머나 eBPF로 일정 간격마다 샘플을 수집하는 방식과 런타임 훅으로 이벤트를 기록하는 방식을 나눠 설명하고, Profiles가 둘을 모두 담도록 설계했다고 밝힙니다.
표준 쪽은 형식의 문제입니다. APM 도구의 프로파일링은 벤더마다 데이터 형식이 달라 도구를 바꾸면 과거 프로파일을 그대로 가져가기 어려웠습니다. OpenTelemetry Profiles는 어느 방식으로 수집했든 같은 형식으로 주고받는 것을 목표로 합니다.
Java 애플리케이션도 지금 프로파일링할 수 있습니다. eBPF 프로파일러의 지원 런타임에 HotSpot JVM이 들어 있어, 커널과 시스템 라이브러리를 거쳐 JVM이 실행 중인 Java 메서드까지 한 스택으로 보여 줍니다. JVM은 심볼 정보를 런타임이 가지고 있어서 컴파일 언어에서 겪는 심볼화 문제와는 성격이 다릅니다. JFR처럼 런타임이 제공하는 도구도 OpenTelemetry와 별개로 지금 그대로 쓸 수 있습니다.
권고는 아직 아닌 쪽입니다. 그래도 지금 읽어 둘 값은 있습니다. 백엔드를 고를 때 무엇을 물어볼지 정리할 수 있습니다. 심볼화를 에이전트에서 하는지 백엔드에서 하는지, 프로파일과 트레이스를 무엇으로 연결하는지, 보관 기간과 과금 단위가 무엇인지 같은 질문입니다. 반대로 지금 특정 도구에 맞춰 파이프라인을 고정하면 규격이 바뀔 때 다시 손봐야 합니다.
OpenTelemetry가 프로파일을 트레이스·메트릭·로그와 나란히 두는 시그널로 다루고 있으므로 그 안에서는 확정된 구분입니다. 다만 안정화 단계는 아직 알파이고 다음 단계가 베타입니다. 시그널로 인정된 것과 프로덕션에서 쓸 수 있는 것은 다른 이야기입니다.
Continuous Profiling은 앞의 세 시그널이 답하지 못하는 질문 하나를 맡습니다. 어느 코드가 자원을 쓰는가입니다. OpenTelemetry에서 표준이 되는 중이지만 아직 알파이고, 이 규격을 프로덕션 수준으로 받아 보관하는 백엔드가 갖춰지지 않은 것이 지금의 제약입니다.
지금은 시험 환경에서 확인해 둘 단계입니다. 런타임 지원과 커널 조건, 저장 위치, 수집 비용, 기존 시그널과의 연결 지점을 순서대로 확인해 두면 규격이 안정될 때 바로 움직일 수 있습니다.
코드 단위까지 내려가는 표준이 오기 전에도 트랜잭션 안에서 시간이 어디에 쓰였는지는 지금 확인할 수 있습니다. 와탭 애플리케이션 모니터링은 일정 간격으로 액티브 스택을 수집해 저장해 두고, 느린 트랜잭션에서 그 시각의 스택으로 넘어가 볼 수 있습니다.