나는 PostgreSQL 안쓰는데도 무려 8억 사용자의 수백만 QPS를 어떻게 해결하는지 궁금하잖아 다들
수백만 QPS를 처리하는데 Azure PostgreSQL을 쓰고, 단일 쓰기 노드와 50 여개의 복제본으로 수용한다는건 직접 안해보면 알 방법이 없는 견적이다. 그 쓰기 처리량을 단일 노드로…. 놀랍다.
이거 단순 계산하면 각 읽기 복제본당 약 2만~5만 QPS 정도를 분담하는 구조로, Azure에서 제공하는 가장 높은 하드웨어 사양(96 vCore, 672GiB RAM, 32TiB)로 추측했다.
East US 리전 기준으로 최대 스펙의 Azure 서버는 수백만 QPS의 네트워크 IO 비용을 제외하고서도, 인스턴스 비용 $10,000 * 50, 스토리지 공간 $5,000 * 50 으로 한화로 월 10억 원씩 쓰는 셈이다.
이렇게 해외 기업의 기술 블로그를 통해서나마 인사이트를 얻을 수 있어서 최신 기술 동향을 파악하는 것이 중요하다.
지난 1년간 OpenAI의 PostgreSQL 사용량은 10배 이상 증가했으며, 계속해서 빠르게 증가하고 있다.
이러한 성장을 지속하기 위해 생산 인프라를 발전시키려는 노력은 새로운 인사이트를 얻었는데, PostgreSQL은 생각보다 훨씬 더 큰 읽기 중심 워크로드를 신뢰성 있게 지원하도록 확장할 수 있다는 점이다.
California 대학교의 Berkeley 캠퍼스 연구에서 처음 시작한 이 시스템은 단일 Primary로도 대규모 글로벌 트래픽을 지원할 수 있다.
OpenAI는 전 세계 여러 지역에 걸쳐서 약 50개의 읽기 복제본이 존재한다. 여기서는 그 과정에서 배운 교훈을 다룬다.
단일 아키텍처로 OpenAI의 규모 요구를 충족한다는 점이 놀랍게 들릴 수 있지만, 실제로 이를 실현하는건 쉽지 않았다.
PostgreSQL 과부하로 발생하는 SEV는 종종 upstream 이슈로 인한 DB 부하 급증 패턴을 따른다:
리소스 사용량이 증가하면서 쿼리 지연도 증가하고, 요청이 timeout되기 시작한다.
이때 재시도 메커니즘은 부하를 더 증폭시켜서 서비스 전체를 저하시키는 악순환을 초래할 수 있다.
또 PostgreSQL은 다중 버전 동시성 제어(MVCC) 구현 때문에 쓰기 중심의 워크로드에 비해 효율이 떨어진다. 그래서 읽기 중심 작업에는 잘 확장되지만 쓰기 트래픽이 많은 시기에는 어려움을 겪는다.
이에 대한 추가적인 문제 논의는 PostgreSQL 위키에 포스트 작성자가 함께 작성한게 있다.
The Part of PostgreSQL We Hate the Most
As much as Andy loves PostgreSQL, there is one part that is terrible and causes many headaches for people. Learn what it is and why it sucks.
www.cs.cmu.edu
이 썸네일은 뭐지
이런 한계를 완화하고 쓰기 부담을 줄이기 위해서 수평적으로 분할(Sharding) 가능한 쓰기 중심의 워크로드를 Azure Cosmos DB로 마이그레이션 중이다.
그리고 불필요한 쓰기를 최소화하도록 애플리케이션 로직을 최적화했다. 이제 기존 PostgreSQL에는 새로운 테이블 추가를 허용하지 않고 신규 시스템에 할당된다.
모든 쓰기를 하나의 Primary 인스턴스로 처리하는 이유는 그 샤딩 과정이 매우 복잡하고 시간이 많이 소요되기 때문이다.
수백 개의 애플리케이션 엔드포인트도 변경해야 해서 몇 달 또는 몇 년이 걸릴 수 있다.
현재 워크로드는 주로 읽기 중심이고, 광범위한 최적화를 진행했기 때문에 여전히 트래픽 증가를 지원할만큼 충분한 여유 공간을 갖고 있다고 한다.
그래서 미래에 샤딩할 수도 있겠지만 현재의 성장을 위한 여유는 충분하기 때문에 단기적인 우선순위에서 제외되었다.
중복 쓰기 오류를 애플리케이션 수준에서 수정하거나 지연된 쓰기를 도입해서 트래픽 급증을 완화하거나 쓰기 속도 제한을 통해 쓰기 pressure를 방지하고 있다.
12개 테이블을 조인하는 복잡한 쿼리의 급증이 심각한 SEV 원인이었고, 대다수가 ORM이 생성한 쿼리였기 때문에 신중히 쿼리문을 검토하고 기대하는대로 동작하는지 확인하는 것이 중요하다.
해당 쿼리들은 분해하고 조인 과정을 애플리케이션 계층으로 옮겨서 진행하고 idle_in_transaction_session_timeout처럼 timeout 설정, 장시간 유휴 쿼리를 모니터링한다.
대부분의 요청은 읽기에 치중되어 있기 때문에 Primary의 SPOF 문제를 완화하기 위해서 읽기 작업을 복제본으로 라우팅했다. 장애시 쓰기 작업은 실패하겠지만 그 영향은 줄어든다.
Primary 장애를 줄이기 위해서 고가용성(HA) 모드로 운영하며 항상 트래픽을 대신할 synced 복제본의 stand-by 구조를 사용한다.
새로운 기능 출시할때 비효율적인 쿼리 도입으로 PostgreSQL CPU를 크게 소모해서 기존 시스템의 요청이 느려질 수 있다.
이 “noisy neighbor” 문제를 완화하기 위해서 워크로드를 리소스 집약적 요청의 우선순위별로 나눠서 라우팅했다.
덜 중요한 작업이 CPU를 크게 소모하더라도 중요한 작업의 요청 성능이 저하되지 않는다.
각 DB 인스턴스의 커넥션이 고갈되거나 유휴 상태가 많아서 statement나 transaction polling 모드를 통해 활성 커넥션 수를 크게 줄일 수 있었다.
연결 설정의 지연 시간(50ms→5ms)도 감소했다.
캐시 계층 장애로 인한 캐시 미스 급증이 데이터베이스 부하로 이어진 사례다. 특정 Key를 놓친 단일 Leader만 fallback하는 캐시 잠금 및 lease 구현으로 해결했다.
하나의 요청만 락 걸고 캐시를 적재하고, 나머지 요청들은 대기하기 때문에 PostgreSQL를 보호할 수 있었다.
50 여개의 읽기 복제본은 모두 Primary의 WAL(Write Ahead Log)를 스트리밍한다.
이 복제본 개수가 증가할수록 더 많은 복제본에게 WAL을 전달해야 해서 네트워크 대역폭, CPU 모두에 부담을 준다.
이로 인해서 복제 지연(replication log)가 더 크고 불안정해져서 시스템의 신뢰성 있는 확장을 해친다.
이를 해결하기 위해서 Azure PostgreSQL 팀과 협력하여 계단식 복제(cascading replication)를 도입했다.
중간(intermediate) 복제본이 WAL을 하위(downstream) 복제본으로 중계하는 방식인데, 테스트중이라고만 하고 실제 지연을 어느 정도 해결하는지 궁금하다.
외에도 한 두개 정도 최적화 방법이 더 있는데 내 흥미를 끌지 못했다. 탈락하셨습니다.
이 컬럼은 적절한 설계와 최적화를 통해 Azure PostgreSQL이 어느 정도 규모의 워크로드까지 처리하도록 확장 가능한지 보여준다.
OpenAI는 거의 50개의 읽기 복제본을 추가하면서도 복제 지연(replication lag)를 거의 0에 가깝게 유지하고, 지리적으로 분산된 지역에 대해서 저지연 읽기를 보장하고 미래의 성장을 위한 여유 용량까지 확보했다.
이를 통해서 클라이언트측에서 두 자릿수 ms의 낮은 지연시간(p99)와 5-9 가용성을 제공하고 있다.
지난 12개월동안 SEV-0 PostgreSQL 사고는 단 한 건뿐이었는데, 이는 ChatGPT ImageGen의 트래픽이 10배 이상 급증하여 일주일만에 1억 명 이상의 신규 사용자가 가입했다.
ㅇㅋ 인정
앞으로도 인프라 수요가 증가함에 따라 PostgreSQL Sharding이나 대체할만한 분산 시스템 등의 추가적인 확장 접근법을 모색한다고 하니 기대된다.
출처 및 인용.
| 가상 쓰레드 도입 전후 DB 병목의 이동 (feat. HikariCP 튜닝 전략) (0) | 2026.01.12 |
|---|---|
| ArgoWorkflows: 대용량 워크플로우 아카이브 조회시 Out of sort memory 기여 (0) | 2026.01.12 |
| Cursus: BloomFilter를 이용한 컨슈머 벤치마크의 정확성 검사 확장 (0) | 2026.01.03 |
| Cursus: Tabellarius CDC(Change Data Capture) 설계 (0) | 2025.12.30 |
| 오픈소스 입문자를 위한 Kubernetes 지역화: 누락된 문서 탐지 스크립트 구현 (1) | 2025.12.22 |