서비스가 왜 고장 났는지 이미 알고 있습니다. 배포 시점에 그 지식을 삭제하세요.
요약
배포 과정에서 소스 코드에 명시된 시스템 구조 정보가 유실되어 장애 대응 시 모델이 이를 추측해야 하는 문제를 지적합니다. 이를 해결하기 위해 애플리케이션이 스스로의 구조를 이해하고 추론할 수 있도록 돕는 '인지 자율 프레임워크(Cognitive Autonomic Framework)'를 제안합니다.
핵심 포인트
- 기존 오토스케일링은 리소스 중심이라 애플리케이션의 논리적 장애를 구분하지 못함
- 로그 기반의 추론은 비용이 높고, 중앙 집중화되어 있으며, 아키텍처를 환각할 위험이 있음
- 배포 시점에 코드에 존재하는 시스템 지식을 삭제하지 않고 활용해야 함
- 애플리케이션이 스스로에 대해 추론할 수 있는 인지 자율 프레임워크의 필요성
우리 대부분이 경험했을 순간으로 시작하고 싶습니다.
새벽 3시입니다. 대시보드가 빨간색을 띠고 있습니다. 어떤 서비스가 실제로 다운되었고 왜 그런지 알아내기 위해 grep 명령어를 여덟 개의 터미널에 걸쳐 실행하고 있습니다. 그리고 내내, 지난달에 자신이 작성한 시스템에서 고고학을 하는 것 같은 불쾌한 느낌이 듭니다.
저를 괴롭혔던 것은 바로 이것입니다. 답은 사실 사라진 적이 없었습니다. 소스 코드에는 명백하게 쓰여 있었습니다. 결제 서비스가 연결 풀(connection pool)을 통해 Postgres와 통신한다는 내용. 이 재시도(retry)는 세 번까지 지연된다는 내용. 그리고 특정 의존성(dependency)은 외부적이며, 절대로 '그냥 재시작'하려고 해서는 안 된다는 내용이었습니다. 이 모든 것이 빌드 시점에 이미 거기에 있었습니다. 그러고 나서 우리는 모든 것을 패키징하고 배포하여 그 구조를 쓰레기통에 던져버린 다음, 잠 부족으로 지친 사람에게 로그 라인들로부터 그것을 재구성하도록 요청했습니다.
그 간극이 저를 충분히 괴롭혔고, 저는 이와 관련된 무언가를 만드는 데 시간을 보냈습니다. 이 글은 그 내용에 관한 것입니다.
오토스케일링(Autoscaling)은 잘못된 문제 해결에 능합니다
우리는 리소스 압력에 반응하는 것에 실제로 매우 능숙해졌습니다. 트래픽이 증가하면, 서버가 느려지고, CPU 사용량이 높아지면, 오토스케일러가 용량을 추가하거나 부하를 줄입니다. 불만은 없습니다. 수년 동안 시스템을 작동하게 해왔으니까요.
문제는 그것이 여러분의 앱이 '무엇'을 위한 것인지 전혀 모른다는 것입니다. 건강하지만 서비스로부터 과부하가 걸려 느린 서비스를, 데이터베이스에 조용히 쓰레기를 쓰는 바람에 빠르고 정상인 서비스와 구분할 수 없습니다. 애초에 애플리케이션 모델 자체가 없었습니다.
그래서 실패의 전체 범주가 그를 그냥 지나쳐 버립니다. 다운스트림(downstream)의 무언가에 의해 연결 풀이 고갈되는 경우. 독성 메시지(poison message)가 재시도 폭풍을 일으키는 경우. 하나의 코드 경로만 깨뜨리고 다른 경로는 완벽하게 정상으로 보이게 만드는 스키마 변경. 오직 CPU와 메모리만을 생각하는 인프라는 이 모든 것에 눈이 멀어 있습니다.
그 이유를 이해합니다. 저 또한 그것이 잘못된 형태라고 생각하며, 세 가지 문제로 계속 되돌아오게 됩니다.
첫째, 재무 검토(finance review)를 통과할 수 없을 정도로 비용이 많이 듭니다. Frontier models(프런티어 모델)는 토큰당 비용을 청구하고, 텔레메트리(telemetry) 데이터는 방대하며, 당신은 이 모든 것을 스택에서 가장 비싼 요소로 밀어 넣으려 하고 있습니다.
둘째, 중앙 집중화되어 있습니다. 즉, 스스로를 돌봐줘야 하는 단일 두뇌를 구축한 셈이며, 이 두뇌는 정작 자신이 이해해야 할 장애 지점으로부터 아주 멀리 떨어져 있습니다.
셋째, 제가 실제로 가장 좌절감을 느끼는 부분인데, 바로 아키텍처를 환각(hallucinate)한다는 점입니다. 우리는 모델에게 로그 더미를 건네주고, 누가 누구를 호출하는지, 여기서 재시도(retry)가 무엇을 의미하는지, 무엇을 재시작해도 안전한지를 _추론(infer)_하라고 요구합니다. 그 정보는 모호하거나 누락된 것이 아니었습니다. 우리가 배포 시점에 그 정보를 삭제하기 전까지는 코드 안에 정확하고 명확하게 존재했습니다. 그러고 나서 우리는 모델에게 그 정보를 다시 추측하게 하기 위해 비용을 지불하며, 대개 그 결과는 더 나쁩니다.
이로 인해 저는 "어떻게 하면 로그를 더 잘 읽을 수 있을까"라는 질문을 멈추고, 다른 질문을 하기 시작했습니다. "왜 애플리케이션이 스스로에 대해 추론(reason)할 수 없는가?"\n
내가 결국 만든 것
내가 만든 것, 즉 인지 자율 프레임워크(Cognitive Autonomic Framework)는 네 가지 일을 수행합니다. 솔직히 말해서 개별 요소 중 새로운 것은 없습니다. 핵심은 그것들이 어떻게 결합되느냐에 대한 도박입니다.
셀프 모델(self-model)은 코드에서 나옵니다. 빌드 시점에 컴파일러가 AST(Abstract Syntax Tree, 추상 구문 트리)를 탐색하여 제가 런타임 시맨틱 토폴로지(Runtime Semantic Topology, RST)라고 부르는 것을 추출합니다. 이것은 작고 조밀한 그래프입니다. 누가 누구에게 의존하는지, 장애 도메인(failure domains), 재시도 정책(retry policies), 지연 시간 예산(latency budgets), 그리고 에이전트가 각 노드에서 시도할 수 있도록 허용된 수리 작업의 폐쇄 목록(closed list)을 포함합니다. 전체 마이크로서비스 그래프가 몇 킬로바이트(KB) 내에 들어오므로, 컨테이너 내부에서 함께 이동합니다. 무언가 고장 나더라도, 시스템의 형태를 추측할 필요가 없습니다. 그냥 읽으면 됩니다.
그 그래프의 노드는 대략 다음과 같습니다:
{
"service": "payment",
"depends_on": ["postgres", "stripe"],
...
제가 중요하게 생각하는 부분은 permitted_repairs와 이것이 폐쇄된 목록 (closed list)이라는 사실입니다. 에이전트는 풀 (pool)을 재시작할 수 있습니다. 하지만 stripe를 재시작하는 것은 허용되지 않는데, 이는 모델이 그것을 외부 의존성 (external dependency)이라고 단호하게 말하기 때문입니다. 안전성은 모델이 마침 기분이 좋았는지 여부가 아니라, 구조 (structure) 안에 존재합니다.
추론은 장애 근처에 머뭅니다. 모든 서비스는 작은 로컬 에이전트 (local agent)를 가지며, 이들은 세 가지 계층 (tier)으로 나뉩니다:
계층 0 반사 (reflex) 서킷 브레이커 (circuit breakers), 타임아웃 (timeouts) ~ms 무료
계층 1 노드 로컬 (node-local) 증거 읽기 + 셀프 모델 (self-model) ~100ms 저렴
계층 2 글로벌 (global) 프런티어 모델 (frontier model), 측면 배치 드묾 비쌈
대부분의 장애는 지루하고 신뢰할 수 있는 기계 장치가 처리하는 계층 0을 벗어나지 않습니다. 계층 1은 로컬 증거를 읽고, 셀프 모델을 확인하며, 제한된 범위 내의 수정 (bounded fix)을 시도합니다. 계층 2의 크고 비싼 모델은 정말로 심각한 상황에서만 호출되며, 그 경우에도 크리티컬 패스 (critical path) 상에 위치하는 것이 아니라 그 옆에 배치됩니다.
노드는 하트비트 (heartbeat)가 아니라 믿음 (beliefs)을 속삭입니다 (gossip). 보통의 가십 (gossip)은 상태 정보와 카운터입니다. 여기에서 노드들은 추측 (hunches)을 속삭입니다: "결제 풀 (billing pool)이 포화 상태인 것 같습니다. 신뢰도 0.9, 여기 제 증거입니다." 만약 이웃 노드들이 독립적으로 동일한 결론에 도달한다면, 신뢰도는 상승하며 이는 시스템적 결함 (systemic fault)이 됩니다. 만약 아무도 그것을 보지 못한다면, 그것은 고립된 문제이며 노드가 로컬에서 스스로 치유할 수 있습니다. 중앙 조정자 (central coordinator)가 결정을 내리지 않고도 "나의 문제"와 "모두의 문제"를 구분해내는 것이 바로 유용한 기술임이 드러납니다.
자율성은 의도적으로 울타리가 쳐져 있습니다. 이 부분은 제가 그냥 넘기지 않을 대목입니다. 에이전트는 결코 임의의 명령을 실행할 수 없습니다. 에이전트는 해당 노드에 대해 모델이 선언한 폐쇄된 집합 (closed set) 중에서 선택하며, 제안된 모든 복구 작업은 프로덕션 (production) 근처에 접근하기 전에 반드시 섀도우 환경 (shadow environment)에서 검증을 통과해야 합니다.
제안됨 (proposes) -> permitted_repairs에 포함되는가? -> 섀도우 체크 통과 여부? -> 프로덕션 배포 (ships to prod)
| 아니오 | 아니오
v v
...
모델이 제안하고, 파이프라인이 결정합니다. 저는 안전성(safety)이 모델이 제대로 맞히기를 바라는 대상이 아니라, 배관(plumbing) 자체의 속성이 되기를 원했습니다.
제가 실제로 증명할 수 있는 것
이것은 다이어그램이 아니라 실제로 실행 중인 구현체입니다. 각각 별도의 컨테이너에 담긴 6개의 실제 서비스, 실제 TCP를 통해 신념(beliefs)을 주고받는 에이전트들, 그리고 기본적으로는 결정론적(deterministic)이지만 원한다면 호스팅된 모델로 교체 가능한 진단 추론기(diagnostic reasoner)로 구성되어 있습니다. 이는 공개되어 있으며, 논문에 기재된 모든 수치는 해당 실행 시스템에서 도출되었습니다. 그 어떤 것도 시뮬레이션된 것이 아닙니다.
결과가 보여준 것:
- 추론기에게 자기 모델(self-model)을 제공했을 때, 실제 근본 원인(root cause)을 찾아내는 빈도가 대략 두 배로 증가했습니다.
- 이는 모델의 크기가 아니라 구조에서 기인한 결과였습니다.
gpt-4o-mini와gpt-4o는 동일한 점수를 기록했습니다. - 안전 경계(safety boundary)는 모델이 확신을 가지고 잘못된 것을 지목하는 경우를 포함하여, 허용되지 않은 모든 수리 시도를 차단했습니다.
- 노드당 오버헤드(overhead)는 작게 유지되었습니다.
그리고 제가 주장하지 않는 부분은, 이 기술을 과장하기 쉽기 때문에 명확히 밝힙니다. 저는 이것이 대규모 플릿(fleet) 규모에서, 광범위한 결함 유형에 걸쳐, 장기간 배포되었을 때도 유지된다는 것을 보여주지는 않았습니다. 대부분의 장애가 저렴하고 로컬하게 처리된다는 경제성 측면의 논리는 제가 아직 측정 중인 단계이며, 아직 흔들어 보일 수 있는 결과는 아닙니다. 논문의 한계(limitations) 섹션은 대충 훑어보는 것이 아니라 정독하도록 작성되었습니다.
DevOps를 넘어 이것이 중요한 이유
제가 실제로 관심을 두는 프레임워크는 "운영을 위한 AI (AI for ops)"가 아닙니다. 그것은 자기 자신에 대한 명시적인 모델을 보유하고 그 모델을 바탕으로 추론하는 소프트웨어입니다. 신뢰성(reliability)은 단지 이것이 명백하게 유용하게 쓰일 수 있는 첫 번째 분야일 뿐입니다. 동일한 구조(fabric)를 통해 적응형 라우팅(adaptive routing), 침입 탐지(intrusion detection), 또는 변화에 따라 자신의 모델을 스스로 재작성하는 서비스를 똑같이 구현할 수 있습니다.
이 모든 것은 하나의 고집스러운 아이디어로 귀결됩니다. 애플리케이션은 무언가 잘못될 때마다 처음부터 상황을 다시 재구성해야 하는 외부 관찰자에게 그 역할을 떠넘기는 대신, 자기 자신에 대한 모델을 직접 보유하고 그 모델을 바탕으로 추론해야 한다는 것입니다.
이 내용이 여러분에게 와닿거나, 혹은 어느 지점에서 논리가 무너지는지 정확히 파악할 수 있다면, 저는 진심으로 여러분의 의견을 듣고 싶습니다.
듣기: https://notebooklm.google.com/notebook/4779c275-9060-44bb-b0a9-bd2eb953592f?authuser=6
논문 (Paper): zenodo.org/records/21352597 (DOI 10.5281/zenodo.21352597)
코드 (Code): github.com/tflux2011/caf-prototype (DOI 10.5281/zenodo.21363579에 아카이브됨)
저는 텍사스에서 활동하는 독립 연구자 Tobi Adeosun입니다. me@tadeosun.com으로 연락하실 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기