Post

[BE] Railway GCP 계정 정지 사태: 단일 클라우드 의존의 대가

[BE] Railway GCP 계정 정지 사태: 단일 클라우드 의존의 대가

서론

5월 19일 22:20 UTC, 개발자 PaaS 플랫폼 Railway에 갑작스러운 전면 장애가 발생했다. 원인은 예기치 않은 Google Cloud Platform(GCP) 계정 자동 정지였다. 이후 약 8시간 동안 Railway의 API, 컨트롤 플레인, 데이터베이스가 오프라인 상태에 빠졌고, 사용자들은 대시보드에서 503 오류를 마주쳤다.

Railway는 수십만 개발자가 Node.js, Python, Ruby, Go 애플리케이션을 “Deploy in minutes”로 배포할 수 있는 플랫폼이다. 그 서비스가 8시간 동안 완전히 멈췄다는 사실은 단순한 서비스 중단 사고를 넘어, 현대 클라우드 인프라 설계에 대한 근본적인 질문을 던진다. Railway는 GCP만 사용하는 것이 아니라 자체 베어메탈 인프라(Railway Metal)와 AWS도 함께 운영하는 멀티 인프라 구조였다. 그럼에도 GCP 하나가 정지되자 전체 플랫폼이 무너진 이유는 무엇인가?

이번 장애는 컨트롤 플레인의 단일 장애점(SPOF), 엣지 캐시의 양면성, 그리고 클라우드 벤더 의존 리스크에 대해 실무적인 교훈을 준다.

본론

장애 타임라인

Railway가 공개한 인시던트 리포트를 기반으로 타임라인을 재구성하면 다음과 같다.

시각 (UTC)이벤트
5월 19일 22:20GCP 자동화 시스템이 Railway 프로덕션 계정 정지
22:20~API, 컨트롤 플레인, GCP 호스팅 데이터베이스 즉시 오프라인. 사용자에게 503 오류
22:20~ (약 1~2시간)엣지 프록시 캐시 유지 → Railway Metal·AWS 워크로드는 일시적으로 트래픽 처리 지속
캐시 만료 시점엣지가 라우팅 테이블 갱신 실패 → 전 리전, 전 워크로드 404 오류로 확산
5월 20일 06:14GCP 환경 복구 완료
06:14 이후 수 시간빌드·배포 백로그 점진적 소화, 완전 정상화까지 추가 시간 소요

장애 지속 시간은 약 8시간. Railway는 GCP 계정이 “자동화 시스템에 의해 정지됐다”고 밝혔지만, 정지 사유에 대해서는 “GCP로부터 충분한 정보를 받지 못했다”고 공식 포스트에서 인정했다.

왜 Metal·AWS 워크로드까지 무너졌나: 엣지 캐시의 두 얼굴

이번 장애에서 가장 흥미로운 기술적 포인트는 엣지 프록시와 캐시의 역할이다.

Railway 아키텍처에서 엣지 프록시는 GCP에 있는 네트워크 컨트롤 플레인으로부터 라우팅 테이블을 주기적으로 받아 캐싱한다. 이 라우팅 테이블이 있어야 엣지가 “이 요청은 Metal의 인스턴스 A로, 저 요청은 AWS의 인스턴스 B로” 라우팅할 수 있다.

캐시가 살아있는 동안: 컨트롤 플레인(GCP)이 다운됐어도 캐시된 라우팅 테이블로 Metal과 AWS의 워크로드는 정상적으로 트래픽을 처리했다. 일부 사용자는 Railway 장애를 인지하지 못했을 가능성이 있다.

캐시가 만료된 순간: 엣지 프록시가 컨트롤 플레인에서 최신 라우팅 테이블을 받아오려 했지만 컨트롤 플레인이 오프라인이어서 실패했다. 캐시가 비워진 엣지는 어디로 라우팅해야 할지 알 수 없어, GCP는 물론 Metal·AWS 워크로드까지 모두 404를 반환하기 시작했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
[GCP 계정 정지 발생]
        ↓
컨트롤 플레인(GCP) 오프라인
        ↓
┌─────────────────────────────────────┐
│ 엣지 캐시 유효 기간 (약 1~2시간)    │
│ Metal 워크로드 → 정상 서빙          │
│ AWS 워크로드  → 정상 서빙           │
└─────────────────────────────────────┘
        ↓ 캐시 TTL 만료
라우팅 테이블 갱신 실패
        ↓
전 리전 전 워크로드 404 오류 (캐스케이드 확산)

이 패턴은 시간 지연 캐스케이드 실패(delayed cascade failure)의 전형적인 사례다. 단기적으로는 캐시가 레질리언스를 제공했지만, 장기적으로는 캐시 만료가 장애를 더 넓게 동시에 확산시키는 결과를 낳았다.

GCP 자동 계정 정지: 왜 이런 일이 생기나

GCP를 포함한 주요 클라우드 벤더들은 특정 조건이 감지되면 자동화 시스템이 계정을 즉시 정지할 수 있다:

  • 결제 문제(카드 만료, 청구 실패)
  • 약관 위반 감지(이상 트래픽, 남용 의심)
  • 보안 이슈(계정 탈취 의심)
  • 규정 준수 정책 위반

Railway의 경우 정확한 사유가 공개되지 않았다. 그러나 이 이벤트가 단일 클라우드 의존의 가장 명확한 리스크를 보여준다는 점에서 중요하다. Railway는 멀티 인프라 구조를 갖추고 있었지만, 컨트롤 플레인과 데이터베이스가 GCP에 집중됐기 때문에 하나가 무너지자 나머지도 연쇄적으로 영향을 받았다.

데이터 플레인(워크로드 실행)의 멀티 클라우드화는 되어 있었지만, 컨트롤 플레인(라우팅, 오케스트레이션, DB)의 멀티 클라우드화는 미완이었다고 볼 수 있다.

복구 과정과 빌드 백로그

GCP 환경이 복구된 5월 20일 06:14 이후에도 Railway는 장애 8시간 동안 쌓인 빌드·배포 큐를 처리해야 했다. 배포를 기다리던 개발자들의 요청이 순차적으로 소화됐고, 완전한 정상화까지는 추가 시간이 필요했다.

Railway 팀은 장애 발생 직후부터 커뮤니티 플랫폼(Railway Central Station)에 공개 포스트를 올려 상황을 투명하게 공유했다. “알려진 것”과 “아직 파악 중인 것”을 구분해 업데이트한 것은 장애 커뮤니케이션의 좋은 사례로 평가받았다. 공식 인시던트 리포트도 장애 후 빠르게 공개됐다.

커뮤니티와 업계 반응

장애 이후 개발자 커뮤니티에서는 크게 두 가지 흐름의 반응이 나왔다.

플랫폼 분산 재논의: “내 서비스가 다른 회사의 GCP 계정 상태에 종속된다”는 구조적 문제를 지적하는 목소리가 있었다. Northflank, Render, Fly.io, Coolify 같은 대안 PaaS로 이전을 검토하거나 실제로 마이그레이션을 시작했다는 개발자들의 후기가 소셜 미디어와 포럼에 다수 게시됐다. Northflank는 자사 블로그에서 Railway 장애를 언급하며 “이런 상황에서 어디로 옮길 수 있는지” 안내 글을 올리기도 했다.

투명한 커뮤니케이션 호평: 반면 Railway의 장애 대응 커뮤니케이션에 대한 긍정적 평가도 있었다. 정확한 사유를 모르는 상태에서도 “현재 파악 중인 것”을 솔직하게 공유하고, 복구 진행 상황을 지속 업데이트했다는 점이 호평을 받았다. 많은 서비스가 장애 시 침묵하다가 사후에만 공식 발표를 내는 것과 대비되는 태도다.

SingleStore는 이 사건을 계기로 “AWS 장애와 GCP 장애를 동시에 고려한 크로스 리전 재해 복구”를 주제로 다룬 기술 블로그를 5월 이내에 발행했다. 유사한 장애가 AWS에서도 발생한 사례(5월 초 US-EAST-1 열 이벤트로 인한 Coinbase·FanDuel 장애)와 묶어서 클라우드 단일 의존 리스크를 다시 강조한 것이다.

백엔드 엔지니어를 위한 실무 교훈

이번 사건은 Railway를 직접 사용하지 않는 팀에게도 시사점이 있다.

1. 컨트롤 플레인을 데이터 플레인과 분리하라

데이터 플레인(실제 트래픽 처리)과 컨트롤 플레인(라우팅 테이블, 서비스 디스커버리, 설정 배포)을 서로 다른 장애 도메인에 배치하면, 컨트롤 플레인 장애 시 데이터 플레인이 얼마나 독립적으로 버틸 수 있는지 명확해진다. 컨트롤 플레인의 TTL(Time To Live)을 실제로 측정하고 문서화해두는 것이 좋다.

2. 엣지 캐시 TTL 전략을 명시적으로 설계하라

캐시 TTL이 너무 짧으면 컨트롤 플레인 순단에도 바로 장애가 전파된다. TTL이 너무 길면 라우팅 변경 반영이 지연된다. 이번 사례처럼 적당히 긴 TTL은 초기에는 레질리언스를 제공하지만, 만료 순간 장애가 동시 다발적으로 전파되는 리스크가 있다. Soft TTL + Health Check 패턴을 고려할 수 있다:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 개념적인 예시: soft TTL과 background refresh
class RoutingTableCache:
    def get(self, key):
        entry = self._cache.get(key)
        if entry is None:
            return self._fetch_and_store(key)  # hard miss

        if entry.is_soft_expired():
            # 백그라운드에서 갱신 시도, 실패해도 기존 캐시 반환
            self._async_refresh(key)
            return entry.value  # stale-while-revalidate

        return entry.value

3. 벤더 잠금 리스크 인벤토리를 만들어라

내 서비스의 어떤 컴포넌트가 단일 클라우드 벤더에 완전히 의존하는지 목록을 작성해두는 것이 좋다. 대안을 당장 마련할 수 없더라도, 리스크를 인지하고 있으면 장애 발생 시 대응 속도가 달라진다. 특히 다음 항목을 명시해두면 유용하다:

  • 데이터베이스: 어느 벤더/리전의 인스턴스를 사용 중인지
  • 컨트롤 플레인 서비스: 단일 벤더 의존 여부
  • DNS, CDN: 다운됐을 때 대안 경로가 있는지

4. 클라우드 계정 거버넌스를 운영 채널과 연결하라

자동 계정 정지 이벤트는 청구 실패, 약관 위반 경고, 비정상 트래픽 알림 등을 사전에 모니터링하지 않을 때 특히 자주 발생한다. GCP, AWS, Azure 등 각 벤더의 빌딩 알림과 정책 위반 알림을 Slack, PagerDuty 같은 운영 채널과 연동하는 것은 기본 중의 기본이다. 경고를 놓치지 않는 것만으로도 예방 가능한 장애가 생각보다 많다.

정리

  • 2026년 5월 19일 22:20 UTC, GCP 자동화 시스템이 Railway 프로덕션 계정을 정지해 약 8시간의 전면 장애가 발생했다.
  • Railway는 GCP·Railway Metal·AWS의 멀티 인프라 구조였지만, 컨트롤 플레인과 데이터베이스가 GCP에 집중됐기 때문에 Metal·AWS 워크로드도 엣지 캐시 만료 후 함께 다운됐다.
  • 이는 시간 지연 캐스케이드 실패의 전형적 사례로, 캐시는 단기 레질리언스를 제공하지만 만료 시점에 장애를 더 광범위하게 동시 전파한다.
  • 커뮤니티에서는 투명한 장애 커뮤니케이션을 높이 평가했지만, 단일 클라우드 의존 구조에 대한 재검토 논의도 활발하게 이루어졌다.
  • 실무 교훈: 컨트롤·데이터 플레인 분리, 엣지 캐시 TTL 전략 명시화, 벤더 잠금 리스크 인벤토리 작성, 클라우드 계정 알림 운영 채널 연동.

Reference

This post is licensed under CC BY 4.0 by the author.