명령어/DB

[PostgreSQL] 동기 복제로 커밋 무손실을 보장한다 — standby가 받았다고 확인해야 커밋 완료

jykim23 2026. 7. 22. 23:10
반응형

설치·접속: PostgreSQL 설치와 접속

부제: 결제 승인·정산 원장처럼 한 건이라도 잃으면 안 되는 트랜잭션인데, 기본 스트리밍 복제는 비동기라 primary가 죽으면 아직 안 넘어간 커밋이 사라질 때

-- 처음엔 비동기(기본값). standby가 받기 전에 primary가 죽으면 그 커밋은 유실될 수 있다.
SELECT application_name, state, sync_state FROM pg_stat_replication;

-- standby가 WAL을 받았다고 확인해야만 COMMIT을 반환하도록 바꾼다
ALTER SYSTEM SET synchronous_standby_names = '*';
SELECT pg_reload_conf();

SELECT application_name, state, sync_state FROM pg_stat_replication;
-- 설정 전 (비동기)
 application_name | state     | sync_state
------------------+-----------+------------
 walreceiver      | streaming | async

-- pg_reload_conf() 후 (동기)
 application_name | state     | sync_state
------------------+-----------+------------
 walreceiver      | streaming | sync

기본 스트리밍 복제는 비동기다. primary는 자기 WAL만 디스크에 쓰면 곧바로 COMMIT을 반환하고, standby로 보내는 건 그다음이다. 처리량은 좋지만 primary가 그 순간 죽으면 아직 전송되지 않은 커밋은 그대로 증발한다. 결제 승인이나 정산 원장처럼 한 건 유실이 곧 돈·분쟁으로 이어지는 트랜잭션에서는 이 창(window)을 없애야 한다. synchronous_standby_names에 대상 standby를 등록하고 reload하면 sync_stateasync에서 sync로 바뀐다. 이제 primary는 그 standby가 WAL을 받았다고 확인(ack)하기 전까지 COMMIT을 클라이언트에 돌려주지 않는다. 즉 커밋이 성공했다면 그 데이터는 최소 두 노드에 존재한다는 게 보장된다. 대가는 지연이다. 매 커밋마다 네트워크 왕복이 붙으므로 primary가 혼자 결정할 때보다 응답이 느려진다. 함정은 동기 standby가 하나뿐인데 그게 멈추면 primary의 커밋이 ack를 기다리며 통째로 멈춘다는 점 — 그래서 실무에선 동기 후보를 2대 이상 두고 정족수(ANY N)로 여유를 준다.

이렇게도 쓴다

synchronous_commit 레벨로 "어디까지 확인하면 커밋으로 볼지"를 조절한다. 강할수록 안전하고 느리다.

-- remote_write : standby OS까지 도달(디스크 flush는 안 기다림) — 가장 가벼운 동기
-- on(기본)     : standby가 WAL을 디스크에 flush할 때까지 대기
-- remote_apply : standby가 그 변경을 redo까지 적용 → 직후 standby 읽기에서 즉시 보임
SET synchronous_commit = 'remote_apply';
SHOW synchronous_commit;
 synchronous_commit
--------------------
 remote_apply

 

동기 후보 여러 대 중 N대만 ack하면 커밋으로 인정하는 정족수 방식. 한 대가 죽어도 나머지로 커밋이 진행된다. (조합: ANY quorum)

ALTER SYSTEM SET synchronous_standby_names = 'ANY 1 (s1, s2)';
SELECT pg_reload_conf();
-- pg_stat_replication.sync_state 가 sync 대신 quorum 으로 표시된다
 application_name | sync_state
------------------+------------
 walreceiver      | quorum

 

우선순위 방식. 나열 순서대로 앞쪽 standby가 동기, 나머지는 대기(potential)로 승격 대비.

ALTER SYSTEM SET synchronous_standby_names = 'FIRST 2 (s1, s2, s3)';
SELECT pg_reload_conf();

 

특정 트랜잭션만 동기로, 나머지는 빠른 비동기로 섞어 쓴다. 세션/트랜잭션 단위로 껐다 켤 수 있다. (조합: per-transaction)

-- 로그성 쓰기는 비동기로 빠르게
SET synchronous_commit = off;
-- 결제 확정만 강하게
BEGIN; SET LOCAL synchronous_commit = remote_apply;
INSERT INTO payments(...) VALUES (...);
COMMIT;

 

지금 어떤 standby가 동기 대상이고 얼마나 밀렸는지 실시간 확인. (조합: 지연 모니터링)

SELECT application_name, sync_state,
       write_lag, flush_lag, replay_lag
FROM pg_stat_replication;

 

동기 standby가 없을 때의 행동을 정한다. 기본은 "standby 나타날 때까지 커밋 대기"이므로, 가용성이 더 중요하면 후보를 늘려 대기를 피한다.

-- synchronous_standby_names 를 비우면 즉시 비동기로 회귀(가용성 우선)
ALTER SYSTEM SET synchronous_standby_names = '';
SELECT pg_reload_conf();
반응형