OpenTelemetry
개요
오픈텔레메트리는 관측 가능성을 위한 오픈소스 api, sdk, 툴의 집합체이다.
관측 가능성을 위한 하나의 프로토콜 표준이자, 개발 도구이면서 시스템 도구라는 것이다.
그만큼 광범위한 내용을 담고 있고 다양한 생태계를 확보하고 있으며, 용어 하나에 많은 의미를 담고 있다.
이를 더 깊게 이해하기 위해서는, 오픈텔레메트리라는 것을 조금 더 세분화하여 이해할 필요가 있다.
오픈텔레메트리 요소
다음의 요소들이 전부 오픈텔레메트리라는 용어에 포함된다.
- 모든 요소들에 대한 명세서
- 텔레메트리 데이터 형식을 지정하는 표준 프로토콜
- 데이터 형식과 이름 양식을 지정하는 컨벤션
- 위의 각 요소를 활용해 개발하기 위한 언어 개발 환경(SDK)
- 라이브러리와 프레임워크로 이루어진 에코시스템
- 제로 코드로 데이터를 생성하는 자동 도구
- 데이터를 수집하고 처리하는 컬렉터
굳이? 싶을 정도로 한 용어에 알차게 많은 개념을 담았다.
결국 관측 가능성을 위한 프로토콜을 정의하면서 관련한 코드를 개발할 수도 있는 한편, 코드 없이 운영적 관점에서 데이터를 생성해낼 수도 있고 전반 시스템을 구축할 수도 있고..
개인적으로는, 오픈 텔레메트리라고 할 때 이렇게 다양한 개념을 가지고 있다는 것을 유의하며 각 요소들이 무엇인지를 이해하는 것이 중요할 것 같다.
왜 이따구로 발전이 진행되고 있는가에 대한 고민을 해결하기 위해서는, 왜 오픈텔레메트리가 나오게 됐는지를 먼저 봐야할 것이다.
배경
관측 가능성의 필요성이 대두된 이후, 다양한 시도와 생태계가 난립하는 관측 가능성 춘추 전국시대에 구국을 위해 등장한 오픈텔레메트리.
원래는 OpenTracing, OpenCensus라는 별개의 두 가지 프로젝트가 있었는데 CNCF에 프로젝트가 병합되어 기증되며 오텔이 생겨나게 됐다.
두 프로젝트는 데이터를 보내고 수집하는 등의 표준을 지정하고자 했고, 이들의 결합으로 비로소 다양한 케이스를 커버할 수 있고, 나아가 확장이 용이한 시스템이자 프로토콜, 툴로서의 오픈텔레메트리가 만들어지게 됐다.
특징
오픈텔레메트리는 다음의 특징을 가진다.
- 벤더 중립적
- 개발자든, 운영자든 이를 위한 구축과 개발을 진행할 수 있다.
- 개발자는 자신의 로직에 관련 세팅을 추가한다.
- 운영자는 전반 아키텍쳐를 구축하고, 코드를 건드리지 않으면서 최대한 데이터를 수집할 수 있도록 에이전트를 배포한다.
- 그래서 zero code, code based, libraries라 계측 도구를 자유롭게 정의할 수 있다.
- 언어, 인프라, 런타임 환경 등 어떤 것에서든 데이터를 가져올 수 있도록 정의한다.
- 관측 가능성의 모든 시그널 유형을 아우른다.
- Trace, Log, Metric 등 모든 데이터의 양식을 지정하고 방향성을 제시한다.
- 현재 가장 성숙하게 발전된 것은 Trace이고, 점차 Log도 안정화단계로 접어들 것으로 생각된다.
오텔이 다루는 데이터 - 시그널
이제부터 오픈텔레메트리의 여러 개념을 구체화시켜 정리하고자 한다.
관측가능성에서 분류되는 데이터 유형을 오텔에서는 신호(Signal)이라 부른다.
이것은 시스템, 어플리케이션의 출력물이라고 조금 더 명시적으로 정의된다.
흔히 아는 그 개념들에, 추가적으로 Baggage 한 가지 개념이 더 있다.
Trace
개념 자체는 관측 가능성에 넣었으므로 생략한다.
스팬을 통해 추적이 가능해진다.
이 시그널과 관련된 컴포넌트들을 보겠다.
이것들은 개발 언어 내에서 구현되는 친구들이라 보면 될 것 같다.
- Tracer Provider
- 아래의 Tracer를 만드는 공장이다.
- 어플리케이션과 라이프사이클을 함께하는, 코드에 내장된 팩토리 메서드 같은 놈이라 보면 되겠다.
- Tracer
- span을 만드는 개별 요소.
- 실질 트레이스를 담당하는 구현체가 된다.
- Trace Exporter
- 만들어진 트레이스를 외부로 보내는 로직.
- 외부라 하면 표준 출력, 아니면 다른 수집기, 디버깅 등 다양한 요소가 될 수 있다.
Span
여기에서는 스팬의 구성 요소를 조금 더 깊게 보겠다.
{
"name": "/v1/sys/health",
"context": {
"trace_id": "7bba9f33312b3dbb8b2c2c62bb7abe2d",
"span_id": "086e83747d0e381e"
},
"parent_id": "",
"start_time": "2021-10-22 16:04:01.209458162 +0000 UTC",
"end_time": "2021-10-22 16:04:01.209514132 +0000 UTC",
"status_code": "STATUS_CODE_OK",
"status_message": "",
"attributes": {
"net.transport": "IP.TCP",
"net.peer.ip": "172.17.0.1",
"net.peer.port": "51820",
"net.host.ip": "10.177.2.152",
"net.host.port": "26040",
"http.method": "GET",
"http.target": "/v1/sys/health",
"http.server_name": "mortar-gateway",
"http.route": "/v1/sys/health",
"http.user_agent": "Consul Health Check",
"http.scheme": "http",
"http.host": "10.177.2.152:26040",
"http.flavor": "1.1"
},
"events": [
{
"name": "",
"message": "OK",
"timestamp": "2021-10-22 16:04:01.209512872 +0000 UTC"
}
]
}
- context
- trace_id
- span_id
- trace flag라 하여 트레이스의 정보를 이진데이터로 담을 수 있다.
- trace state라 하여 벤더별 특정 정보를 담을 수 있다.
- attribute
- 트래킹을 하고 싶은 각종 데이터를 키값쌍으로 넣는 공간이다.
- event
- 스팬의 메타데이터 정보를 담을 때 쓰는 공간.
- 일종의 로그 정보라 할 수 있겠다.
- attribute보다 명시적으로 인지하고 싶은 데이터들을 여기에 넣으라고 한다.
각 스팬은 상태값을 가진다.
- Unset - 에러가 발생하지 않고 종료됨
- Error
- Ok - 개발자가 구현에 있어서 명시적으로 성공을 지정하고 싶다면 사용
간단히 말해서 스팬의 상태값을 지정하지 않으면 기본적으로 에러가 없는 것인데, 개발자가 명시적으로 에러가 없다는 것을 남기고 싶다면 Ok로 지정해도 된다는 것이다.
또 스팬에는 여러 유형이 있다.
이 값은 트레이스 데이터로서 합칠 때 일종의 각 스팬이 무엇인지 나타내는 힌트가 되어준다.
- Client - 동기 요청을 보내는 측의 스팬
- Server - 요청을 받는 측의 스팬
- Internal - 한 프로세스 내부에서만 발생하는 스팬
- Producer - 큐나 이벤트 리스너 아키텍쳐 상에서 비동기적으로 요청을 보내는 측의 스팬
- Consumer - 비동기적인 요청을 수행하는 측의 스팬
client - server 구조와, producer - consumer 구조가 있는 것이 보일 것이다.
후자는 비동기, 혹은 이벤트 드리븐 아키텍쳐에서 상정하는 스팬 유형이라 보면 될 것 같다.
Baggage
스팬이란 건 결국 각 요소들이 만들어내는 하나의 로그이다.
하나의 서비스(서버) 안에서는 스팬의 각종 속성을 자식 스팬에 전달하는 것이 쉽다.
그런데 각 요청이 전파되고 또 다른 서비스와 연계되는 과정 속에서 한 가지 문제에 맞닥뜨린다.
결국 스팬이 로그라면, 원격 서비스간 로그를 전달하는 게 아니라면 어떻게 다음 스팬에서 기입할 추가 정보를 전달하는가?
이런 컨텍스트 전파를 위해 사용되는 것이 Baggage이다.
요청이 전달될 때 키값쌍으로서 요청에 같이 전달하는 방식인 것이다.
오텔을 구현하는 구현체는 baggage라는 특수한 형태의 시그널을 사용할 수 있도록 해야 한다.
메트릭, 로그
이건 크게 다른 내용과 다르지 않은 것 같아서 넘어간다.
계측(instrumentation)
시스템이 관측 가능하다는 것은 사람에게 계측된다는 것이다.
즉 시스템의 컴포넌트들은 위의 시그널들을 방출해야 한다.
이를 위해서 오텔에서는 몇 가지 방법을 제안하고 마련했다.
코드 베이스
개발자가 어플리케이션을 개발하며 내부에서 오텔 api를 사용해 데이터를 만들고 전달한다.
오텔 sdk를 이용해 관련 설정들을 코드 내부에 구현하여 사용하는 방식이다.
그럼 직접 api를 정의하고, sdk고 데이터를 만들고 외부로 전파하는 것까지 전부 직접 구현하면 된다!
그렇다면 다른 오텔 호환 툴들에서 시그널들을 활용할 수 있게 될 것이다.
제로 코드
(대체로) 개발자가 이미 만들어진 라이브러리를 런타임에 포함해 알아서 데이터를 전달하는 방식이다.
운영자 입장에서 편리하게 세팅할 수 있다는 장점이 있다.
다만 상세한 커스텀은 힘들 것이다.
제로코드는 이렇게 이미 잘 만들어진 번들을 어플리케이션 런타임에 주입하는 것이다.
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
opentelemetry-instrument \
python myapp.py
파이썬으로 치면 이런 식으로 실행한다.
이러면 내부 코드 중에 requests, flask 등의 코드가 들어가는 지점마다 자동으로 오텔 관련 코드가 주입된다.
Go 언어의 경우도 이렇게 하는 게 가능한데, 이렇게 컴파일된 채 실행되는 프로그램의 경우, eBPF를 활용해서 네트워크 스택 호출, 프로세스 작업 전환 등의 케이스에 대해 필요한 작업들을 수행한다.
(이래서 go instrument의 경우 루트 권한으로 실행돼야 한다.)
다양한 프레임워크를 위한 제로코드 라이브러리가 있어서 여기에서 확인해보고 사용할 수 있을 듯하다.[1]
관련 문서
이름 | noteType | created |
---|---|---|
OpenTelemetry | knowledge | 2025-02-28 |
Jaeger | knowledge | 2025-04-29 |
OpenTelemtry Operator | knowledge | 2025-04-29 |
4주차 - opentelemetry 데모 | project | 2025-03-01 |
4W - 오픈텔레메트리 기반 트레이싱 예거 시각화, 키알리 시각화 | published | 2025-05-03 |