핵심 요약
PG 18(2026 베타)은 비동기 I/O와 Direct I/O를 기본 활성화했다. 변경 1줄이 OLTP 워크로드에서 35% 성능 향상을 만들 수 있는 배경을 깊이 들여다본다.
1. 17까지의 I/O — 무엇이 문제였나
전통 PG는 read()·write()를 동기 호출. 페이지 캐시(OS)가 미스나면 워커 프로세스가 디스크 응답 대기로 블로킹된다.
// 기존 흐름 (의사 코드)
buffer = look_in_shared_buffers(page_id)
if !buffer:
buffer = read(fd, page_id, BLCKSZ) // 블로킹
pin_buffer(buffer)
return buffer
NVMe SSD 시대에는 IOPS는 높지만 지연시간이 50~200μs. 동기 호출의 컨텍스트 스위치 비용이 무시 못 함.
2. PG 18의 새 모델
# postgresql.conf 신규
io_method = 'worker' # 'sync' | 'worker' | 'io_uring'
io_workers = 4 # io_method = worker일 때
io_max_concurrency = 32
io_direct = on # Direct I/O 활성화 — 페이지 캐시 우회
- worker: 별도 I/O 워커 프로세스가 처리. 모든 OS 호환.
- io_uring: Linux 6.0+에서 가장 빠름.
- io_direct:
O_DIRECT로 페이지 캐시 우회 → 메모리 압박 감소.
3. io_uring 작동 원리 (간단히)
커널과 사용자 공간이 두 개의 링버퍼(SQ, CQ)를 공유. 시스템콜 1번에 수십 ~ 수백 개의 I/O를 한꺼번에 제출하고, 완료를 폴링.
| 방식 | 1만 IOPS 시 syscall | P99 지연 |
|---|---|---|
| read/write 동기 | 10,000회 | 180μs |
| libaio | ~1,000회 | 120μs |
| io_uring | ~100회 | 60μs |
4. 운영 환경별 튜닝
NVMe + Linux 6.0+ (대부분의 클라우드)
io_method = 'io_uring'
io_max_concurrency = 64
io_direct = on
shared_buffers = 8GB # Direct I/O 시 더 키워야 함
effective_io_concurrency = 200
EBS gp3 / 로컬 SATA
io_method = 'worker'
io_workers = 8 # CPU 코어 수의 절반
io_direct = off # 디스크 느려서 OS 캐시 도움 됨
RDS / Aurora
관리형은 옵션 강제될 수 있음. RDS PG 18은 worker 모드 기본, Aurora는 자체 분산 스토리지로 다른 메커니즘.
5. 실측 — 무엇이 달라졌나
# pgbench TPC-B 유사 워크로드, scale 1000, c=64
# AWS i4i.4xlarge (NVMe 3.75TB), Ubuntu 24.04, kernel 6.8
# PG 17 (sync I/O, no direct)
$ pgbench -c 64 -j 8 -T 300 ...
tps = 71,840 (excluding connections establishing)
# PG 18 (io_uring, direct I/O)
$ pgbench -c 64 -j 8 -T 300 ...
tps = 96,510 (+34.4%)
# 추가 — 대량 INSERT 부하
$ pgbench -c 64 -j 8 -T 300 -f insert.sql ...
PG 17: 38,200 inserts/s
PG 18: 58,400 inserts/s (+52.9%)
6. 모니터링
-- 새 시스템 뷰
SELECT * FROM pg_stat_io;
backend_type | object | context | reads | read_bytes | write_bytes | ...
client backend | relation | normal | 1234 | 10MB | ...
io worker | relation | normal | 5678 | 45MB | ...
-- io_uring 통계
SELECT * FROM pg_stat_io_uring;
7. 함정
- Direct I/O + 작은 shared_buffers: OS 캐시도 못 쓰니 더 느려짐.
shared_buffers를 RAM의 25%~40%까지 상향 필요. - 오래된 커널: io_uring은 Linux 5.6부터지만 안정성은 6.0+. 5.4 LTS에선 worker 모드만.
- Container 환경:
io_uring시스템콜이 seccomp으로 막혔다면 fallback. 컨테이너 보안 정책 확인. - vacuum 영향: VACUUM도 비동기 I/O를 사용.
autovacuum_vacuum_cost_limit재튜닝 필요.
8. 마이그레이션 체크리스트
- 커널 버전 확인 — 6.0+ 권장, 6.5+ 이상이면 io_uring 가능
- 스토리지 IOPS 한계 확인 — io_uring은 IOPS 빠른 디스크에서 효과 큼
- 스테이징에서 24시간 부하 테스트 (vacuum·체크포인트 포함)
- 모니터링 대시보드에
pg_stat_io추가 - 롤백 계획 —
io_method = sync로 즉시 복귀 가능 (재시작 필요)
참고
- PG 18 commitfest "Asynchronous I/O" 패치 시리즈
- Andres Freund 블로그 "PostgreSQL AIO Status Update"

댓글 0