#8 - PgBouncer 실전 운영 챕터 - Spring Boot 읽기·쓰기 분리 전략
중년개발자
@loxo
16일 전
PgBouncer 실전 운영 챕터
Master / Replica 분리, DNS 설계, Spring Boot 읽기·쓰기 분리 전략
0. 이 챕터의 전제 (중요)
이 문서는 PgBouncer 공식 문서의 동작 원리를 기반으로,
- PostgreSQL Master / Replica 구조
- DNS 또는 엔드포인트 분리
- PgBouncer
databases섹션 설계 - Spring Boot 입장에서의 쓰기 / 읽기 분리 전략
을 실제 운영에서 가장 많이 쓰이는 방식으로 정리한 실전 가이드다.
목표는 "개념 설명"이 아니라 운영자가 그대로 가져다 쓸 수 있는 설정이다.
1. PostgreSQL Master / Replica 구조 복습
PostgreSQL 자체는 Read / Write 분리를 자동으로 해주지 않는다.
- Write → 반드시 Master
- Read → Replica 여러 대로 분산 가능
따라서 분리는 반드시 애플리케이션 또는 미들웨어 계층에서 수행해야 한다.
2. PgBouncer의 핵심 한계 (중요한 오해 정리)
PgBouncer는:
- ❌ SQL을 파싱해서 읽기/쓰기를 구분하지 않는다
- ❌ SELECT 를 자동으로 Replica 로 보내주지 않는다
PgBouncer는 오직:
"어떤 접속 엔드포인트(alias) 로 들어왔는가"만 본다
👉 읽기/쓰기 분리는 접속 단에서 이미 결정되어 있어야 한다
이 점이 실전 설계의 출발점이다.
3. 실전 표준 아키텍처 (DNS + PgBouncer)
핵심 설계 포인트
-
PgBouncer 인스턴스는 논리적으로 2개
- write 전용
- read 전용
-
실제로는 같은 서버 / 같은 프로세스여도 무방
-
DNS 또는 Service 이름으로 역할을 분리
4. pgbouncer.ini 실전 구성 (Master / Replica 분리)
4.1 databases 섹션 – 핵심 중의 핵심
[databases]
# Write 전용 (Master)
mydb_write = host=pg-master.mydb.internal port=5432 dbname=mydb
# Read 전용 (Replica Pool)
mydb_read = host=pg-replica.mydb.internal port=5432 dbname=mydb중요한 포인트
-
pg-replica.mydb.internal은:- DNS Round Robin
- 또는 L4/L7 Load Balancer
- 또는 Cloud Provider Read Endpoint
-
PgBouncer는 Replica 개수를 모른다
-
단지 "이 host 로 연결한다"고만 이해한다
4.2 PgBouncer 공통 설정 (실전 표준)
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 5000
default_pool_size = 100
reserve_pool_size = 20
server_idle_timeout = 60
server_lifetime = 3600
logfile = /var/log/pgbouncer/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid5. userlist.txt 실전 운영 방식
PgBouncer는 PostgreSQL 자체 인증을 하지 않는다.
userlist.txt만 신뢰- 이 파일은 PostgreSQL 에서 SELECT 로 생성해야 한다
5.1 userlist.txt 형식
"app_user" "SCRAM-SHA-256$..."
5.2 운영 패턴 (권장)
- PostgreSQL 에서 사용자/비밀번호 관리
pg_authid또는pg_shadow조회- 스크립트로
userlist.txt생성 - PgBouncer reload
👉 인증의 단일 진실 소스는 PostgreSQL
6. Spring Boot 입장에서의 읽기 / 쓰기 분리
6.1 가장 중요한 사실
Spring Boot는:
- ❌ PgBouncer에게 읽기/쓰기를 맡기지 않는다
- ✅ DataSource 를 분리해서 직접 제어한다
6.2 실전 표준: DataSource 2개
spring:
datasource:
write:
url: jdbc:postgresql://pgbouncer-write.mydb.internal:6432/mydb
username: app_user
password: ********
read:
url: jdbc:postgresql://pgbouncer-read.mydb.internal:6432/mydb
username: app_user
password: ********6.3 트랜잭션 라우팅 전략
가장 많이 쓰이는 방식:
@Transactional(readOnly = true)→ Read DataSource- 나머지 → Write DataSource
이 로직은 Spring 레벨에서 결정된다
PgBouncer는 단순히 연결을 효율적으로 관리할 뿐이다.
7. 흔한 실수 TOP 5
- PgBouncer가 SQL을 보고 Replica로 보내줄 거라 착각
- Write / Read 를 같은 엔드포인트로 사용
- Replica 에서 트랜잭션 쓰기 시도
- userlist.txt 수동 편집
- pool_mode = session 사용
8. 운영자 관점 한 줄 요약
PgBouncer는 트래픽을 분산하지 않는다.
PgBouncer는 연결 비용을 줄일 뿐이다.
읽기/쓰기 분리는:
- DNS
- Endpoint
- Application
이 셋 중 하나에서 반드시 명확히 결정되어야 한다.
9. 공식 문서 참고 포인트
- PgBouncer does not do query routing
- Databases section defines logical endpoints
- Pooling happens per database + user
(공식 문서: https://www.pgbouncer.org/usage.html)
마지막 정리 문장
"PgBouncer는 DB 아키텍처를 대신 설계해주지 않는다.
대신, 올바른 설계를 전제로 했을 때 시스템을 버티게 해준다."
목차
- #1 - 처음 만드는 PostgreSQL 프로젝트 DB 생성 및 실행문 까지
- #2 - 실무적인 입장에서 대용량 처리 테이블 생성
- #3 - WSL에서 시작하는 실전 PostgreSQL 17 + Redis 개발환경 구축, 강의용 데이터 구축
- #4 - PostgreSQL WAL · INSERT · SELECT · 디스크 관계 정리
- #5 - PostgreSQL Heap Page(8KB)와 CTID - 이해가 쉬운 설명
- #6 - PostgreSQL VACUUM (배큠) - ‘청소’이자 ‘건강검진’이다.
- #7 - PgBouncer로 이해하는 대규모 PostgreSQL 커넥션 풀링
- #8 - PgBouncer 실전 운영 챕터 - Spring Boot 읽기·쓰기 분리 전략
- #9 - WSL PostgreSQL 17 Master-Replica 구축 가이드