피드로 돌아가기
Dev.toDatabase
원문 읽기
Database & Caching at Scale: From 200ms to 15ms Query Times at 100K+ Users
PostgreSQL 데이터베이스의 인덱스 최적화, 연결 풀링, 읽기 복제, Redis 캐싱을 통해 평균 쿼리 시간을 200ms에서 15ms로 단축 및 동시 사용자 1K에서 100K+ 지원
AI 요약
Context
PostgreSQL 단일 인스턴스에서 인덱스 전략이 부재하고 연결 풀링이 없으며 캐싱 계층이 없는 상태로, 동시 사용자 100K+로 증가하면서 평균 쿼리 시간 200ms, P95 850ms, P99 2,100ms를 기록했다. 전체 쿼리의 12%가 1초 이상 소요되었고 데이터베이스 CPU 점유율이 92%에 달했다.
Technical Solution
- 기본 Primary Key 인덱스만 존재하던 상태에서 47개의 최적화된 인덱스 추가: 복합 인덱스(composite index), INCLUDE 절을 활용한 커버링 인덱스, 부분 인덱스(partial index), GIN 인덱스를 통해 쿼리 플랜 개선
- 직접 데이터베이스 연결에서 최대 100개 연결 제한의 연결 풀링(connection pooling) 도입으로 연결 고갈 해결
- 단일 PostgreSQL 인스턴스를 Primary 1대 + Read Replica 3대 구조로 변경하여 읽기 쿼리 분산
- Redis 캐시 레이어 도입으로 87% 캐시 히트율 달성 및 데이터베이스 쿼리 부하 감소
- 전역 분산 배포로 <100ms 글로벌 응답 시간 확보
Impact
- 평균 쿼리 시간: 200ms → 15ms (92% 감소)
- P95 쿼리 시간: 850ms → 48ms (94% 감소)
- P99 쿼리 시간: 2,100ms → 125ms (94% 감소)
- 1초 이상 느린 쿼리 비율: 12% → 0.02%
- 데이터베이스 CPU 점유율: 92% → 28%
- 쿼리당 비용: $0.000265 → $0.000012 (95% 감소)
- 월간 비용: $530 → $920 (용량 100배 증가 대비 73% 비용 증가)
Key Takeaway
단일 데이터베이스에서 100K+ 동시 사용자로 확장할 때 인덱스 전략 수립, 연결 풀링, 읽기 복제, 캐싱을 체계적으로 조합하면 비용 효율성을 유지하면서 극적인 성능 향상을 달성할 수 있다.
실천 포인트
PostgreSQL 환경에서 10M+ 행의 대규모 테이블을 다룰 때 team_id, 시간 범위, 상태 조건을 모두 포함하는 복합 인덱스와 INCLUDE 절을 활용한 커버링 인덱스를 적용하면 풀 테이블 스캔 4,500ms를 인덱스 스캔 12ms로 단축할 수 있고, Redis read-through 캐싱 패턴으로 87% 히트율을 달성하면 데이터베이스 쿼리를 대폭 감소시킬 수 있다.