AIOps 스터디 첫 주차 내용으로, AIOps가 정확히 어떤 개념인지 정리하고 밀접한 관련이 있는 Observability에 대해서도 함께 정리합니다.
Observability in the AI-Native Era 의 아래 챕터 내용을 정리했습니다.
1990년대~2000년대 초, IT 시스템을 운영한다는 건 비교적 단순했다. 서버 몇 대, 잘 알려진 애플리케이션 몇 개. CPU가 90%를 넘으면 알림을 보내고, 디스크 여유 공간이 5% 미만이면 누군가 달려가서 처리했다. SNMP, JMX 같은 표준 프로토콜로 OS와 애플리케이션 메트릭을 긁어오는 방식은 당시엔 충분했다. 서버 이름도 sql-prod-1, app-frontend-4 같이 기억하기 쉬운 이름을 붙일 수 있었다. CMDB(Configuration Management Database)에 모든 걸 수동으로 기록해도 관리가 됐다.
그런데 세상이 바뀌었다. 물리 서버 몇 대가 수백 개의 VM이 됐고, 모놀리식 앱이 수백 개의 마이크로서비스로 쪼개졌다. 여러 가용 영역에 걸쳐 파드가 배포되고, 서버리스 함수가 이벤트에 반응하며, SaaS API와 온프레미스 시스템이 혼재하는 하이브리드 환경이 됐다. 소규모 환경에서도 9개 앱이 3,304개 마이크로서비스, 10,000개 이상의 파드, 142개 호스트, 7개 글로벌 데이터센터에 걸쳐 동작하는 게 현실이다.
이 복잡도에서 단일 메트릭 + 정적 임계값 방식은 쉽게 무너질 수 있다. 수천 개의 파드에 각각 임계값을 설정하고 관리하는 건 불가능에 가깝고, 설정한다 해도 동적으로 스케일링되는 환경에서는 의미가 없다.
GPT에 물어보면 이렇게 답한다:
"Observability는 외부 출력(로그, 메트릭, 트레이스)을 통해 시스템의 내부 상태를 이해할 수 있는 특성이다. Monitoring은 사전 정의된 메트릭과 임계값으로 시스템 헬스를 추적하는 프로세스다. Observability는 proactive하고 탐구적이며, 왜 문제가 발생했는지 이해할 수 있게 한다. Monitoring은 reactive하며, 문제가 발생한 후 알려준다."
핵심은 여기에 있다. 모니터링은 미리 알고 있는 것에 반응하고, Observability는 알지 못했던 것을 탐색할 수 있게 한다. 정적 시스템에서는 모니터링으로 충분했지만, 동적이고 복잡한 클라우드 네이티브 환경에서는 Observability가 필수다.
2016년 Gartner가 AIOps를 정의하며 "ML과 빅데이터 분석으로 IT 운영을 자동화하고 강화한다"는 비전을 제시했다. 초기 목표는 여러 Observability 도구에서 오는 신호들을 상관 분석해 알림 노이즈를 줄이는 것이었다.
하지만 초기 AIOps는 약속을 지키지 못했다. 이유는 명확하다: 비표준화된, 단절된 데이터셋. 온프레미스와 클라우드에서 오는 데이터를 표준화하는 데 막대한 수작업이 필요했고, 로그·메트릭·트레이스·이벤트를 연결하는 표준도 없었다. ROI를 증명하기도 어려웠다.
2026년 현재, AIOps가 원래 약속을 이행할 수 있는 조건이 갖춰졌다. 핵심은 다음 5가지 자동화 능력이다:
소방관처럼 불을 끄는 것에서, 불이 나기 전에 예방하는 것으로의 전환이다.
메트릭은 서버, 프로세스, 데이터베이스, 애플리케이션 같은 entity에서 수집하는 수치 데이터다. CPU 사용률, 메모리 소비량, 서비스 응답시간, 실패율 등이 여기에 해당한다. 시간에 걸쳐 지속적으로 수집하면 시스템 동작을 추세로 파악할 수 있고, 알림 설정과 성능 최적화에 활용된다.
메트릭 수집의 주요 과제는 high cardinality, 고유한 데이터가 많아지는 문제이다다. 예를 들어 사용자 이름이나 IP 주소를 메트릭 차원으로 추가하면, 수십억 개의 고유 값이 생겨 분석이 불가능해진다. 게다가 기술 메트릭(요청 수)에 사용자 이름을 포함하면 조직 내 누구나 해당 메트릭을 통해 사용자 정보를 열람할 수 있어 개인정보 문제가 생길 수 있다.
로그는 가장 오래된 Observability 신호다. 코드를 짜본 사람이라면 누구나 print나 console.log를 써봤을 것이다. 현대 로깅 프레임워크는 timestamp, log level(ERROR/WARNING/INFO/DEBUG), context(request ID, application ID), content(실제 메시지) 같은 표준 필드를 구조화된 형태로 출력한다. Fluentd, Logstash, OpenTelemetry 같은 에이전트가 로그를 수집하고, 파드·네임스페이스·클러스터 정보로 추가 enriching한다.
로그 수집의 가장 큰 과제는 볼륨이다. 시스템은 엄청난 양의 로그를 생성하고, 그 중 일상 운영에 유의미한 것은 일부에 불과하다. 오래된 레거시 시스템의 비구조화된 로그도 골칫거리다. 빠른 디버깅을 위해 추가한 DEBUG 로그를 지우지 않고 방치하는 것도 흔한 실수다. 로그는 중요하지만, 올바른 로깅 문화와 자동화된 검사 없이는 비용만 잡아먹는 데이터 늪이 된다.
분산 트레이스는 메트릭/로그/트레이스 중 가장 최근에 제시된 개념이다. 단일 요청이 여러 서비스를 통과하는 전체 여정을 추적해, 각 구간의 지연시간과 동작을 파악할 수 있게 한다.
2000년대 초 Dynatrace, AppDynamics, New Relic 같은 APM 벤더들이 Java/.NET 바이트코드를 자동 계측하는 방식으로 도입했다. 웹 요청이 들어와서 애플리케이션 서버, 큐, 미들웨어, 백엔드 서비스, 데이터베이스를 거쳐 응답이 나가는 전체 흐름을 엔드투엔드로 볼 수 있게 됐다.
기술적 핵심은 trace context 전파다. 첫 서비스에서 생성된 고유 trace ID를 HTTP 헤더, 메시지 속성, 스레드 로컬 스토리지 등을 통해 마지막 서비스까지 전달해야 한다. 이 복잡한 전파 문제를 OpenTelemetry가 표준화했다. 각 트레이스는 고유 ID를 가지고, 웹 요청·DB 호출·메서드 실행 등 개별 작업은 span으로 표현되며, span들은 parent-child 관계로 트리를 구성한다.
trace 수집의 주요 과제는 과도한 계측, 중복 데이터, 샘플링이다. 독점 에이전트에서 OpenTelemetry 기반 개발자 직접 계측으로 전환이 늘어나면서, 이 세 가지 문제를 개발팀이 직접 고민해야 하는 상황이 됐다.
메트릭·로그·트레이스만으로는 충분하지 않을 수 있다. 현대 Observability는 다음 신호들도 포함하는 경우가 있다.:
이 모든 신호를 수집하고 분석하는 방식도 오픈소스 표준으로 수렴하고 있다.
OpenTelemetry(OTel): 가장 중요한 표준. 트레이스·메트릭·로그의 생성·수집·전송을 표준화한 CNCF 프로젝트. 저장·분석 백엔드가 아닌 수집 프레임워크다. OTel Collector가 핵심 컴포넌트로, receivers → processors → exporters 구조로 데이터를 정규화·샘플링·enriching하며 여러 백엔드로 전달한다. 대부분의 상용 Observability 플랫폼이 OTLP를 지원한다.
Prometheus: 2012년 SoundCloud에서 시작, 2016년 CNCF 합류. 메트릭 특화, 고카디낼리티 시계열 DB, PromQL. HTTP endpoint scraping 방식으로 동작하며 Alertmanager와 연동해 알림을 처리한다. 사실상 클라우드 네이티브 메트릭 표준이다.
Grafana / Perses: Grafana는 Prometheus의 사실상 기본 시각화 도구로 방대한 커뮤니티 대시보드를 보유한다. 단, 대시보드 파일 포맷이 비표준이라 다른 솔루션과 호환되지 않는다. Perses는 이 문제를 해결하기 위한 벤더 중립 오픈 대시보드 스펙으로, CNCF 샌드박스 단계에 있다.
분산시스템의 정의는, 엄밀히 말하면, 단일 서버에서만 동작하지 않는 모든 시스템이다. 이 정의는 수십 년 전부터 그대로지만, 달라진 건 규모와 동적성이다.
물리 서버 몇 대가 수백 개의 VM이 됐고, VM은 다시 수천 개의 쿠버네티스 파드와 서버리스 함수로 쪼개졌다. 배포 주기는 분기에서 주, 주에서 하루, 이제는 분 단위 자동화로 단축됐다. 컴포넌트들은 퍼블릭 클라우드, 프라이빗 클라우드, 온프레미스에 걸쳐 퍼졌다. 규모가 커질수록, 속도가 빨라질수록, 분산이 넓어질수록 — 전통적인 방식으로 이 시스템을 관리하는 건 더 이상 현실적이지 않다.
분산 시스템을 책임지는 엔지니어라면 항상 다섯 가지 질문에 답할 수 있어야 하며, 시스템의 Observability를 잘 설정함으로써 모두 답할 수 있게 된다.:
분산 시스템에서 인프라는 대부분 공유된다. 같은 쿠버네티스 노드의 파드들은 CPU·메모리를 공유하고, 같은 물리 서버의 VM들은 디스크 I/O를 공유한다.
Noisy Neighbor 문제: resource limits 설정 없이 배포된 파드 하나가 CPU·메모리·네트워크·디스크를 과도하게 점유해 같은 노드의 다른 파드들을 느리게 만들거나 크래시시키는 상황. 모니터링 포인트: 특정 프로세스가 이웃 대비 10배 이상 자원을 지속적으로 사용하면 자동 알림.
Right-sizing: 반대로 지속적인 저사용률은 인프라 다운사이징의 신호다. FinOps 팀이 Observability 데이터를 활용해 자원 낭비를 줄이는 게 현대적인 접근이다.
분산시스템에서 Trace 수집을 통해, 엔드유저(브라우저, 모바일)부터 미들웨어, 마이크로서비스, 백엔드 DB까지 트랜잭션 전체를 따라갈 수 있다. HTTP든 메시지 큐든, trace context를 caller에서 callee로 전파하는 방식으로 동작한다.
하지만 트레이스만으로는 통신 문제를 완전히 파악하기 어려운 경우가 있다. 트레이스에는 caller의 발신 타임스탬프와 callee의 수신 타임스탬프가 찍히는데, 그 차이가 어떤 트레이스에서는 10ms, 다른 트레이스에서는 10초라면? 아예 타임아웃이 찍혀서 요청이 callee에 도달하지 못한 경우라면? 트레이스는 이 질문에 답하지 못한다.
이를 정확히 파악하기 위해서는 trace 외에 추가로, 동기·비동기 통신을 가능하게 하는 중간 레이어들 — 네트워크, 커넥션 풀, 큐 — 을 함께 관찰해야 한다.
"서버 몇 대, 예측 가능한 트래픽. CPU 90% 넘으면 알림" - Static thresholds은 정적 인프라 환경에서는 잘 작동했다. 하지만 2026년은 다르다. 파드가 수백 개이고, KEDA나 Karpenter가 실시간으로 스케일링한다. 여기에 Static thresholds을 그대로 적용하면 수만개의 불필요한 threasholds를 설정해야 한다.
KEDA나 Karpenter처럼 동적 스케일링이 작동하는 환경에서는 "정상이 무엇인지"가 실시간으로 바뀐다. 정적 임계값을 걸어봤자 의미가 없어 시스템이 스스로 정상 범위를 학습하게 해야 한다. 베이스라인을 정하는 방식은 크게 3가지이다.
그렇다고, Static Threshold가 불필요한 것은 아니다. 여전히 API rate limit, SLA/SLO, worker thread 같은 well-defined, easily predictable한 수치의 경우 유효하게 동작할 수 있다.
CPU, 메모리, 디스크, 네트워크는 여전히 중요한 알림 지표이다. Google SRE 핸드북의 4 golden signals(latency, traffic, errors, saturation)도 마찬가지다. SRE와 ITOps 팀은 이 지표들을 기반으로 VM 크기를 조정하고, 행업된 프로세스를 재시작하고, 로드밸런서 뒤에 트래픽을 분산시켜왔다.
그런데 Kubernetes가 이 작업들을 상당 부분 자동화했다. 자동화가 일어난 곳에서는 알림의 초점도 달라져야 한다.
자동화가 레이어마다 깊어질수록, 우리가 직접 반응해야 하는 지점도 달라진다. 클라우드 네이티브 스택의 각 레이어에 맞는 새로운 golden signals를 정의할 필요가 있으며 다음과 같다.
데이터가 많다고 좋은 게 아니다. AI가 제대로 동작하려면 고품질이어야 하고, 컨텍스트가 풍부해야 한다. Garbage in, garbage out — 옵저버빌리티도 예외가 아니며, 이런 데이터를 생성하려면 어떻게 해야할까?
- Pets: 개별적으로 애정을 가지고 관리하는 대상
- Cattle: 표준화되어 대체 가능한 대상
예전엔 서버에 Joe, Sally, Hugo 같은 이름을 붙이고 각자 대시보드를 만들었다. Kubernetes 파드는 다르다. my-critical-svc라는 워크로드를 만들면 파드 이름은 my-critical-svc-1694, my-critical-svc-4352처럼 재시작할 때마다 바뀐다. 개별 엔티티를 추적하는 게 불가능하다.
이제 대시보드는 이름이 아닌 메타데이터로 필터링해야 한다. 그러려면 조직 전체가 합의한 표준화된 시맨틱 규약이 필요하다. 규약이 없으면 스케일이 불가능하다.
로그 한 줄에 API 호출 정보만 있어선 안 된다. 파드, 워크로드, 네임스페이스, 노드, 클라우드 리전까지 함께 있어야 한다. 그래야 이런 질문에 답할 수 있다: "이 에러가 특정 리전에서만 발생하는가?", "특정 Kubernetes 버전에서만 생기는가?", "특정 배포 설정과 연관이 있는가?" 아래 방법으로, observability data를 풍부하게 만들 수 있다.
인프라 태그: Terraform, Ansible 같은 IaC로 VM을 생성할 때 붙이는 태그(Environment, Owner, CostCenter 등)를 수집되는 모든 신호에 동일하게 enriching한다. 태그 하나가 여러 가지를 동시에 해결한다. Owner:SalesUSEast 태그가 붙은 로그는 해당 팀만 볼 수 있도록 접근 제어를 걸 수 있고, Environment:Dev 태그가 붙은 트레이스는 2스프린트 후 자동 삭제해 스토리지 비용을 줄일 수 있다.
배포 레이블·어노테이션: Kubernetes Deployment에 버전, 환경, 오너십 정보를 명시하면 해당 파드에서 수집되는 모든 신호에 자동으로 붙는다. 이를 통해, 버전별 응답시간·에러율 비교, 신버전이 구버전보다 실패율이 높으면 자동 알림, preproduction과 production 동작 비교 후 프로모션 결정 등이 가능해진다.
Jira, GitHub, GitLab, Argo CD, Jenkins 같은 DevOps 도구에서 이벤트를 수집해 옵저버빌리티 백엔드에 연결하면 세 가지가 가능해진다.
"왜 Jira가 느리지?", "왜 빌드 파이프라인이 안 돌지?" — 이 문제들은 대개 사람들이 불평하기 시작하고 나서야 발견된다. 원인은 단순한 경우가 많다. Jenkins 파이프라인이 공유 인프라 문제로 느려졌거나, 잘못 설정된 MCP 서버가 GitHub API를 과도하게 호출해 rate limit에 걸렸거나. 하지만 자동으로 감지되지 않으니 피해가 커진 후에야 인지한다.
Jira, GitHub, Argo, Harbor 같은 도구에도 동일한 옵저버빌리티와 알림을 설정해야 한다. OpenTelemetry의 확산으로 이런 도구들도 점점 OTel을 지원하고 있다. 엔지니어를 지원하는 도구가 멈추는 건, 비즈니스 서비스가 멈추는 것만큼 치명적이다.
데이터는 생성되는 곳과 최대한 가깝게 enriching하는 게 가장 효율적이다. 벤더 에이전트는 수집 시점에 자동으로 enriching하고, OTel Collector는 processor를 통해 파이프라인에서 규칙 기반으로 enriching한다.
그렇다고 모든 데이터를 다 저장할 필요는 없다. 트랜잭션의 99.9%가 성공한다면, 그 99.9%를 전부 상세 저장하는 건 낭비다. 샘플링 전략 세 가지:
샘플링 결정 시점도 중요하다. Head-based는 트레이스 시작 시점에 결정해 가볍지만, 결과를 모르는 상태에서 결정한다. Tail-based는 모든 span이 수집된 후 결정해 정확하지만 메모리를 많이 쓴다. 일반적으로 head-based로 시작하고, 크리티컬 트랜잭션이나 규제·컴플라이언스 요건이 있는 케이스에만 tail-based를 조합하는 게 실용적이다.
다른 작업을 하고 있는데 Slack으로 이런 메시지가 온다:
"Argo CD sync(PR-342)가 payment 서비스의 실패율을 높이고 있습니다. frontend 서비스에서
java.lang.abcdException이 발생해 HTTP 500 에러가 사용자에게 전달되고 있습니다. PR을 롤백하는 것을 권장합니다."
공상과학처럼 들리지만 지금 이미 가능하다. context-enriched observability 데이터, 자동 베이스라인과 ML, 그리고 LLM의 조합이다. 이게 어떻게 동작하는지 분해해보자.
출발점은 모든 레이어에서 이상 동작을 감지하는 것이다. 임계값이나 베이스라인이 깨지는 순간, 특정 컴포넌트에서 이상 이벤트가 발생했다고 볼 수 있다.
예를 들어 유저 로그인 API가 평소보다 느려졌다고 하자. 이 API는 Kubernetes 클러스터에서 실행 중이고, 큐와 DB에 의존한다. 헬스 히트맵으로 시각화하면 패턴이 보인다 — DB 쿼리 시간이 느려지고 1분 후 business API가 degraded 상태가 되고, 그 후 application 레이어까지 실패한다. 인간의 눈으로도 패턴을 읽을 수 있다.
하지만 이상탐지만으로는 부족하다. 이 단순한 예시에도 이미 놓친 게 많다.
이상 탐지만으로는 추측밖에 할 수 없다. 의존성, 공유 자원, 외부 이벤트까지 포함한 context-enriched 데이터가 있어야 진짜 원인을 찾을 수 있다.
컨텍스트가 갖춰지면 의존성 모델을 따라 네 가지 방향으로 원인을 추적한다.
네 가지를 모두 연결하면 비로소 진짜 root cause에 도달한다 — "배치 잡이 DB를 과부하시켜 business API가 느려지고, 엔드유저에게 영향이 갔다."
root cause를 찾았다고 끝이 아니다. 의존성 다이어그램을 그릴 수 있는 전문가만 이해한다면 의미가 없다.
Step 2의 모든 과정은 자동화할 수 있다. 많은 옵저버빌리티 플랫폼이 이미 메타데이터를 기반으로 데이터를 연결하고, 의존성 트리를 따라 자동으로 원인을 추적한다. 속도는 데이터 품질과 저장 구조에 달려 있다. 품질이 좋을수록 빠르고 정확하다.
마지막 단계는 LLM이다. 수집된 증거 — 이상 목록, 의존성 정보, 관련 외부 이벤트 — 를 LLM에 넣으면 세 가지를 인간이 이해할 수 있는 언어로 돌려준다:
데이터 품질이 좋을수록, 의존성 정보가 풍부할수록, 설명도 더 정확해진다. Context is king이 단순한 구호가 아닌 이유가 여기에 있다.