단 하나의 데이터베이스로 8억 명을? OpenAI가 PostgreSQL로 불가능을 가능케 한 방법
서론: ChatGPT 스케일의 예상치 못한 영웅
ChatGPT는 8억 명의 사용자와 초당 수백만 건의 쿼리를 처리하는 거대한 서비스입니다. 이러한 규모를 들으면 대부분의 엔지니어는 복잡하게 샤딩된 분산 데이터베이스 아키텍처를 떠올릴 것입니다. 수백, 수천 개의 노드로 데이터를 분산시켜야만 감당할 수 있는 트래픽이라고 생각하는 것이 일반적입니다.
하지만 놀랍게도 OpenAI는 이 모든 것을 주로 단 하나의 기본(Primary) Azure PostgreSQL 인스턴스와 전 세계 여러 리전에 분산된 **약 50개의 읽기 전용 복제본(read replicas)**으로 처리하고 있습니다. 캘리포니아 버클리 대학의 과학자 팀이 처음 만들었던 이 데이터베이스가 현대 AI 시대의 가장 거대한 워크로드 중 하나를 지탱하는 영웅이 된 것입니다. 이 사실은 기존의 스케일링 상식에 도전장을 내밉니다.
이 글에서는 OpenAI가 어떻게 전통적인 데이터베이스로 여겨지는 PostgreSQL의 한계를 뛰어넘어 세계 최대 규모의 워크로드를 감당했는지, 그 과정에서 얻은 가장 중요하고 놀라운 교훈들을 자세히 살펴보겠습니다.
1. 샤딩이 항상 정답은 아니다: 단일 데이터베이스의 힘
OpenAI의 가장 의외의 결정은 폭발적인 성장에도 불구하고 PostgreSQL을 샤딩하지 않고 단일 기본 인스턴스 아키텍처를 고수한 것입니다. 그들은 기존 애플리케이션 워크로드를 샤딩하는 것이 수백 개의 엔드포인트를 수정해야 하는 매우 복잡하고 시간이 많이 소요되는 작업이며, 완료하는 데 수개월에서 수년이 걸릴 수 있다고 판단했습니다.
대신, 그들은 자신들의 워크로드가 주로 **읽기 중심(read-heavy)**이라는 점에 주목했습니다. 이 특성 덕분에 광범위한 최적화를 통해 현재 아키텍처만으로도 미래의 성장을 감당할 충분한 여력을 확보할 수 있었습니다. 물론 이것이 샤딩을 영원히 배제한다는 의미는 아닙니다. OpenAI는 미래에 PostgreSQL을 샤딩할 가능성을 열어두고 있지만, 현재로서는 최우선 순위가 아니라고 말합니다. 이 접근 방식은 비전통적이지만, OpenAI의 특정 요구사항에는 매우 효과적인 전략이었습니다.
2. 진짜 문제는 읽기가 아닌 쓰기: 쓰기 부하를 무자비하게 분산하라
PostgreSQL은 MVCC(다중 버전 동시성 제어) 구현 방식 때문에 쓰기 중심 워크로드에 본질적인 어려움을 겪습니다. 단일 필드만 업데이트해도 전체 행이 복사되어 새로운 버전을 만들기 때문에, 쓰기 부하가 높을 때 심각한 쓰기 증폭(write amplification) 현상이 발생합니다. 이는 더 많은 읽기 증폭(dead tuple 스캔), 테이블 및 인덱스 팽창(bloat), 인덱스 유지 관리 오버헤드 증가, 복잡한 오토배큠(autovacuum) 튜닝과 같은 추가적인 문제로 이어집니다. (이 문제에 대한 깊이 있는 분석은 저자가 참여한 “The Part of PostgreSQL We Hate the Most” 블로그 글에서 찾아볼 수 있습니다.)
OpenAI는 이 문제를 해결하기 위해 쓰기 트래픽을 공격적으로 분산시키는 전략을 채택했습니다.
-
쓰기 중심 워크로드 이전: 수평적으로 파티셔닝이 가능한 쓰기 중심 워크로드는 Azure Cosmos DB와 같은 샤딩된 시스템으로 이전했습니다.
-
신규 테이블 생성 금지: 현재 PostgreSQL 배포에 더 이상 새로운 테이블을 추가하는 것을 금지했습니다. 새로운 워크로드는 기본적으로 샤딩된 시스템으로 보내도록 강제했습니다.
-
애플리케이션 로직 최적화: 불필요한 쓰기를 유발하는 애플리케이션 버그를 수정하고, 트래픽 급증을 완화하기 위해 지연 쓰기(lazy writes)를 도입했습니다.
“새로운 워크로드는 기본적으로 샤딩된 시스템으로 보내고, 더 이상 현재 PostgreSQL 배포에 새로운 테이블을 추가하는 것을 허용하지 않습니다.”
3. 복잡한 로직은 데이터베이스 밖으로: 애플리케이션의 역할 재정의
비용이 많이 드는 쿼리 하나가 전체 서비스를 마비시킬 수 있습니다. 실제로 OpenAI에서는 12개의 테이블을 조인하는 단 하나의 값비싼 쿼리가 급증하여 심각한 장애를 일으킨 사례가 있었습니다. 이러한 쿼리는 데이터베이스의 CPU를 과도하게 소모하여 다른 모든 요청을 느리게 만듭니다.
해결책은 복잡한 로직을 데이터베이스에서 애플리케이션 레이어로 옮기는 것이었습니다. 여러 테이블을 조인해야 하는 복잡한 쿼리는 여러 개의 단순한 쿼리로 분해하고, 조인 로직은 애플리케이션 코드 내에서 처리하도록 변경했습니다. 특히, 이런 문제성 쿼리들은 종종 ORM(Object-Relational Mapping) 프레임워크에 의해 자동으로 생성될 수 있으므로, ORM이 생성하는 SQL을 신중하게 검토하는 것이 매우 중요하다고 강조합니다. 또한, 장시간 유휴 상태로 남아 오토배큠을 방해하는 쿼리를 방지하기 위해 idle_in_transaction_session_timeout과 같은 타임아웃을 설정하는 것이 필수적입니다.
4. 규모뿐만 아니라 장애를 대비해 설계하라: 단일 장애점 완화 전략
단 하나의 쓰기 인스턴스를 갖는다는 것은 치명적인 단일 장애점(single point of failure)을 안고 있다는 의미입니다. 만약 기본 인스턴스가 다운되면 쓰기 작업이 모두 중단되어 서비스 전체에 영향을 미칠 수 있습니다.
OpenAI는 이 위험을 완화하기 위해 장애 상황을 염두에 두고 시스템을 설계했습니다.
-
읽기/쓰기 분리: 대부분의 핵심적인 사용자 요청은 읽기 전용 쿼리이므로, 이 트래픽을 모두 읽기 전용 복제본으로 이전했습니다. 이렇게 하면 기본 인스턴스가 다운되더라도 읽기 요청은 계속 처리될 수 있어, 서비스 전체가 중단되는 최악의 상황(SEV0)을 막을 수 있습니다.
-
빠른 장애 조치: 기본 인스턴스 장애에 대비해 고가용성(HA) 모드로 핫 스탠바이(hot standby)를 운영합니다. 핫 스탠바이는 항상 동기화된 복제본으로, 장애 발생 시 신속하게 기본 인스턴스로 승격되어 다운타임을 최소화합니다. OpenAI는 Azure PostgreSQL 팀이 이러한 장애 조치가 극심한 부하 상황에서도 안전하고 안정적으로 유지되도록 상당한 노력을 기울였다고 언급합니다.
-
다중 복제본 배포: 각 리전마다 여러 개의 복제본을 배포하여, 단일 복제본의 장애가 리전 전체의 서비스 중단으로 이어지지 않도록 설계했습니다.
5. 다층 방어로 데이터베이스를 사수하라: 노이즈와 과부하 차단
데이터베이스는 예측 불가능한 부하로부터 스스로를 보호할 수 없습니다. 따라서 여러 계층에 걸쳐 방어막을 구축하는 것이 필수적입니다. OpenAI는 데이터베이스를 과부하로부터 보호하기 위해 다음과 같은 정교한 다층 방어 전략을 사용합니다.
-
워크로드 격리: “시끄러운 이웃(noisy neighbor)” 문제를 해결하기 위해 트래픽을 우선순위가 높은 티어와 낮은 티어로 나누어 별도의 인스턴스로 라우팅합니다. 이를 통해 우선순위가 낮은 워크로드의 부하가 급증하더라도 핵심 서비스에 영향을 주지 않습니다.
-
커넥션 풀링: PgBouncer를 도입하여 데이터베이스 커넥션을 효율적으로 재사용했습니다. 이를 통해 평균 커넥션 설정 지연 시간을 50ms에서 5ms로 극적으로 줄였고, 커넥션 고갈로 인한 장애를 방지했습니다.
-
캐싱 전략: “캐시 잠금(cache locking)” 메커니즘을 구현하여 캐시 미스(cache-miss)가 폭풍처럼 몰아칠 때 데이터베이스가 다운되는 것을 막았습니다. 동일한 키에 대해 캐시 미스가 여러 번 발생하면, 단 하나의 요청만 데이터베이스에 접근하여 데이터를 가져오고 캐시를 채웁니다. 나머지 요청들은 데이터베이스에 부하를 주지 않고 캐시가 채워질 때까지 기다립니다.
-
비율 제한(Rate Limiting): 애플리케이션, 커넥션 풀러, 쿼리 등 여러 계층에 걸쳐 비율 제한을 구현하여 트래픽 급증이 데이터베이스를 압도하는 것을 방지합니다. 또한 ORM 계층을 개선하여 특정 쿼리 다이제스트(digest)를 차단하는 기능을 추가함으로써, 문제가 되는 쿼리로 인한 부하를 신속하게 차단할 수 있습니다.
-
엄격한 스키마 관리: 가벼운 스키마 변경만 허용하고, 전체 테이블 재작성을 유발하는 변경은 피합니다. 모든 스키마 변경에는 5초의 엄격한 타임아웃을 적용합니다. 새로운 기능에 새 테이블이 필요한 경우, PostgreSQL이 아닌 Azure Cosmos DB와 같은 대체 샤딩 시스템에 생성해야 합니다.
결론: 가능성의 한계를 밀어붙이다
OpenAI의 사례는 체계적인 엔지니어링과 영리한 최적화가 동반된다면 PostgreSQL과 같은 전통적인 도구도 세계에서 가장 큰 워크로드 중 하나를 처리할 수 있도록 확장될 수 있음을 증명합니다. 그들은 초당 수백만 건의 쿼리, 99.999%의 가용성, 그리고 10ms대의 낮은 지연 시간을 달성하며 이 아키텍처의 잠재력을 보여주었습니다.
하지만 이 여정은 아직 끝나지 않았습니다. 그들은 샤딩하기 더 까다로운 나머지 쓰기 중심 워크로드를 계속해서 이전하고 있으며, Azure 팀과 협력하여 50개 이상의 복제본으로 확장할 수 있는 **계단식 복제(cascading replication)**를 테스트하고 있습니다. 또한 미래의 수요를 대비해 샤딩된 PostgreSQL이나 다른 분산 시스템을 지속적으로 탐색하고 있습니다.
OpenAI의 사례는 우리가 ‘전통적인’ 기술의 한계를 너무 빨리 단정짓고 있는 것은 아닌지 되돌아보게 합니다. 당신의 기술 스택에는 이처럼 숨겨진 잠재력을 가진 '영웅’이 있습니까?
