Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 297 additions & 0 deletions week03/giribuin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
<!-- status: | 🌱 raw | 🔨 dev | ✅ done | 🗑️ drop | -->
## ⬛ Summary
> Observability는 시스템 외부에 드러난 log, metric, trace 같은 telemetry를 통해서 내부 상태와 장애 원인을 추론할 수 있게 하는 것이다. 백엔드에서는 요청 흐름, 병목을 추적하는 데 주로 사용한다. AI Agnet가 발전하면서 agent의 동작 흐름을 추적하는 방향으로도 확장되고 있다.
---
## ⬛ Content
### Observability
- 시스템이 왜 이렇게 동작했는지를 외부로 드러난 신호를 통해 내부 상태를 추론할 수 있게 만드는 능력
- Observability lets you understand a system from the outside by letting you ask questions about that system without knowing its inner workings
---
#### Monitoring vs Observability
- Monitoring: 지금 문제가 생겼는가?
- CPU 사용률 > 80\%
- API 500 에러율 5\% 넘었나?

- Observability: 왜 문제가 생겼는가?
- 왜 특정 사용자의 요청만 느린가?
- 왜 결제 요청 중 일부만 실패하는가?
- 같은 API인데 왜 모바일 앱에서만 에러가 발생하는가?

> Monitoring은 미리 정해둔 지표와 알림을 보는 것이라면, Observability는 예상하지 못한 문제도 해결하기 위해 log, metric, trace 같은 telemetry를 남기는 것
>
> Monitoring과 Observabililty는 같은 데이터를 공유하지만 그 데이터를 통해 얻고자 하는 목적이 다름. 장애가 발생했을 때 원인을 추적할 수 있는 기록을 남기는 것

---
##### Log, Metric, Trace
###### Log: 특정 시점에 발생한 event 기록

~~~
2026-06-26T12:01:03Z ERROR payment failed order_id=123 reason=timeout
~~~

- 개별 event에 집중
- 장점: 구체적으로 기록을 남길 수 있음
- 결제 실패, 실패 원인 등
- 한계: 로그만으로 전체 흐름을 파악하기 어려움
- 여러 사용자들의 로그가 겹칠 때, 한 눈에 파악하기 어려움
- 상관관계를 가지는 ID가 필요(trace_id, request_id)
---
###### Metric: 시간에 따른 수치 데이터

~~~
http_requests_total = 152340
http_request_duration_p95 = 350ms
cpu_usage = 82%
error_rate = 3.2%
~~~

- metric은 전체 상태의 추세에 집중
- 에러율이 점점 증가하고 있나?
- 응답 시간이 점점 느려지나?
- 트래픽이 점점 커지나?
- 장점: 미리 정한 기준에 대해 알람 남길 수 있음
- cpu 사용량 80% 넘기면 알림
- 한계: 문제가 발생한 건 알지만, 왜 발생했는지는 모름
---
###### Trace: 하나의 요청이나 작업이 시스템 내부에서 지나간 경로

~~~
Trace: POST /orders

Client
→ API Gateway
→ Auth Service
→ Order Service
→ Payment Service
→ DB
→ Message Queue
~~~

- 여러 개의 span으로 구성
- span: 요청 안의 개별 작업 단위
- trace: 전체 요청 흐름
- 장점: 문제의 원인을 찾는 데 강함
- Metric을 통해 API 병목을 발생했다는 것을 알았다고 하면
- Trace를 통해 어디에서 얼마나 시간이 소요되었는지를 확인할 수 있음
- 한계: 모든 맥락을 파악할 수는 없음
- 어디서 API가 시간을 많이 썼는 지는 확인했지만
- 어떤 코드가 문제를 일으켰는지는 log랑 같이 확인해야 함

**Span, Trace, Parent-Child Span**

- Trace ID: 하나의 요청 전체를 묶는 ID
- 요청에 대한 서비스 흐름을 재구성 할 수 있음
- Span ID: 요청 안의 개별 작업 ID
- Parent Span: 어떤 작업이 이 작업을 호출했는지 나타내는 상위 span
- Child Span: 상위 작업 안에서 파생된 하위 작업

~~~
Trace: POST /orders 요청 전체

Span 1: API Gateway 요청 수신
Span 2: Auth Service 토큰 검증
Span 3: Order Service 주문 생성
Span 4: DB insert
Span 5: Payment API 호출
~~~


---
#### AI Agent Observability
- 보통은
- 어떤 API가 느리지?
- 어떤 DB query가 느리지?
- 어떤 서비스에서 에러가 났지?
- 어떤 요청이 어떤 서비스를 거쳤지?

~~~
Log = payment failed(결제 실패)
Metric = error_rate, latency
Trace = POST /orders 요청 흐름
~~~

---
- AI Agent에서는
- 왜 이 tool를 호출했지?
- 왜 검색 query를 이렇게 만들었지?
- 검색된 문서는 잘 검색된건가?
- 검색 결과는 잘 해석했나?
- 판단 과정에 문제는 없었나?
- 최종 답변의 신뢰도는 어떤 증거들로 뒷받침하고 있나?

~~~
Log = agent가 남긴 구체적 실행 기록
Metric = token usage, cost, latency, success rate, tool failure rate
Trace = user request → LLM call → tool call → retrieval → final answer 흐름
~~~

---

> AgentTrace\[2\]
> LLM 기반으로 autonomous agents의 역량이 커졌지만, 중요한 분야에서 도입은 제한적임. 그 이유는 보안 문제 때문임. LLM은 nondeterministic(동일 프롬프트라도 결과 가매번 다름)으로 동작하기 때문에 software assurance의 기반인 static auditing 방식을 무력화 시킴.
>
> 기존의 보안 방법론(입음

~~~
traceparent: 00-<trace-id>-<parent-id>-<trace-flags>
~~~

HTTP 요청처럼 바로 호출하는 경우

~~~
Service A → HTTP → Service B
~~~

- 이 경우는 단순하지만, queue나 background job이 끼면 복잡해짐

~~~
Order Service
→ Kafka / RabbitMQ / SQS
→ Notification Worker
~~~

- trace context를 header에 넣어서 전달해야 함. 하지 않으면,
- 주문 요청 trace와 알림 worker 처리 trace가 다른 trace처럼 보일 수 있기 때문

---
##### Sampling 문제

Distributed tracing은 유용하긴 한데 모든 요청을 다 저장하면 cost가 너무 큼

그래서 sampling을 사용해서 원인 분석에 필요한 trace를 남김

~~~
정상 요청 1%만 저장
에러 요청은 100% 저장
latency가 2초 넘는 요청은 100% 저장
~~~

- Head-based sampling: 요청 시작 시점에 저장 여부 결정

- Tail-based sampling: 요청이 끝난 뒤 에러/지연 등 결과를 보고 저장 여부 결정

---

#### Context Propagation

Trace 정보를 서비스 간에 전달해서, 여러 시스템에서 발생한 span들을 하나의 trace로 이어 붙이는 매커니즘
- trace_id와 parent span 정보를 다음 서비스로 넘겨주는 것

> Distributed tracing이 가능하려면 각 서비스가 같은 trace context를 공유해야 함

**context: 요청을 추적하기 위해 필요한 부가 정보**
- trace_id, span_id, parent_span_id, sampling flag, baggage

**Propagation: 한 서비스에서 다음 서비스로 요청을 보낼 때 trace context도 같이 보내는 것**

```
Service A
└─ 현재 trace context 보유

Service A → Service B 요청
└─ trace context를 HTTP header에 삽입(inject)

Service B
└─ header에서 trace context 추출(extract)
└─ child span 생성
```

OpenTelemetry에서는 두 단계로 수행
- inject: 현재 context를 outbound 요청에 넣기
- extract: inbound 요청에서 context 꺼내기

**Baggage: 추가적인 비즈니스 context 전달하는 것**
- 여러 서비스에서 어떤 정보를 알고 싶을 때 baggage로 전달 할 수 있음
- 민감정보나 너무 큰 데이터 같은 걸 넣을 때 조심
- 모든 downstream 서비스로 퍼질 수 있기 때문

---
#### OpenTelemetry

telemetry 데이터를 생성/수집/처리/전송하기 위한 표준 프레임워크

##### 필요성

서비스마다 관측 도구를 직접 붙이면 구조가 복잡해짐

백엔드 서버에서 도구들을 직접 연동한다고 하면,

```
Trace → Jaeger
Metric → Prometheus
Log → Elasticsearch / Loki
APM → Datadog
```

애플리케이션 코드가 특정 벤더에 종속되게 됨

이 문제를 해결 하기 위해서 중간 계층으로 OpenTelemetry를 둠
- Opentelemetry 방식으로 telemetry 생성
- Collector가 받아서 원하는 backend로 export

```
[1] Application (실제 서비스 코드)
[2] Instrumentation (코드에서 telemetry를 생성하도록 instrument)
[3] OpenTelemetry API (span/metric/log를 만드는 interface)
[4] OpenTelemetry SDK (API의 실제 구현체)
[5] Exporter (telemetry를 외부로 내보냄)
[6] OpenTelemetry Collector (telemetry를 받고, 처리해서 각 backend로 전달)
[7] Observability Backend (Jaeger, Prometheus, Grafana, Datadog, Loki 등 저장/시각화 도구)
```

다음 목적을 위해 사용:
1. telemetry 생성 방식 표준화
2. trace / metric / log 수집 방식 표준화
3. observability backend 교체 비용 감소
4. 여러 언어와 프레임워크의 계측 방식 통일
---
#### Semantic Convention

telemetry 데이터의 이름, 의미, 타입, 단위를 표준화하는 규칙

필드명만 정하는 게 아니라 코드베이스·라이브러리·플랫폼 전반에서 공통 naming scheme을 따르도록 함

1. attribute name
2. attribute type
3. attribute meaning
4. valid values
5. span name
6. span kind
7. metric name
8. metric unit
9. event name
10. resource attribute

##### Cardinality 문제

어떤 attribute가 가질 수 있는 고유 값의 개수인데, semantic convention과 같이 알아야 함

```
낮은 cardinality:
http.request.method = GET / POST / PUT / DELETE
http.response.status_code = 200 / 404 / 500
region = kr / us / eu

높은 cardinality:
user.id = 수백만 개
order.id = 수천만 개
session.id = 수억 개
request.id = 요청마다 다름
```

- metric label에 user_id를 넣는다고 하면, 사용자 수만큼 시계열이 증가
- 일반적으로 Metric lable은 낮은 cardinality 위주
- Trace attribute는 디버깅에 필요한 고유 ID 일부 허용
- Log는 상세 맥락 기록이 가능하지만 개인정보/보안에 주의하면서 사용

---
## ⬛ Links
\[1\] "Observability primer | OpenTelemetry". no date, https://opentelemetry.io/docs/concepts/observability-primer/

\[2\] A. AlSayyad, K. Y. Huang and R. Pal, "AgentTrace: A Structured Logging Framework for Agent System Observability", University of California, Berkeley, no date, https://arxiv.org/pdf/2602.10133