| 항목 | MySQL | PostgreSQL |
|---|---|---|
| 프로세스 모델 | 스레드 기반 (단일 프로세스 + 멀티 스레드) | 프로세스 기반 (커넥션당 fork) |
| 커넥션 비용 | 가벼움 | 무거움 → PgBouncer 필수 |
| 기본 max_connections | 151 | 100 |
| 스토리지 엔진 | 플러그인 방식 (InnoDB, MyISAM 등) | 단일 통합 엔진 |
MySQL — 스레드 기반
[ 생성 ]
pthread_create() → 새 스레드 생성
- 스택만 할당
- 프로세스 메모리 공유
- 수십 μs
[ 메모리 ]
스레드 1개 ≈ 256KB ~ 1MB
- 스택 + thread-local 변수
- Buffer Pool, 카탈로그는 공유
[ 단점 ]
- 격리 부족: 한 스레드 메모리 violation → mysqld 전체 죽음
- 동시성 제어 복잡: 메모리 공유로 mutex/lock 곳곳에 필요
PostgreSQL — 프로세스 기반
[ 생성 ]
fork() → 새 프로세스 생성
- 페이지 테이블 복사 + PCB 생성
- 수 ms
[ 메모리 ]
backend 1개 ≈ 10MB
- 별도 프로세스라 공유 안 됨
- work_mem, 카탈로그 캐시 각자 보유
[ 단점 ]
- 연결 생성 비용 큼 (fork 자체가 무거움)
- 연결당 메모리 사용량 큼 → PgBouncer 필요한 이유
역할: 영구 연결을 임시 연결처럼 동작시키는 매칭 브로커 → backend 프로세스 수 축소로 자원 절감
Before (PgBouncer 없이)
HikariCP Postgres
conn1 ════════════════ backend #1 (영구 1:1 매칭)
conn2 ════════════════ backend #2
After (PgBouncer 적용)
[HikariCP Conn1] ──TCP A──→ [PgBouncer] ─TCP X─→ [backend #1]
─TCP Y─→ [backend #2]
─TCP Z─→ [backend #3]
↑
트랜잭션마다 매번 다름
HikariCP는 "커넥션 100개"를 들고 있다고 생각하지만, 실제 Postgres backend는 20개만 돌 수도 있음. HikariCP Connection 수 ≠ Postgres backend 수