
나는 일부러 내 결제 서비스를 망가뜨린 후, AI에게 이를 고발하라고 요청했다
요약
의도적으로 결제 시스템 장애를 발생시킨 후, AI 에이전트가 OpenTelemetry 데이터를 활용해 장애 원인을 얼마나 정확하고 빠르게 분석하는지 테스트한 실험 사례입니다. 에이전트가 로그와 트레이스를 분석하여 수동 대응보다 빠르게 문제 지점을 찾아내는 과정을 다룹니다.
핵심 포인트
- AI 에이전트를 활용한 프로덕션 장애 대응 자동화 가능성 확인
- OpenTelemetry와 SigNoz를 이용한 관측성(Observability) 데이터 구축
- 에이전트가 서비스 간 트레이스를 분석하여 장애 지점을 정확히 식별
- 엔지니어의 수동 로그 분석 시간을 단축하는 에이전트의 성능
음, 저는 모든 개발자가 커리어 중 적어도 한 번은 겪게 되는 전형적인 새벽 2시의 상황을 재구상해보고 싶었습니다. 엔지니어들을 때때로 떨게 만들었던 프로덕션 다운타임(production downtime) 말이죠. 대부분의 엔지니어는 잠결에 대시보드를 멍하니 바라보며 무엇이 잘못되었는지 궁금해하며 강제로 깨어있어야 했습니다. 이것이 오보가 아니라는 것을 깨달은 후에는 로그를 살펴보고, 배포(deployment)가 이루어졌는지 확인하는 등의 기본적인 체크리스트(보통 프로젝트에서 장애 발생 시 따르는 체크리스트)를 따르며 상황에 맞서곤 했습니다. 오늘날은 어떨까요? AI 덕분에(?) 실패 원인에 대해 여전히 갈피를 잡지 못하는 엔지니어가 부서진 프로덕션 환경을 AI 에이전트(AI agent)에게 던지며 속으로 간절히 빌고 있는 모습에 더 가깝습니다. "제발 이것 좀 고쳐줘, 실수하지 말고."라고 말이죠. 음, 우리는 공식적으로 알고리즘에 아무런 맥락(context) 없는 혼돈을 넘겨주는 시대에 살고 있으므로, 알림이 울리자마자 에이전트가 분석을 수행하여 실제 새벽 2시에 깨어날 필요가 없는, 그 실체가 과연 기대만큼인지 확인해보고 싶었습니다. 그래서 저는 일부러 제 결제 프로세서(payment processor)를 망가뜨렸고, 세 개의 서비스가 도미노처럼 쓰러지는 것을 지켜보았습니다. 그리고 평소 하던 대로 제가 만든 에이전트에게 왜 그런 일이 일어났는지 말해달라고 요청했습니다. 제가 로그를 다 열기도 전에, 에이전트는 이미 발생했을 일련의 모든 동작을 제공했습니다. 에이전트는 정확한 서비스(service)를 지목하고, 정확한 트레이스(trace)를 제공했으며, 제가 수동으로 매핑하는 것보다 더 빠르게 수행했습니다. 이것을 어떻게 해냈는지 살펴봅시다.
이 시나리오를 시뮬레이션하기 위해 구축한 것
제 에이전트 기술을 테스트하기 위해 의도적으로 프로덕션 애플리케이션(production application)을 망가뜨릴 수는 없기 때문에 (제목이 다르게 말하고 있다는 건 알지만, 어쩔 수 없으니까요 :)) 실제 프로덕션에서 작동하는 방식과 유사하게 서로 통신하는 세 개의 서비스를 만들었습니다. 이 세 서비스는 다음과 같습니다:
-
api-gateway (*:8000): 공용 프론트 도어(front door)이자 카나리 라우터(canary router)입니다. 스트랭글러 피그 패턴 (strangler fig pattern)에 따라 트래픽의 80%는 안정적인 orders-service v1으로, 20%는 v2로 라우팅합니다.
-
orders-service (*:8001 v1 / :8002 v2): SQLite에 주문을 기록한 다음, 카드를 결제하기 위해 payments 서비스를 동기적 (synchronously)으로 호출합니다. 만약 payments가 느려지면, 그 뒤에 있는 모든 것이 대기하게 됩니다.
-
payments-service (*:8003): 가짜 제3자 결제 프로세서 (third-party payment processor)이며, 특정 돌발 상황을 만들기 위해 제가 직접 만든 비밀 제어 엔드포인트 (control endpoint)를 가지고 있습니다.
세 서비스 모두 트레이스 (traces) (서비스 사이를 오가는 하나의 요청에 대한 시간 기록이 포함된 중첩된 기록), 메트릭 (metrics), 로그 (logs)를 방출하기 위한 오픈 표준인 OpenTelemetry로 연결되어 있습니다. 저는 코드 변경 없이 각 서비스를 opentelemetry-instrument로 감싸서(wrap), 셀프 호스팅되는 SigNoz 인스턴스로 전송하도록 설정했습니다.
SigNoz를 구축하는 것은 정말 간단한 일이었습니다. 보통은 깨진 Docker 설정과 누락된 의존성(dependencies)의 늪에서 시간의 절반을 허비하곤 하지만, 이번에는 달랐습니다. 20분 이내에 깨끗한 오픈 소스 텔레메트리 파이프라인 (telemetry pipeline)을 준비할 수 있었습니다.
curl -fsSL https://signoz.io/foundry.sh | bash
...
덕분에 5분도 채 되지 않아 localhost:8080에 UI를 설정하고, 4317-4318 포트에 텔레메트리 수집 (ingestion)을 설정할 수 있었습니다.
그다음 부하(load) 발생 시 통상적으로 유입되는 트래픽을 시뮬레이션하기 위해, k6를 사용하여 11분 동안 가상 사용자(virtual users)를 1명에서 15명으로 점진적으로 늘려 실제 아침 트래픽 곡선을 모방했습니다.
- 5,814개 요청, 245개 실패 (4.21%)
- http_req_duration: 평균 418ms, 중앙값 103ms, p90 651ms
- p95: 3.26초
저 p95 수치가 전체 상황을 한 줄로 요약해 줍니다. 이는 요청 중 일부가 매우 좋지 않은 상태였음을 의미하며, 실제 상황이라면 사용자에게 영향을 미쳤을 것입니다.
범죄
부하 테스트를 실행한 후, 3분째에 저는 의도적으로 payments 제어 엔드포인트의 성능을 저하시켰습니다. 요청당 2~4.5초의 지연을 도입하고, 호출의 40%를 HTTP 503 오류로 드랍(drop)시켰습니다.
이것은 실제 환경에서 발생하는 상황, 즉 제3자 제공업체(third party provider)나 동일 조직 내의 다른 팀이 자신들의 서비스 중 하나에 업그레이드를 배포할 때 어떤 일이 일어나는지를 시뮬레이션하기 위해 수행되었습니다. 그들의 테스트 케이스에서는 잘 작동했지만 (그들의 로컬 환경에서는 잘 돌아가니까요 :)), 실제로 그 서비스가 시작되면 우리 메인 애플리케이션 전체에 걸쳐 연속적으로 대규모 성능 저하를 유발합니다. 시스템이 완전히 죽은 것은 아니지만, 갑자기 절뚝거리며 신뢰할 수 없는 상태가 되며, 이는 영향 범위(blast radius)가 이미 퍼질 때까지 표준 업타임 체크(uptime checks)가 완전히 놓치게 되는 방식입니다.
현재 우리의 아키텍처가 api-gateway → orders-service → payments-service와 같이 모두 동기식 호출 체인(synchronous call chain)으로 구성되어 있기 때문에, 고통은 곧바로 상위로 전달되었습니다. 세 서비스 모두의 에러율과 p99 지연 시간(latency)이 정확히 동일한 5초 구간(buckets)에서 급증했는데, 이는 세 서비스가 발맞추어 실패하는 것이 세 개의 문제가 아니라, 세 개의 가면을 쓰고 있는 하나의 문제임을 말해줍니다.
대시보드를 통해 확인한 결과, 엔드 투 엔드(end to end)를 보여주는 traceId인 trace 0050c21ff1f619a14f9bbbb7f7a5a182를 찾아냈습니다. 11개의 스팬(span) 중 8개가 에러가 발생했습니다. **스팬 (span)**은 요청 내에서 시간이 측정되는 하나의 작업 단위입니다. :

저 리프 스팬(leaf span, 마지막 스팬)이 많은 것을 말해줍니다. 결제 POST /charge는 실제로 다른 어떤 서비스에도 의존하지 않습니다. 이는 이 전체 여정이 호출하는 마지막 API이며, 단지 2.73초 동안 머물다가 실패할 뿐입니다. 각 스팬의 지속 시간은 부모 스팬의 지속 시간과 40ms 이내로 차이가 나는데, 이는 이것이 세 개의 독립적인 지연이 아니라 차단형 캐스케이드(blocking cascade)라는 증거입니다. 각 계층은 바로 아래 계층이 완료되기를 기다린 다음, 위로 올라가는 과정에서 실패를 다시 던집니다 (503 → 502 → 502). 제정신인 사람이라면 이를 파악하는 데 이상적으로 약 20~30분이 걸리겠지만, 만약 이것이 실제로 새벽 2시에 발생했다면 상황은 빠르게 악화되었을 것입니다. 바로 이 지점이 제가 항상 제 역할을 대신해 줄 자동화된 동료를 원했던 부분입니다. 제가 잠에서 깨어나 정신을 차릴 때까지 이 로그들을 확인하고 분석 결과를 가져다주는 동료 말이죠. 만약 이런 것이 가능하다면, 수많은 개발자에게 큰 도움이 될 것입니다.
AI가 동일한 결론에 도달할 수 있을까?
본론으로 들어가기 전에, SigNoz의 클라우드 제품은 평이한 영어로 인시던트(incident)를 조사하는 Noz라는 AI 팀원을 제공합니다. 하지만 저는 SigNoz를 로컬에 호스팅했기 때문에, 클라우드 전용 기능인 이 서비스는 사용할 수 없었습니다. 대신 제가 사용할 수 있었던 것은 SigNoz가 MCP를 통해 노출한 트레이스(traces), 로그(logs), 메트릭(metrics), 알림(alerts), 대시보드(dashboards)를 아우르는 40여 개의 도구 세트였습니다. (MCP는 AI 에이전트에게 호출 가능한 도구 상자를 전달하는 표준화된 방식입니다.) 에이전트의 컨텍스트 윈도우(context window)를 (코드 파일을 주고 로그를 가리키는 방식으로) 불필린 채로 "_제발 이것을 고쳐줘, 실수하지 말고"라고 말하는 대신, 저는 제 서비스의 그래프와 SigNoz의 도구들이 연결된 일반적인 AI 에이전트를 구성했습니다.
"내 api-gateway 서비스가 지난 15분 동안 지연 시간 및 에러 문제를 겪고 있어. api-gateway, orders-service, payments-service의 트레이스, 에러, 주요 작업(top operations)을 확인하여 무엇이 실제로 잘못되었는지 조사해줘. 적절한 도구를 사용하여 이 결론에 도달해줘."
두 번의 턴(turn)에 걸쳐 7번의 MCP 도구 호출이 이루어진 후, 에이전트는 거의 원문 그대로의 내용으로 다음과 같이 답변했습니다:
"근본 원인(Root cause): payments-service가 장애 지점이며, 나머지는 모두 증상입니다. payments-service의 POST /charge가 HTTP 503 오류와 함께 실패하고 있으며, 실패하는 데 2.6 - 4.5초가 소요됩니다 (정상적인 p50 수치는 약 ~90ms). 세 서비스 모두 동일한 5초 구간(buckets) 내에서 동시에 급증(spike)했습니다. 이는 세 가지 독립적인 문제가 아니라, 하나의 상위(upstream) 장애가 호출 체인(call chain)을 통해 연쇄적으로 발생(cascading)하고 있음을 의미합니다."
이것은 저 역시 20분 정도의 차이로 도달했던 결론이었습니다. 정확한 근본 원인을 좁히기 위해 저는 다음과 같이 질문했습니다: "이것이 payments-service로부터 시작된 연쇄 장애(cascading failure)인가요? 구체적인 트레이스(trace)를 보여주세요." 에이전트는 요청하지 않았음에도 위에서 언급한 정확한 트레이스 ID를 가져왔고, 스팬 트리(span tree)를 단계별로 따라가며 "각 홉(hop)은 독자적으로 느린 작업을 수행하는 것이 아니라, 바로 아래 단계의 작업이 완료되기를 기다리며 블로킹(blocking)되고 있을 뿐이다"라는 결론에 도달했습니다. 이는 제가 20분 전에 내린 결론과 정확히 일치했습니다.
여기서 이 사실을 다시 한번 강조하고 싶습니다. 우리는 코드의 graphify 버전과 SigNoz에서 제공하는 MCP 도구만을 사용하여 이 AI 에이전트를 만들었습니다. 에이전트의 도구 호출 로그를 보면 SigNoz MCP 서버에 대한 7번의 호출이 기록되어 있을 뿐, 단 하나의 파일 읽기(file read)도 없었습니다. 에이전트는 제가 지뢰처럼 심어둔 main.py의 예외(exception)를 읽어서 결론을 내린 것이 아니라, 순수하게 도구들이 제공하는 텔레메트리(telemetrics)의 도움을 받아 이 결론에 도달한 것입니다.
그 추론 과정은 정말 볼만했습니다. 트레이스(traces), 메트릭(metrics), 로그(logs)가 이미 하나의 쿼리 가능한 OpenTelemetry 네이티브 저장소에 존재했기 때문에, 에이전트는 제가 후속 질문을 타이핑하는 동안 세 서비스에 걸친 작업, 에러율, 트레이스 타이밍을 교차 참조하며 책임을 지고 분석을 수행했습니다. 이상적으로는 모델의 지능 덕분이겠지만, 격언에도 있듯이 아무리 지능적인 모델이라도 잘못되거나 틀린 데이터가 입력된다면, 양질의 데이터를 가진 상대적으로 추론 능력이 낮은 모델만큼의 추론을 해낼 수 없을 것입니다.
같은 세션에서 에이전트는 제가 심어둔 두 번째 버그도 포착했습니다. v2 카나리 환경의 GET /orders/{order_id}/receipt 호출 중 5%가 처리되지 않은 RuntimeError를 조용히 발생시키고 있었습니다. 간단한 상태 검사(health check)로는 절대 잡을 수 없었고, 요청의 95%는 여전히 성공했으며 대시보드는 녹색으로 유지되었습니다. 단 하나의 Query Builder 필터 서비스명 = 'orders-service' AND name = 'GET /orders/{order_id}/receipt' AND has_error = true를 통해 모든 발생 사례가 드러났고, 전체 스택 트레이스(full stack trace)까지 첨부되었으며, 제가 작성한 try/except 구문은 단 하나도 없었습니다.

모든 것이 순조롭게 진행되지는 않는다 (이것이 삶이나 새로운 스택 온보딩의 현실이다)
- 문서를 읽고, 에이전트 코드를 작성하고, 모든 도구들을 연결하는 과정에서 첫 MCP 호출이 평평한 403 응답을 반환했습니다. 이유는 역할(role)이 할당되지 않은 서비스 계정 때문이었는데, 단순히 signoz-admin 역할을 할당하고 전체 세션을 재시작해야 했습니다. 왜냐하면 mcp 도구들은 에이전트가 세션을 시작할 때만 로드되기 때문이었고, 짜잔! 문제가 해결되었습니다. 이 기쁨은 아기가 가장 좋아하는 장난감을 얻었을 때와 비슷했습니다.
핵심 시사점 (The Takeaway)
AI는 엔지니어들이 가진 경험을 대체하지 못할 것입니다. 하지만 한 가지에 대해서는 맞습니다. 바로 인간이 보기보다 트레이스 그래프(trace graph)를 더 빠르게 읽을 수 있다는 점입니다.
여기서 진짜 반전은 LLM이 인간보다 우월한 추론 능력을 가졌다는 것이 아닙니다 (우리가 AGI 또는 ASI를 갖기 전까지는). 그 추론 능력은 이상적으로 인간의 지성에서 파생됩니다. 중요한 것은 AI가 얼마나 유용한지는 여러분이 공급하는 원시 데이터(raw data) 기반의 텔레메트리(telemetry) 인프라에 달려 있다는 것입니다. 'AI 팀원'이라는 홍보 문구는, 일반적인 에이전트가 어떤 힌트도 없이 원시 데이터를 가지고 완벽한 장애 보고서(incident report)를 저에게 건네주었을 때 마케팅 용어의 허풍에서 벗어났습니다.
실제로 이 AI 팀원이 왜 작동했는지 분석하고 싶다면, 제가 가설을 세운 세 가지가 있습니다:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기