클라우드 PostgreSQL 요금 비교 (AWS RDS vs Supabase vs Neon) 및 Too many connections(PgBouncer) 해결 가이드
서버리스 API나 AI 에이전트 백엔드를 배포한 뒤 트래픽이 몰리는 순간 가장 먼저 마주치는 장애 중 하나가 바로 FATAL: sorry, too many clients already 오류입니다. PostgreSQL의 기본 max_connections는 인스턴스 메모리에 비례해 제한되며, AWS RDS db.t4g.micro는 약 87개, db.t4g.small은 약 175개 수준에 묶여 있습니다. 요청마다 새 TCP 연결을 여는 서버리스 환경에서는 동시 접속자 100명만 넘어도 데이터베이스가 즉시 신규 연결을 거부합니다.
이 병목을 피하려고 무작정 RDS 인스턴스 사양을 키우거나 RDS Proxy를 붙이면 월 고정비가 15달러에서 순식간에 100달러 이상으로 불어납니다. 반면 Supabase나 Neon 같은 매니지드 서버리스 PostgreSQL은 커넥션 풀러를 기본 내장하고 있지만, 유휴 상태 과금 방식과 Egress(외부 전송) 단가 구조가 달라 워크로드에 따라 오히려 비용 역전이 발생합니다. 이번 글에서는 AWS RDS, Supabase, Neon의 실제 월간 과금 구조를 수치로 대조하고, PgBouncer Transaction 모드로 커넥션 고갈과 Prepared Statement 충돌을 동시에 잡는 실전 설정을 정리합니다.
1. AWS RDS vs Supabase vs Neon 요금 및 스펙 비교
클라우드 PostgreSQL 비용은 단순히 월 기본료만 비교하면 오판하기 쉽습니다. 상시 가동(Always-on) 여부, 커넥션 풀러 포함 여부, 스토리지 IOPS 및 Egress 단가를 함께 계산해야 실제 청구서를 예측할 수 있습니다. 프로덕션 소규모~중규모 워크로드 기준 세 플랫폼의 핵심 스펙과 가격을 표로 정리했습니다.
| 구분 / 항목 | AWS RDS (db.t4g.small) | Supabase (Pro Plan) | Neon (Launch / Scale) |
|---|---|---|---|
| 기본 월 요금 | 단일 AZ 약 $24~$29/월 (gp3 20GB 포함, Multi-AZ 시 약 2배) |
기본 $25/월 (Compute 크레딧 $10 포함, 추가 프로젝트 별도) |
Launch $19/월~ (CU-hour + 스토리지 $0.35/GB 종량제) |
| 유휴 과금 방식 | 24시간 상시 과금 (트래픽 0이어도 100% 청구) |
상시 과금 (일시 중지 기능은 무료 티어 한정) |
Scale-to-Zero 지원 (기본 5분 유휴 시 컴퓨트 과금 중단) |
| 커넥션 풀링 | 기본 미포함 (RDS Proxy 추가 시 월 $22+ 발생) |
Supavisor 기본 내장 (Transaction/Session 포트 분리) |
PgBouncer 풀러 기본 내장 (호스트명 -pooler 접미사로 즉시 사용) |
| 스토리지·Egress | gp3 3,000 IOPS 기본 제공 외부 Egress $0.09/GB (100GB 초과) |
8GB 포함(초과 $0.125/GB) 월 250GB Egress 포함(초과 $0.09/GB) |
초과 스토리지 $0.35/GB Copy-on-Write 브랜칭 즉시 복제 |
| 최적 워크로드 | 24시간 일정 트래픽, AWS VPC 내부망 연동 | Auth·Storage·pgvector 일체형 서비스 | 서버리스 API, 트래픽 편차가 큰 개발·SaaS |
2. 숨은 과금 함정: RDS Proxy, Cold Start, 그리고 Compute Add-on
AWS RDS의 부가 비용: RDS Proxy와 네트워크 Egress
AWS RDS는 인스턴스 자체 가격만 보면 합리적이나, 서버리스 함수(AWS Lambda, Vercel)와 연결할 때 RDS Proxy를 붙이는 순간 단가 구조가 바뀝니다. RDS Proxy는 프로비저닝된 vCPU당 시간당 $0.015(최소 과금 기준 월 약 $22 수준)를 별도로 청구합니다. db.t4g.small 인스턴스 비용($24~29)에 프록시 비용만 얹어도 월 청구서가 두 배 가까이 뜁니다. 또한 RDS가 Private Subnet에 있고 외부 NAT Gateway를 거쳐 데이터를 주고받는 구조라면 네트워크 전송 비용까지 겹치므로, VPC 내부 통신 비용을 줄이려면 AWS NAT Gateway 데이터 처리 요금 폭탄 원인과 VPC Endpoint(S3·ECR)·fck-nat으로 클라우드 네트워크 비용 80% 절감 가이드를 참고해 네트워크 경로를 먼저 정리하는 편이 유리합니다.
Neon Scale-to-Zero의 양면: Cold Start와 CU 폭증
Neon은 트래픽이 없는 시간대에 컴퓨트 노드를 자동으로 재워(Scale-to-Zero) 야간·주말 비용을 0에 가깝게 낮춥니다. 하지만 절전 상태에서 첫 쿼리가 들어올 때 컴퓨트가 깨어나는 Cold Start 지연(통상 300ms~1초 이상)이 발생하므로, 응답 지연에 민감한 실시간 결제 API라면 Scale-to-Zero를 끄거나 최소 대기 시간을 늘려야 합니다. 반대로 인덱스 없는 무거운 쿼리나 배치 작업이 오토스케일링 CU(Compute Unit) 상한을 계속 치면 종량제 요금이 고정형 RDS보다 높아질 수 있습니다.
Supabase Pro의 Compute Add-on과 pgvector 활용
Supabase Pro 플랜($25/월)은 기본으로 Micro 컴퓨트 크레딧($10)을 포함하지만, 동시 접속자나 백그라운드 워커가 늘어나 Small($15)·Medium($60)으로 컴퓨트를 올리면 그 차액만큼 매달 합산됩니다. 프로젝트가 2개 이상이면 프로젝트마다 컴퓨트 비용이 따로 붙는 점도 유의해야 합니다. 다만 인증(Auth), 오브젝트 스토리지, 벡터 검색(pgvector)을 한 번에 묶어 관리할 수 있어 AI 앱 구축 시 별도 인프라 비용을 아끼는 효과가 큽니다. 벡터 인덱스 메모리 튜닝과 비용 비교는 RAG 구축을 위한 벡터 DB(Pinecone·Qdrant·Supabase pgvector) 요금 비교 및 PostgreSQL HNSW 인덱스·메모리 튜닝 실전 가이드에서 더 자세히 확인할 수 있습니다.
3. Too many connections 해결: PgBouncer Transaction 모드 실전 설정
RDS Proxy나 고가 플랜에 비용을 쓰지 않고도 커넥션 고갈을 막으려면 앞단에 PgBouncer를 두어야 합니다. PgBouncer는 애플리케이션이 여는 수천 개의 단기 연결을 자신이 받아낸 뒤, 실제 PostgreSQL 서버에는 소수의 장수명 커넥션만 열어두고 트랜잭션이 실행되는 동안만 커넥션을 빌려주고 즉시 회수합니다.
커넥션 풀링에는 세 가지 모드가 있습니다. Session 모드는 클라이언트 연결이 끊길 때까지 서버 커넥션을 점유해 서버리스 환경의 폭주를 막지 못하며, Statement 모드는 다중 문장 트랜잭션(BEGIN...COMMIT)을 쓸 수 없습니다. 실무의 표준은 쿼리 트랜잭션이 끝나는 즉시 커넥션을 풀로 반환하는 Transaction 모드입니다.
# /etc/pgbouncer/pgbouncer.ini
[databases]
app_db = host=your-rds-endpoint.ap-northeast-2.rds.amazonaws.com port=5432 dbname=app_db
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
# 핵심: Transaction 모드로 커넥션 재사용 극대화
pool_mode = transaction
# 클라이언트 최대 수용 연결 수 vs 실제 DB 서버에 열 최대 연결 수
max_client_conn = 2000
default_pool_size = 20
reserve_pool_size = 5
reserve_pool_timeout = 3
# 유휴 서버 커넥션 정리 및 드라이버 호환성 옵션
server_idle_timeout = 60
ignore_startup_parameters = extra_float_digits,options
ORM·드라이버의 Prepared Statement 충돌 트러블슈팅
PgBouncer Transaction 모드를 켜자마자 ERROR: prepared statement "s0" already exists 또는 does not exist 에러가 터지는 경우가 잦습니다. 트랜잭션마다 다른 백엔드 서버 커넥션을 할당받기 때문에, 이전 커넥션에 등록된 이름 있는 Prepared Statement를 다음 커넥션이 찾지 못해 생기는 현상입니다. Supabase Supavisor(포트 6543)나 Neon Pooler를 쓸 때도 똑같이 발생하므로, 애플리케이션 드라이버에서 Prepared Statement 캐싱을 끄거나 풀러 호환 플래그를 반드시 넘겨야 합니다.
// 1) Prisma (DATABASE_URL 끝에 pgbouncer=true 추가)
DATABASE_URL="postgresql://user:pass@pooler-host:6432/app_db?pgbouncer=true&connection_limit=1"
// 2) Drizzle ORM / postgres.js (prepare 옵션 비활성화)
import postgres from 'postgres';
const client = postgres(process.env.DATABASE_URL!, { prepare: false });
# 3) Python asyncpg (statement_cache_size 0 설정)
conn = await asyncpg.connect(dsn, statement_cache_size=0)
4. 워크로드별 선택 기준과 비용 최적화 체크리스트
인프라 선택은 결국 트래픽 패턴과 팀의 운영 여력에 따라 두 갈래로 나뉩니다. 24시간 일정한 트래픽이 들어오고 이미 AWS VPC 안에서 EC2·ECS를 운영 중이라면 RDS(db.t4g.small 이상)에 자체 PgBouncer 컨테이너를 얹는 구성이 가장 예측 가능한 비용을 보장합니다. 반대로 트래픽이 주간·야간에 크게 출렁이는 서버리스 API나 개발·스테이징 환경을 자주 띄우는 팀이라면 Scale-to-Zero와 내장 풀러를 제공하는 Neon이나 Supabase가 초기 인프라 구축 비용과 유지보수 시간을 크게 줄여줍니다.
- 커넥션 수 계산:
default_pool_size는 DB vCPU 수 × 2~4 범위(예: 2 vCPU면 15~25개)로 낮게 잡고, 대기열은max_client_conn으로 받아냅니다. - 타임아웃 설정: PgBouncer 앞단에서
query_wait_timeout = 15(초)를 걸어 장시간 멈춘 쿼리가 전체 풀을 마비시키지 않게 차단합니다. - 비용 재점검: RDS Proxy 월 비용($22+)이 부담된다면 소형 EC2나 기존 ECS 클러스터에 PgBouncer를 사이드카로 띄워 프록시 비용을 0원으로 만들 수 있습니다.

