[우버(Uber) 기술 블로그] 10만 대의 DB 서버를 자동으로 움직이는 힘, Stateful 플랫폼 '오딘(Odin)' 이야기
안녕하세요! 오늘은 글로벌 모빌리티 기업 우버(Uber)가 대규모 데이터베이스와 스토리지 시스템을 어떻게 효율적으로 자동 관리하고 있는지, 그들의 핵심 인프라 플랫폼인 '오딘(Odin)'에 대해 소개해 드리려고 합니다.
최근 많은 기업들이 서비스 확장을 위해 쿠버네티스(Kubernetes)를 도입하지만, 데이터베이스(MySQL, Cassandra)나 메시지 큐(Kafka) 같은 상태 저장(Stateful) 시스템을 대규모로, 그것도 완전히 자동화하여 관리하는 것은 여전히 까다로운 영역입니다.
몇 백 대 수준에서 시작해 현재 10만 대 이상의 호스트를 관리하기까지, 우버가 겪은 고민과 기술적 해법을 함께 살펴보겠습니다.
1. 런북(Runbook)의 한계에서 탄생한 '오딘'
2014년, 우버가 무서운 속도로 성장하면서 인프라 팀은 거대한 벽에 부딪혔습니다. 서비스가 커질수록 MySQL, Cassandra, Kafka, HDFS 등 다채로운 데이터베이스 엔진이 우후죽순 늘어났기 때문입니다.
초기에는 엔지니어들이 문서화된 매뉴얼(Runbook)을 보며 수동으로 이 시스템들을 관리했습니다. 하지만 서버가 수천, 수만 대로 늘어나는 상황에서 수동 관리는 곧 장애로 이어졌습니다. 게다가 DB 종류마다 관리 방식이 달라 파편화 문제도 심각했죠.
이를 해결하기 위해 우버는 특정 데이터베이스 기술에 종속되지 않고(Technology-agnostic) 통합 관리가 가능한 자가 치유(Self-Healing) 플랫폼, '오딘(Odin)'을 개발하게 됩니다.
📊 오딘의 운영 규모 (2024년 기준)
- 관리 호스트(서버): 10만 대 이상
- 워크로드 수: 30만 개 이상
- 컨테이너 수: 380만 개 이상
- 지원 스토리지 기술: MySQL, Cassandra, Kafka, Presto 등 총 23가지 엔진
- 특징: 고성능을 위해 원격 저장소가 아닌 서버에 직접 부착된 로컬 디스크(Locally attached drives) 사용
2. 오딘의 핵심 아키텍처: 쿠버네티스를 닮은 자가 치유 시스템
오딘은 오픈소스인 쿠버네티스(Kubernetes)와 개념적으로 매우 유사한 구조를 가지고 있습니다. 가장 핵심은 '선언형(Declarative) 모델'과 '조정 루프(Remediation Loops)'입니다.
[ 엔지니어: "최종 상태(Goal State)" 설정 ]
│
▼
┌────────────────────────────────────────┐
│ 글로벌 플랫폼 'Grail' │ ◀── (전 세계 데이터 센터 상태 수집)
└────────────────────────────────────────┘
│
▼ [상태 비교 및 조정 루프 작동 (Cadence 워크플로우)]
┌────────────────────────────────────────┐
│ 각 서버 호스트 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ odin-agent │ │ worker │ │ (사이드카: DB 엔진별 제어)
│ │ (물리 자원) │ │ (DB 통역사) │ │
│ └──────────────┘ └──────────────┘ │
└────────────────────────────────────────┘
- 선언형 모델: 엔지니어가 "이 데이터베이스는 최소 3개의 카피를 유지해 줘"라고 '최종 상태(Goal State)'를 선언하면, 시스템이 알아서 그 상태를 만듭니다.
- 조정 루프와 Cadence: 시스템은 백그라운드에서 끊임없이 현재 상태와 최종 상태를 비교합니다. 만약 서버 하나가 죽어서 카피가 2개로 줄어들면, 우버의 오픈소스 워크플로우 엔진인 Cadence를 통해 자동으로 새 서버에 복제본을 띄웁니다.
- 눈과 발이 되는 컴포넌트:
- Grail: 전 세계 데이터 센터에 흩어진 오딘의 상태를 한눈에 보여주는 중앙 데이터 플랫폼입니다.
- odin-agent: 특정 DB 기술을 모르는 공통 에이전트로, 서버 내 CPU, 메모리, 디스크 자원을 할당합니다.
- worker: DB 종류마다 다르게 존재하는 사이드카 컨테이너입니다. 예를 들어 MySQL용 worker는 현재 노드가 마스터인지 레플리카인지 확인하고 제어하는 '통역사' 역할을 합니다.
3. Stateful 하기에 필요했던 전략: "Make-before-Break"
우버는 인프라 효율을 극대화하기 위해 한 달에 전체 워크로드의 무려 60%를 다른 서버로 재배치(Rescheduling)합니다. 빈 공간을 채워 넣고 서버 낭비를 줄이기 위함이죠.
여기서 Stateful 시스템만의 독특한 문제가 발생합니다. 오딘은 고성능을 위해 로컬 디스크를 씁니다. 만약 일반적인 웹 서버(Stateless)처럼 기존 컨테이너를 그냥 끄고 새 서버에서 켜면 어떻게 될까요? 새 서버가 기가바이트, 테라바이트 급의 데이터를 처음부터 복제받는 데 최소 1시간 이상이 걸립니다. 그동안 데이터 유실 위험이 커지고 서비스 가동성(Availability)에 구멍이 생깁니다.
이를 해결하기 위해 오딘은 "Make-before-Break (부수기 전에 먼저 만들기)" 전략을 사용합니다.
- 기존 워크로드를 종료하기 전에, 이사를 갈 새 서버에 복제본 워크로드를 먼저 생성합니다.
- 데이터와 고유 식별자(Identity)가 완전히 동기화되어 안전해진 것을 확인한 후에야 비로소 기존 워크로드를 종료합니다.
4. 거대해진 시스템이 마주한 성장통: 자동화끼리의 충돌
오딘 덕분에 우버는 수만 대의 DB를 무인으로 관리할 수 있게 되었지만, 규모가 10만 대를 넘어가면서 새로운 차원의 문제가 발생했습니다. 바로 자동화 루프 간의 충돌입니다.
예를 들어, 데이터 안전을 위해 3개의 노드로 묶여 있는 클러스터(Consensus-based cluster)가 있다고 가정해 보겠습니다. 이 클러스터는 최소 2개의 노드가 살아있어야(Quorum 유지) 정상 작동합니다.
- 상황:
- 루프 A (업그레이드 자동화): "보안 패치를 위해 노드 1번을 잠시 재부팅할게." (남은 노드 2개 - 정상)
- 루프 B (비용 최적화 자동화): "어? 노드 2번이 있는 서버 효율이 안 좋네? 다른 서버로 이사 시켜야지." (남은 노드 1개 - 과반수 붕괴, 클러스터 마비!)
과거에는 사람이 개입해 "지금 업그레이드 중이니까 이사는 멈춰!"라고 통제했지만, 10만 대 규모에서는 사람이 일일이 확인할 수 없습니다. 자가 치유를 하려는 수많은 자동화 엔진들이 서로 눈치를 보지 않고 각자 일하다가 오히려 시스템을 망가뜨리는 역설적인 상황이 발생한 것이죠.
💡 글을 마치며: 다음 과제는 '전역적 조율(Global Coordination)'
우버의 오딘 플랫폼 엔지니어들은 이 성장통을 해결하기 위해 수많은 자동화 작업이 서로 간섭하지 않도록 중앙에서 안전하게 통제하고 동시성을 제어하는 시스템을 구축했다고 합니다. 여러 개의 자가 치유 루프가 동시에 돌더라도 서비스 중단 없이 완벽한 하모니를 이루게 만든 것이죠.
대규모 RAG 기반 AI 에이전트 서비스나 대형 데이터 플랫폼을 준비하는 엔지니어라면, 우버의 오딘이 보여준 '선언형 모델'과 'Make-before-Break' 전략, 그리고 '자동화 간의 충돌 방지' 개념은 인프라 설계에 큰 영감을 주는 사례인 것 같습니다.
원문: Odin: Uber's Stateful Platform
Thanks
Hans