Scaling PostgreSQL to power 800 million ChatGPT users
Quick Summary
OpenAI는 ChatGPT와 API의 8억 사용자 규모 트래픽을 감당하기 위해 단일 primary PostgreSQL과 전 세계 약 50개 읽기 replica를 기반으로 읽기 중심 워크로드를 수백만 QPS까지 확장했다.
🖼️ 인포그래픽
🖼️ 4컷 인포그래픽
💡 한 줄 요약
OpenAI는 ChatGPT와 API의 8억 사용자 규모 트래픽을 감당하기 위해 단일 primary PostgreSQL과 전 세계 약 50개 읽기 replica를 기반으로 읽기 중심 워크로드를 수백만 QPS까지 확장했다.
📌 핵심 요약
- OpenAI의 PostgreSQL 부하는 1년 사이 10배 이상 증가했지만, 단일 primary Azure PostgreSQL flexible server와 여러 지역의 약 50개 read replica를 통해 ChatGPT와 API의 대규모 읽기 중심 트래픽을 처리해 왔다.
- 단일 primary 구조는 읽기 중심에는 충분한 확장 여지를 제공했지만, 캐시 장애, 비싼 조인 쿼리, 신규 기능으로 인한 write storm 같은 상황에서는 지연 증가와 재시도 증폭으로 서비스 전반의 장애로 이어질 수 있었다.
- PostgreSQL의 MVCC 특성 때문에 write-heavy 워크로드에서는 행 전체 복사, dead tuple 증가, 테이블·인덱스 bloat, autovacuum 튜닝 부담이 커졌고, OpenAI는 shardable write-heavy 워크로드를 Azure Cosmos DB 같은 sharded system으로 이전하고 신규 테이블 추가를 제한했다.
- OpenAI는 primary의 부담을 줄이기 위해 read traffic을 replica로 옮기고, 불필요한 write를 제거하며, lazy write와 backfill rate limit을 적용하고, 고비용 쿼리·ORM 생성 SQL·idle transaction을 지속적으로 점검했다.
- 가용성과 성능 격리를 위해 HA hot standby, 지역별 다중 replica, workload tier 분리, PgBouncer connection pooling, cache locking·leasing을 적용해 단일 replica 장애, connection storm, cache-miss storm, noisy neighbor 문제를 완화했다.
🧩 주요 포인트
- OpenAI의 PostgreSQL 부하는 1년 사이 10배 이상 증가했지만, 단일 primary Azure PostgreSQL flexible server와 여러 지역의 약 50개 read replica를 통해 ChatGPT와 API의 대규모 읽기 중심 트래픽을 처리해 왔다.
- 단일 primary 구조는 읽기 중심에는 충분한 확장 여지를 제공했지만, 캐시 장애, 비싼 조인 쿼리, 신규 기능으로 인한 write storm 같은 상황에서는 지연 증가와 재시도 증폭으로 서비스 전반의 장애로 이어질 수 있었다.
- PostgreSQL의 MVCC 특성 때문에 write-heavy 워크로드에서는 행 전체 복사, dead tuple 증가, 테이블·인덱스 bloat, autovacuum 튜닝 부담이 커졌고, OpenAI는 shardable write-heavy 워크로드를 Azure Cosmos DB 같은 sharded system으로 이전하고 신규 테이블 추가를 제한했다.
- OpenAI는 primary의 부담을 줄이기 위해 read traffic을 replica로 옮기고, 불필요한 write를 제거하며, lazy write와 backfill rate limit을 적용하고, 고비용 쿼리·ORM 생성 SQL·idle transaction을 지속적으로 점검했다.
- 가용성과 성능 격리를 위해 HA hot standby, 지역별 다중 replica, workload tier 분리, PgBouncer connection pooling, cache locking·leasing을 적용해 단일 replica 장애, connection storm, cache-miss storm, noisy neighbor 문제를 완화했다.
🧠 상세 정리
1. PostgreSQL이 맡은 핵심 역할과 급격한 부하 증가
OpenAI에서 PostgreSQL은 ChatGPT와 OpenAI API 같은 핵심 제품을 뒷받침하는 내부 데이터 시스템으로 오랫동안 사용되어 왔다. 사용자 기반이 빠르게 커지면서 데이터베이스에 걸리는 요구도 함께 폭증했고, 지난 1년 동안 PostgreSQL 부하는 10배 이상 증가했다. 글은 이런 성장 속에서도 PostgreSQL이 예상보다 훨씬 큰 읽기 중심 워크로드를 안정적으로 처리할 수 있었다는 점을 핵심 관찰로 제시한다. 특히 단일 primary Azure PostgreSQL flexible server와 여러 지역에 분산된 약 50개 read replica를 통해 전 세계 트래픽을 감당했다는 점이 강조된다. 이는 단순히 인스턴스를 키운 사례가 아니라, 애플리케이션과 데이터베이스 계층을 함께 최적화해 수백만 QPS 규모까지 끌어올린 엔지니어링 사례로 설명된다.
2. 단일 primary 구조가 가능했던 이유와 그 한계
글은 OpenAI 규모에서 단일 primary 구조가 작동한다는 사실이 놀랍게 보일 수 있지만, 실제 운영은 단순하지 않았다고 설명한다. ChatGPT 출시 이후 트래픽이 전례 없이 증가하자 OpenAI는 애플리케이션 최적화, PostgreSQL 레이어 최적화, 인스턴스 확장, read replica 추가를 빠르게 병행했다. 이 구조는 읽기 중심 워크로드에서는 상당한 여유를 제공했지만, primary 하나가 모든 write를 처리한다는 근본적 제약은 계속 남아 있었다. 캐시 계층 장애로 인한 광범위한 cache miss, CPU를 포화시키는 다중 조인 쿼리, 신규 기능 출시로 인한 write storm이 발생하면 데이터베이스 지연이 증가하고 요청 timeout이 늘었다. 이후 재시도가 다시 부하를 키우는 악순환으로 이어져 ChatGPT와 API 서비스 전체를 저하시킬 수 있었다.
3. MVCC와 write-heavy 워크로드의 구조적 부담
OpenAI는 PostgreSQL이 읽기 중심 워크로드에서는 잘 확장되지만, write traffic이 높아지는 구간에서는 여전히 어려움을 겪는다고 밝혔다. 주요 원인으로 PostgreSQL의 MVCC 구현이 언급된다. 쿼리가 tuple이나 단일 field를 업데이트해도 행 전체가 복사되어 새 버전이 만들어지기 때문에, heavy write 상황에서는 write amplification이 크게 증가한다. 또한 dead tuple이 늘어나면서 읽기 쿼리가 최신 버전을 찾기 위해 여러 tuple version을 훑어야 하므로 read amplification도 증가한다. 여기에 table bloat, index bloat, index maintenance overhead, autovacuum 튜닝의 복잡성이 더해져 write-heavy 워크로드에는 부담이 커진다.
4. write 압력을 줄이기 위한 워크로드 이전과 정책 변경
OpenAI는 write-heavy 워크로드의 한계를 줄이기 위해 shardable한 workload를 sharded system으로 이전하고 있으며, 예시로 Azure Cosmos DB를 언급한다. 또한 애플리케이션 로직을 최적화해 불필요한 write를 줄이는 방향도 병행했다. 기존 PostgreSQL deployment에는 더 이상 새로운 table을 추가하지 않고, 신규 workload는 기본적으로 sharded system을 사용하도록 한다는 정책도 제시된다. 다만 기존 애플리케이션 workload를 sharding하는 일은 수백 개 endpoint 수정이 필요할 수 있어 매우 복잡하고 오래 걸린다. 현재 workload가 주로 read-heavy이고 이미 많은 최적화가 적용되어 있기 때문에, PostgreSQL 자체를 당장 sharding하는 것은 근시일 내 우선순위가 아니라고 설명한다.
5. primary 부하 최소화와 write spike 대응
단일 writer 구조에서는 primary가 write spike를 감당하지 못하면 ChatGPT와 API 같은 서비스에 직접 영향이 간다. OpenAI의 대응 원칙은 primary에 걸리는 읽기와 쓰기 부담을 가능한 한 줄여, 갑작스러운 write spike를 처리할 여유를 확보하는 것이다. 읽기 트래픽은 가능한 경우 replica로 넘기지만, write transaction 안에 포함된 일부 read query는 primary에 남아야 하므로 이런 쿼리는 느려지지 않도록 효율성을 집중 관리한다. write traffic에서는 shardable하고 write-heavy한 workload를 sharded system으로 이전하고, redundant write를 만들던 애플리케이션 버그를 수정했다. 또한 적절한 곳에는 lazy write를 도입해 트래픽 spike를 완화하고, table field backfill에는 엄격한 rate limit을 적용해 과도한 write pressure를 막았다.
6. 고비용 쿼리, ORM, idle transaction 관리
OpenAI는 PostgreSQL에서 여러 expensive query를 발견했고, 과거에는 이런 쿼리의 volume spike가 CPU를 크게 소모해 ChatGPT와 API 요청을 느리게 만들었다고 설명한다. 특히 많은 table을 조인하는 쿼리는 서비스 전체를 저하시킬 수 있으며, 실제로 12개 table을 조인하는 매우 비싼 쿼리가 과거 high-severity SEV의 원인으로 확인된 사례가 언급된다. OpenAI는 가능한 한 복잡한 multi-table join을 피하고, 필요한 경우 쿼리를 분해해 복잡한 join logic을 application layer로 옮기는 방식을 고려한다고 밝혔다. 또한 문제 쿼리 중 상당수가 ORM이 생성한 SQL에서 나오기 때문에, ORM이 만든 SQL이 기대대로 동작하는지 꼼꼼히 검토하는 것이 중요하다고 한다. long-running idle query가 autovacuum을 막을 수 있으므로 idle_in_transaction_session_timeout 같은 timeout 설정도 필수적인 운영 장치로 제시된다.
7. 가용성 확보와 noisy neighbor 격리
read replica 하나가 내려가도 트래픽은 다른 replica로 라우팅할 수 있지만, writer가 하나뿐이면 primary는 단일 장애 지점이 된다. OpenAI는 critical request 대부분이 read query만 포함한다는 점을 활용해 이런 read를 writer에서 replica로 옮겼고, primary 장애 시에도 읽기 요청은 계속 처리될 수 있도록 했다. write operation은 여전히 실패할 수 있지만, 읽기가 유지되면 영향 범위가 줄어 SEV0 수준의 전면 장애로 번지는 것을 완화할 수 있다. primary에는 HA mode와 hot standby를 사용해 장애나 maintenance 상황에서 standby를 빠르게 승격할 수 있게 했다. 또한 특정 요청이나 신규 기능이 PostgreSQL CPU를 과도하게 소비해 다른 workload를 방해하는 noisy neighbor 문제를 줄이기 위해, low-priority와 high-priority traffic을 별도 instance로 분리하고 제품·서비스 간에도 유사한 격리 전략을 적용했다.
8. 연결 폭주와 cache-miss storm 방어
Azure PostgreSQL instance에는 최대 connection limit이 있으며, 글에서는 5,000개 제한을 언급한다. OpenAI는 connection storm으로 사용 가능한 connection이 모두 소진되는 사고를 겪었고, 이를 완화하기 위해 PgBouncer를 proxy layer로 배포해 database connection을 pooling했다. statement pooling이나 transaction pooling mode를 사용하면 client connection을 효율적으로 재사용할 수 있으며, benchmark에서는 평균 connection time이 50ms에서 5ms로 줄었다. 또한 proxy, client, replica를 같은 region에 배치해 inter-region connection 비용과 connection 사용 시간을 줄였다. 캐시 계층에서는 cache hit rate가 갑자기 떨어질 때 PostgreSQL로 read burst가 몰리는 문제를 막기 위해 cache locking과 leasing을 사용하며, 같은 key에서 여러 miss가 발생해도 하나의 요청만 데이터베이스를 조회하고 나머지는 cache repopulation을 기다리도록 했다.
🧾 핵심 주장 / 시사점
- 이 글의 핵심은 PostgreSQL이 단일 primary 구조에서도 읽기 중심 워크로드라면 매우 큰 규모까지 확장될 수 있지만, 그 전제는 replica 활용, 쿼리 최적화, connection pooling, cache storm 방어 같은 운영 장치가 촘촘히 갖춰져야 한다는 점이다.
- OpenAI는 PostgreSQL을 무조건 sharding하기보다, 비용이 큰 기존 workload sharding은 미루고 write-heavy·shardable workload부터 별도 sharded system으로 옮기는 현실적인 단계적 접근을 택했다.
- 대규모 데이터베이스 장애는 단일 원인보다 cache miss, 비싼 쿼리, 재시도, connection exhaustion처럼 여러 증폭 경로가 겹치며 커지므로, 부하를 줄이는 최적화뿐 아니라 장애 전파를 끊는 격리와 backpressure 설계가 중요하다.
✅ 액션 아이템
- 단일 primary는 유지하되 읽기 중심 부하는 Azure PostgreSQL replica 약 50개로 옮겨 수백만 QPS 처리 체력을 점검하고 운영 여지를 확보한다.
- 캐시 장애, 비싼 조인, write storm이 재시도 증폭을 만들지 않도록 불필요한 write를 줄이고 고비용 ORM SQL·idle transaction을 상시 정리한다.
- MVCC에서 행 전체 복사·dead tuple·bloat를 키우는 write-heavy 패턴을 Cosmos DB 이전 대상화하고 lazy write·backfill rate limit·cache locking·leasing를 함께 적용한다.
❓ 열린 질문
- 어떤 지표와 임계값에서 Azure PostgreSQL primary의 부담을 Cosmos DB 같은 sharded 시스템으로 이전할지 판단할 것인가?
- 캐시 장애와 쓰기 폭주가 겹칠 때 재시도 증폭을 먼저 포착하는 모니터링 경보는 어떤 조합이 유효한가?
- 지역별 다중 replica와 workload tier 분리를 병행할 때 어떤 기준으로 replica 분포와 connection pool 정책을 조정할 것인가?