Rain Lag

골판지 사고 스토리 메트로 맵: 작은 실패가 현대 스택 전체로 번져가는 경로를 손으로 따라가 보기

“메트로 맵” 방식으로 시스템을 바라보면, 지저분한 장애가 추적 가능한 경로로 보이고, 숨은 의존성이 드러나며, 작은 결함이 대형 장애로 번지는 걸 막을 수 있다.

서론: 골판지 사고(The Cardboard Incident)

어떤 엔지니어링 팀이든 하나쯤은 “골판지 사고(cardboard incident)” 같은 이야기가 있다.

잊혀진 기능 플래그 하나가 프로덕션 전체를 멈춰 세웠던 때일 수도 있다. 아니면 사이드카 컨테이너의 아주 사소한 설정 오류가 트래픽을 조용히 제한하다가, 결국 핵심 API가 멈춰버렸던 순간일 수도 있다. 겉에서 보면 그저 “한 번의 장애”처럼 보인다. 하지만 내부에서는 이것이 연쇄 반응이다. 수많은 마이크로 수준의 실패가 서비스, 큐, 캐시, 대시보드로 얽힌 미로를 타고 번져간다.

현대 시스템은 각각의 박스가 따로따로 망가지지 않는다. 도시처럼 망가진다. 한 노선이 멈추면 다른 노선이 과부하되고, 승객(요청)이 엉뚱한 곳에 몰린다. 전체 지도가 보이지 않으면, 모든 사고는 늘 수수께끼처럼 느껴진다.

여기서 등장하는 개념이 바로 **사고 스토리 메트로 맵(incident story metro map)**이다. 작은 결함이 스택 전체를 어떻게 통과해 가는지 시각적으로 추적하는 방법이자, 더 탄탄한 시스템을 설계하게 해 주는 강력한 도구다.


현대 시스템은 “목록”이 아니라 “지도”다

모놀리식(Application) 시대에는 가끔 이렇게 선형으로 생각할 수 있었다. 입력이 들어오고, 로직이 실행되고, 출력이 나온다. 하지만 오늘날 “단순해 보이는” 제품조차도 다음과 같은 요소들 위에서 돌아간다.

  • 마이크로서비스와 서버리스 함수
  • 데이터베이스, 캐시, 메시지 큐
  • 서드파티 API와 SaaS 플랫폼
  • 컨테이너, 오케스트레이터, 로드 밸런서
  • 엣지 네트워크와 CDN

이 모든 것은 리스트가 아니라 그래프를 이룬다. 즉, 다음과 같은 의존성의 웹이 만들어진다.

  • 하나의 서비스가 여러 다른 서비스에 동시에 의존한다.
  • 공유 인프라(예: DB 클러스터)는 눈에 잘 안 보이는 단일 장애 지점(SPOF)이 된다.
  • 재시도 폭풍, 타임아웃, 백프레셔가 직관적이지 않은 피드백 루프를 만든다.

무언가가 고장 나면, 그 영향은 직선처럼 퍼져 나가지 않는다. 이 그래프를 라우팅하듯 퍼져 나간다. 의존성, 페일오버 규칙, 타임아웃 설정이 허용하는 어떤 경로든 타고 움직인다.

이 그래프가 어떻게 생겼는지 분명히 보이지 않으면, 작은 문제는 종종 랜덤하고, 간헐적이며, 설명 불가능한 것처럼 보인다. 그리고 그게 이미 대형 장애가 된 뒤에야 비로소 실체가 드러난다.


“메트로 맵” 뷰: 실패 경로를 눈에 보이게 만들기

텍스트 기반 대시보드와 알림은 뭐가 잘못됐는지, 그리고 가끔은 어디서 처음 나타났는지를 알려주는 데 강하다. 하지만 장애가 스택 전체를 어떻게 타고 이동했는지는 잘 보여주지 못한다.

서비스 맵(service map) 또는 **메트로 맵(metro map)**은 시스템을 도시 지하철 노선도처럼 시각화함으로써 이 문제를 해결한다.

  • 역(station) 은 서비스, 컴포넌트, 인프라 요소를 나타낸다.
  • 노선(line) 은 그 사이의 의존 관계와 데이터 흐름을 나타낸다.
  • 존(zone) 은 관련 도메인을 묶는다. 예: 사용자-facing 서비스, 백엔드 API, 데이터 레이어, 외부 벤더.

장애 상황에서는 다음을 하이라이트할 수 있다.

  • 최초 이상 징후가 나타난 지점
  • 그다음 트래픽이 어떤 경로를 탔는지
  • 어느 업스트림·다운스트림 컴포넌트가 함께 저하(degrade)됐는지

수십 개의 분리된 대시보드를 뒤지는 대신, 사실상 노선도 위에 연필로 경로를 그리는 셈이다.

“장애는 Service A의 DB 커넥션 풀에서 시작해, Service B의 API로 전파됐고, 그로 인해 Service C에 부하가 증가하면서, 결국 Service D와 공유하던 메시지 큐가 포화 상태가 됐다.”

이 경로가 눈에 보이는 순간, 사고는 더 이상 랜덤하지 않다. 추적 가능한 스토리가 된다.


토폴로지를 모니터링에 되돌려 먹이기

메트로 맵은 위키 페이지에 예쁘게 붙여 두는 정적인 다이어그램이 아니다. 진짜 힘은 이 데이터가 모니터링·옵저버빌리티 스택과 직접 연결될 때 발휘된다.

의존성과 토폴로지 데이터가 메트릭, 로그, 트레이스와 통합돼 있다면 다음이 가능하다.

  • 맥락 속 영향도 표시: 장애가 난 서비스와 그 의존 관계를 실시간으로 하이라이트한다.
  • 경로 단위 SLA 추적: 서비스 단위 가용성뿐 아니라, 전체 요청 경로의 신뢰도를 측정한다.
  • 임원용 대시보드 제공: “어떤 API들이 좀 느립니다”가 아니라 다음처럼 말할 수 있다.
    • “Service A → B → C 경로를 지나는 체크아웃 플로우가 Vendor X 장애로 EU 고객의 7%에게서 성능 저하를 겪고 있습니다.”
  • 지능형 알림 강화: 단순한 원시 메트릭이 아니라, 가입 플로우, 결제 플로우, 의료 기기 텔레메트리 수집 등 핵심 경로 기준으로 알림을 걸 수 있다.

시간이 지나면 다음과 같은 피드백 루프가 만들어진다.

  1. 시스템 토폴로지를 모델링한다.
  2. 실제 사고가 새로운 실제 경로와 숨은 의존성을 드러낸다.
  3. 토폴로지와 메트로 맵을 업데이트한다.
  4. 모니터링과 대시보드가 더 정확하고 실용적으로 바뀐다.

각 사고는 지도를 더 정교하게 만들고, 더 정교해진 지도는 다음 사고를 더 쉽게 진단하게 해 준다.


작은 실패가 대형 장애로 커지는 방식

의존 관계나 실패 경로에 대한 시야가 없으면, 아주 작은 결함도 순식간에 커질 수 있다.

  • 느린 다운스트림 API가 200ms 정도의 레이턴시를 추가한다.
  • 업스트림 서비스들이 긴 타임아웃을 가진 재시도를 붙인다.
  • 스레드 풀은 꽉 차고, 큐는 길어지고, CPU는 치솟는다.
  • 공유 데이터베이스가 예기치 못한 부하로 타임아웃을 뿜기 시작한다.
  • 같은 DB를 쓰던 다른 서비스도 연쇄적으로 실패하기 시작한다.

사용자 눈에는, 이건 이미 완전한 장애로 보인다. 하지만 루트 코즈는 단 하나의 컴포넌트에서 시작한 사소한 레이턴시 증가였을 뿐이다.

문제를 치명적으로 만든 건 결함 그 자체가 아니다. 그 결함이 어떻게 퍼져 나갈 수 있는지에 대한 가시성 부족, 그리고 전파를 막을 가드레일 부재였다.

메트로 맵은 두 가지 방식으로 이를 도와준다.

  1. 사고 중: 실패한 컴포넌트를 포함하는 경로가 어디인지, 그리고 (성능이 좀 떨어지더라도) 여전히 동작 가능한 대체 경로가 있는지 빠르게 볼 수 있다.
  2. 사고 후: 실제로 어떤 연쇄가 일어났는지 지도를 그려 보고, 이런 질문을 던질 수 있다.
    • 어디에서 영향이 제한됐어야 했는가?
    • 어떤 의존성이 지나치게 결합돼 있는가?
    • 어디에 격리나 백프레셔가 부족한가?

서킷 브레이커: 실패 노선 위의 정류장

실패가 어떻게 전파되는지 보이기 시작하면, 다음 단계는 연쇄를 차단하는 것이다. 여기서 서킷 브레이커(circuit breaker) 같은 탄력성 패턴이 등장한다.

서킷 브레이커는 다음을 수행한다.

  • Service A에서 Service B로 가는 호출을 모니터링한다.
  • 실패나 타임아웃이 설정한 임계를 넘으면 트립(오픈)한다.
  • 쿨다운 기간 동안 이후 호출을 단락(short-circuit)하고, 종종 폴백 응답을 반환한다.

메트로 맵 위에서 보면, 이건 마치 철도 노선 위의 제어된 정류장과 같다.

  • 트래픽이 라인 끝까지 몰려가서 쌓이지 않도록, 미리 정해진 경계에서 막거나 우회시킨다.
  • 업스트림 서비스와 공유 인프라를 과부하에서 보호한다.
  • 전체 시스템 장애 가능성을, 국지적이고 잘 이해된 성능 저하로 바꿔 준다.

비슷한 역할을 하는 패턴들은 더 있다.

  • 벌크헤드(bulkhead): 스레드, 커넥션 같은 리소스를 구역별로 격리해, 시끄러운 이웃 하나가 전체를 침몰시키지 못하게 한다.
  • 레이트 리미팅 & 백프레셔: 트래픽 흐름을 제어해 과부하를 방지한다.
  • 타임아웃과 지터를 동반한 재시도: 한 컴포넌트가 느려졌을 때, 자기 손으로 재시도 폭풍을 만들지 않게 한다.

잘 만들어진 메트로 맵에서는 이런 요소들이 분명하게 표시돼 있다. 그래서 실패 경로를 따라가다 보면 동시에 이렇게도 볼 수 있다.

  • 실패가 어디에서 멈췄어야 했는지
  • 서킷 브레이커나 벌크헤드가 완전히 비어 있는 구간이 어디인지

“작은” 것이 더 이상 작지 않은 영역: 미션 크리티컬 도메인

어떤 도메인에서는 “사소한” 문제라는 건 존재하지 않는다. 예를 들어:

  • 자동차: 작은 센서 이상을 제어 유닛이 잘못 해석했을 때
  • 의료: 모니터링 장비의 약간의 클럭 드리프트나 잘못 구성된 페일오버
  • 산업 / OT: 제어 시스템 간의 일시적인 네트워크 끊김

이런 영역에서는 물리 세계가 곧 지도에 포함된다. 실패는 단지 대시보드가 느려지는 수준이 아니라, 사람이나 설비에 직접적인 피해를 줄 수 있다.

그래서 미션 크리티컬 시스템은 훨씬 더 엄격한 신뢰성 분석을 요구한다.

  • 의존성과 실패 모드를 더 엄밀하게 모델링한다(FMEA, HAZOP 등).
  • 안전 필수(safety‑critical) 기능과 비핵심 기능을 강하게 격리한다.
  • 주요 경로에는 형식 검증 혹은 인증받은 컴포넌트를 사용한다.

여기서도 사고 메트로 맵은 유용하지만, 판돈이 크기 때문에 더 깊은 규율이 필요하다.

  • 단지 “가능성 높은” 흐름만이 아니라, 최악의 전파 시나리오까지 고려해야 한다.
  • 모든 사소한 설계·운영 이슈를, 훨씬 위험한 경로로 이어질 수 있는 잠재적인 진입점으로 다루어야 한다.

사건이 아니라 “경로”로서의 사고

사고를 하나의 독립된, 알 수 없는 “이벤트”로 취급하면, 사후 분석(Post‑mortem)은 대개 증상만 좇게 된다.

  • “Service X가 다운됐습니다.”
  • “CPU를 늘렸습니다.”
  • “타임아웃을 튜닝했습니다.”

대신, 사고를 **시스템 안을 통과하는 하나의 경로(route)**로 취급하면, 사후 분석의 깊이가 전혀 달라진다.

각 사고마다 다음을 물어볼 수 있다.

  1. 이번 사고의 경로는 무엇이었나?
    초기 결함 → 탐지 → 서비스 간 전파 → 사용자 영향까지의 전체 흐름.

  2. 어떤 역이 취약 지점이었나?
    문제를 증폭시킨 서비스나 컴포넌트(예: 과도한 재시도, 백프레셔 없음, 공유 의존성 등).

  3. 어떤 가드레일이 실패했거나 존재하지 않았나?
    서킷 브레이커, 벌크헤드, 더 나은 타임아웃 정책이 있었다면 영향을 국지화했을 곳.

  4. 지도를 어떻게 업데이트해야 하나?
    새로 발견된 의존성을 추가하고, SLA 정의를 조정하며, 핵심 경로를 정제한다.

시간이 지나면, 사고 경로 라이브러리가 쌓인다.

  • 반복적으로 나타나는 패턴 (예: “잠복된 벤더 이슈 → 재시도 폭풍 → DB 경합”)
  • 이미 알려진 고위험 역과 노선
  • 격리를 추가했을 때 큰 탄력성 향상을 가져왔던 지점들

이렇게 되면 조직 문화는 “망가진 것만 고치는” 수준에서, “문제가 퍼져나가게 만든 네트워크 전체를 강화하는” 방향으로 이동한다.


결론: 다음 골판지 사고가 오기 전에 지도를 그려라

모든 팀에는 골판지 사고 같은 이야기가 하나쯤 있다. 중요한 질문은, 다음 사고가 당신을 또 놀라게 만들 것이냐, 아니면 이미 지도 위에 표시해 두고, 방어하고, 리허설까지 마쳐 둔 경로를 그저 따라갈 뿐이냐 하는 것이다.

그 지점에 도달하려면 다음이 필요하다.

  1. 시스템을 리스트가 아닌 그래프로 모델링하라. 실제 의존성과 데이터 흐름을 담아라.
  2. 메트로 맵 뷰를 만들어라. 엔지니어와 비기술 이해관계자 모두가 한눈에 이해할 수 있게 하라.
  3. 토폴로지를 모니터링 스택에 연결하라. 장애가 날 때, 지도가 실시간으로 빛나게 만들라.
  4. 탄력성 패턴을 설치하고, 지도에 명시하라. 서킷 브레이커, 벌크헤드, 백프레셔를 핵심 분기점마다 배치하라.
  5. 사후 분석을 경로 분석으로 수행하라. 지도를 계속 업데이트하고, 시스템적 약점을 강화하라.

현대 스택의 복잡성은 피할 수 없다. 없앨 수 있는 종류의 것이 아니다. 하지만 우리는 그 복잡성을 눈에 보이게 만들 수 있다. 실패가 어떻게 움직이는지에 대한 분명한 스토리를 만들고, 작은 결함이 정말로 작은 수준에 머물도록 시스템을 설계할 수 있다. 그게 바로 다음 전설적인 골판지 사고를 막는 방법이다.