4.4 동기/비동기 commit
PostgreSQL의 commit이 얼마나 안전해야 하는지는 synchronous_commit 파라미터로 조절합니다. WAL fsync를 commit 응답 전에 기다릴 것인가, 안 기다릴 것인가의 트레이드오프입니다. 클러스터 차원의 기본부터 트랜잭션별 오버라이드까지 제어가 세밀합니다.
값과 의미
| 값 | commit 응답 시점 |
|---|---|
on (기본) | 로컬 WAL fsync 완료 후 |
local | 로컬 fsync 완료 후. 동기 복제 표준에서 standby 응답은 안 기다림 |
remote_write | 로컬 fsync + standby의 WAL receive (디스크 안 기다림) |
remote_apply | 로컬 fsync + standby가 적용까지 완료 |
off | 로컬 WAL이 아직 메모리에 있을 때 응답 — fsync는 백그라운드에서 |
on과 off의 차이가 가장 크고, local·remote_*는 복제 환경에서 의미가 있습니다.
synchronous_commit = on vs off
on (기본)
sequenceDiagram
participant Client
participant Backend
participant WAL
Client->>Backend: COMMIT
Backend->>WAL: WAL record + fsync 요청
WAL-->>Backend: fsync OK
Backend-->>Client: COMMIT (응답)
- 디스크에 들어간 commit만 “성공"으로 인정
- crash 시 직전 commit은 안전하게 살아남음
- commit latency = WAL fsync 비용
off
sequenceDiagram
participant Client
participant Backend
participant WALMem as WAL buffer
participant WALDisk as pg_wal
Client->>Backend: COMMIT
Backend->>WALMem: WAL record (메모리만)
Backend-->>Client: COMMIT (즉시 응답)
Note over WALMem,WALDisk: 다음 walwriter cycle에서<br/>일괄 fsync (기본 200ms 내외)
- commit이 매우 빠름 (fsync 대기 없음)
- crash 시 마지막 200ms 정도의 commit 손실 가능
- 단, 데이터베이스 일관성은 깨지지 않음 — “이미 완료됐다고 말한 트랜잭션이 사라질 뿐”
사고 모델
| 사고 | on | off |
|---|---|---|
| PostgreSQL backend crash | 응답한 commit 모두 살아남음 | 응답한 commit 일부 손실 |
| 호스트 power off / kernel panic | 응답한 commit 모두 살아남음 | 응답한 commit 일부 손실 |
| 디스크 손상 (storage 측) | data_checksums + backup으로 복구 | 같음 |
일관성(constraint·FK·serializability)은 off에서도 깨지지 않습니다. 다만 클라이언트가 “성공"으로 보고받은 트랜잭션이 crash 후 없어질 수 있다는 점이 다릅니다.
트랜잭션 단위 오버라이드
전체를 on으로 두되, 로그성 데이터처럼 손실 허용 가능한 트랜잭션만 off로 풀 수 있습니다.
-- 한 트랜잭션만 비동기 commit
BEGIN;
SET LOCAL synchronous_commit = off;
INSERT INTO event_log(...) VALUES (...);
COMMIT; -- 빠르게 응답또는 세션 단위:
SET synchronous_commit = off;
-- 이 세션의 모든 commit이 비동기이 패턴이 운영의 정석입니다. 민감한 데이터는 안전, 손실 허용 가능한 데이터만 빠르게.
복제 환경의 local / remote_*
synchronous_standby_names 파라미터로 동기 복제 대상을 정한 경우, 다음 의미가 추가됩니다.
| 값 | 의미 (동기 복제 활성 시) |
|---|---|
local | primary의 디스크 fsync만 기다림. standby는 무시 |
on | primary fsync + 동기 standby의 flush까지 |
remote_write | primary fsync + 동기 standby의 receive까지 (디스크 안 기다림) |
remote_apply | primary fsync + 동기 standby가 WAL을 적용해 query에서도 보일 때까지 |
운영 트레이드오프:
flowchart LR
L["local<br/>가장 빠름"] --> O["on<br/>표준"] --> RW["remote_write"] --> RA["remote_apply<br/>가장 강함, 느림"]
classDef fast fill:#d1fae5,stroke:#047857,color:#064e3b
classDef mid fill:#fef3c7,stroke:#b45309,color:#78350f
classDef strong fill:#fed7aa,stroke:#c2410c,color:#7c2d12
class L fast
class O mid
class RW,RA strong
대부분 동기 복제는 on 또는 remote_write로 운영합니다. remote_apply는 복제 지연 없이 standby에서 같은 결과를 봐야 하는 매우 엄격한 시나리오에서만.
관련 fsync 옵션
| 파라미터 | 기본 | 의미 |
|---|---|---|
fsync | on | 마스터 스위치. off는 절대 금지 — 데이터 손상 가능 |
synchronous_commit | on | 위 표 |
wal_sync_method | OS별 자동 | fdatasync/fsync/open_datasync/open_sync 등. 보통 기본값으로 충분 |
commit_delay | 0 | μs. 여러 commit을 묶어 한 번에 fsync (group commit). 매우 높은 TPS에서만 의미 |
commit_siblings | 5 | commit_delay가 작동할 최소 동시 트랜잭션 수 |
fsync = off는 어떤 상황에서도 운영 금지. 약간의 성능 이득이 있지만 power-off 시 클러스터 자체가 깨질 수 있습니다. “검증 환경이라 잠깐만” 같은 사용도 사고로 이어진 사례가 많습니다.TPS 영향 — 간단한 수치 감
synchronous_commit = on 환경에서 commit latency는 보통 storage의 fsync 지연에 좌우됩니다.
| 스토리지 | 대략적인 fsync 지연 |
|---|---|
| 로컬 NVMe SSD | |
| 데이터센터 SATA SSD | |
| 네트워크 SSD (EBS gp3) | |
| HDD |
OLTP TPS는 single-thread commit 기준 1 / fsync_latency 가까이로 묶입니다. 여러 backend가 동시에 commit해도 WAL fsync는 직렬화되는 경우가 많아서 같은 지연이 모두에게 영향.
synchronous_commit = off로 풀면 이 직렬화가 사라져 TPS가 수배~수십 배 증가 가능합니다. 단, 위에서 본 손실 위험과 짝입니다.
진단
-- commit 지연 추적
SELECT mean_exec_time, calls, query
FROM pg_stat_statements
WHERE query ILIKE 'commit%'
ORDER BY mean_exec_time DESC
LIMIT 5;
-- WAL fsync 통계 (PG 14+)
SELECT * FROM pg_stat_wal;pg_stat_wal의 wal_sync_time / wal_sync로 평균 fsync 지연 추정 가능합니다.
흔한 안티패턴
| 패턴 | 문제 |
|---|---|
synchronous_commit = off 클러스터 디폴트로 | 결제·금융 등 손실이 절대 안 되는 트랜잭션도 비동기 |
fsync = off | 절대 금지 (위 callout) |
commit_delay 무리하게 큼 | latency 증가가 처리량 증가보다 큼 |
| 동기 복제 대상이 1개뿐이고 standby가 자주 끊김 | primary commit이 영원히 멈춤 |
synchronous_standby_names = 'ANY 2 (s1, s2, s3)'로 3대 중 2대 응답을 받는 식이 표준입니다. 1대만 동기로 두면 그 1대가 죽을 때 primary가 멈춥니다.정리
synchronous_commit = on(기본) = 안전, commit latency = WAL fsync 비용off로 풀면 빠르지만 직전 ~200ms commit 손실 가능합니다. 일관성은 유지- 트랜잭션 단위
SET LOCAL로 부분 비동기 운영이 정석 - 복제 환경에서는
local/on/remote_write/remote_apply단계 선택 fsync = off는 어떤 경우에도 금지- 동기 복제 대상은 quorum(2 of 3 등)으로 정상 운영 보장
다음 절(4.5)에서는 PostgreSQL의 디스크 위치 분할에 쓰는 tablespace를 봅니다.