본문 바로가기

백엔드

[Primary-Secondary Replication 1] 기본 구조와 읽기 요청 분산

서론

서비스 초기에는 하나의 애플리케이션 서버와 하나의 데이터베이스만으로도 충분할 수 있습니다.

[Client]
    ↓
[Application]
    ↓
[Database]

 

이 구조는 단순합니다.

 

모든 읽기와 쓰기가 하나의 데이터베이스에서 처리되기 때문에 데이터의 현재 상태를 파악하기도 쉽습니다.

하지만 사용자가 늘어나고 요청량이 증가하면 애플리케이션 서버만 확장해서는 해결되지 않는 문제가 나타납니다.

애플리케이션 서버를 여러 대로 늘리더라도 모든 요청이 결국 하나의 데이터베이스로 전달되기 때문입니다.

[Application 1] ─┐
[Application 2] ─┼─→ [Single Database]
[Application 3] ─┘

이 구조에서는 다음 두 가지 문제가 발생할 수 있습니다.

  • 읽기와 쓰기가 동일한 데이터베이스 자원을 경쟁합니다.
  • 하나뿐인 데이터베이스의 장애가 전체 서비스 장애로 이어질 수 있습니다.

이번 글에서는 이러한 문제를 해결하기 위해 사용할 수 있는 Primary-Secondary Replication의 기본 구조와 읽기 요청 분산 방법을 살펴보겠습니다.


1. 읽기와 쓰기가 동일한 자원을 경쟁한다

하나의 데이터베이스가 모든 요청을 처리하면 읽기와 쓰기가 동일한 자원을 함께 사용합니다.

조회 요청은 다음과 같은 자원을 사용합니다.

  • CPU
  • 메모리
  • 디스크 I/O
  • Buffer Cache
  • 데이터베이스 Connection

동시에 주문 생성, 결제 상태 변경, 재고 차감과 같은 쓰기 작업도 동일한 자원을 사용합니다.

따라서 읽기 요청이 급격하게 증가하면 쓰기 성능까지 영향을 받을 수 있습니다.

 

반대로 대규모 쓰기 작업이 발생하면 조회 응답 시간이 느려질 수 있습니다.

 

물론 데이터베이스를 여러 대로 늘리기 전에 다음과 같은 최적화를 먼저 수행해야 합니다.

  • 불필요한 쿼리 제거
  • 적절한 인덱스 구성
  • Connection Pool 조정
  • 반복 조회에 대한 캐시 적용
  • 데이터베이스 자원 증설

이번 글에서는 이러한 기본적인 최적화를 모두 수행했지만, 여전히 읽기 부하가 과도한 상황이라고 가정하겠습니다.


2. 단일 데이터베이스는 SPOF가 될 수 있다

애플리케이션 서버를 여러 대 운영하더라도 데이터베이스가 하나라면 데이터베이스 장애가 전체 서비스 장애로 이어질 수 있습니다.

[Application 1] ─┐
[Application 2] ─┼─→ [Single Database]
[Application 3] ─┘

애플리케이션 서버가 정상적으로 동작하고 있어도 데이터베이스에 접근할 수 없다면 정상적인 서비스를 제공할 수 없습니다.

이처럼 특정 구성 요소 하나의 장애가 전체 시스템 장애로 이어질 수 있는 지점을 SPOF, 즉 Single Point of Failure라고 합니다.

 

따라서 다음 두 가지 질문을 해결해야 합니다.

  1. 증가하는 읽기 요청을 어떻게 분산할 것인가?
  2. 현재 데이터베이스가 장애를 일으켰을 때 어떻게 서비스를 복구할 것인가?

이 두 문제를 해결하기 위해 데이터베이스를 여러 대로 구성하는 방식을 검토할 수 있습니다.

그중 가장 먼저 고려할 수 있는 구조가 Primary-Secondary Replication입니다.


3. Primary-Secondary Replication이란

Primary-Secondary Replication은 하나의 Primary가 쓰기를 담당하고, 하나 이상의 Secondary가 Primary의 변경을 전달받아 자신의 데이터에 반영하는 구조입니다.

                    ┌───────────────┐
                    │  Secondary 1  │
                    │  read / apply │
                    └───────▲───────┘
                            │
[Client] → [Primary] ───────┼── Replication Log
           write / commit   │
                    ┌───────▼───────┐
                    │  Secondary 2  │
                    │  read / apply │
                    └───────────────┘

 

정상 상태에서는 Primary 하나만 쓰기를 승인합니다.

 

Secondary는 Primary에서 발생한 변경을 전달받아 자신의 데이터에 적용합니다.

데이터베이스 제품에 따라 Replication에 사용하는 로그의 이름은 다를 수 있습니다.

  • MySQL: binlog
  • PostgreSQL: WAL

구현 방식과 설정에는 차이가 있지만, 기본 원리는 동일합니다.

 

정상 상태에서는 하나의 데이터베이스만 쓰기를 승인하고, 나머지 데이터베이스는 그 변경을 따라간다.

 

Secondary를 읽기 요청에 활용하면 Primary의 읽기 부하를 줄일 수 있습니다.

또한 Primary에 장애가 발생하면 Secondary 하나를 새로운 Primary로 전환하여 서비스를 복구할 수 있습니다.

 

다만 데이터베이스를 여러 대로 구성했다고 해서 읽기 확장과 장애 대응이 자동으로 해결되는 것은 아닙니다.

 

다음과 같은 질문에 답할 수 있어야 합니다.

  • 쓰기 직후 Secondary에서 조회하면 최신 데이터가 보이는가?
  • 어떤 읽기 요청을 Primary에서 처리해야 하는가?
  • 어떤 읽기 요청을 Secondary로 보내도 되는가?
  • Secondary가 Primary보다 뒤처진 상태라면 어떻게 처리해야 하는가?
  • Primary 장애 시 어떤 Secondary를 새로운 Primary로 선택해야 하는가?

이번 글에서는 이 중 읽기 요청 분산에 집중하겠습니다.


4. Primary와 Secondary의 역할

Primary-Secondary 구조에서는 일반적으로 Primary가 쓰기 요청을 담당합니다.

클라이언트의 다음 요청은 Primary로 전달됩니다.

  • INSERT
  • UPDATE
  • DELETE

Primary는 트랜잭션을 실행하고, 변경 내용을 Replication에 사용할 수 있는 로그로 기록합니다.

Secondary는 해당 로그를 전달받아 자신의 데이터에 적용합니다.

Client
   │
   │ INSERT / UPDATE / DELETE
   ▼
Primary
   │
   │ Replication Log
   ▼
Secondary

 

Primary만 쓰기를 처리하도록 제한하는 이유는 쓰기 순서를 하나의 노드에서 결정하기 위해서입니다.

 

여러 데이터베이스가 서로 조정하지 않고 동일한 데이터에 쓰기를 수행하면 변경 순서와 최종 상태를 결정하기 어려워질 수 있습니다.

Primary-Secondary 구조는 정상 상태의 쓰기 권한을 Primary 하나에 두어 이러한 문제를 피합니다.

 

Secondary는 일반적으로 다음 역할을 담당합니다.

  • Primary의 변경 사항 유지
  • 읽기 요청 처리
  • 리포트 및 통계성 조회 처리
  • Primary 장애 시 Promotion 후보

Secondary를 추가하는 목적은 모든 읽기를 강제로 Secondary로 보내는 것이 아니라, 지연을 허용할 수 있는 읽기를 분리하여 Primary의 부하를 줄이는 것입니다.

그러므로 Primary와 Secondary는 역할이 다르지만, Primary에서 읽기가 불가능한 것은 아닙니다.


5. 쓰기 요청은 어떻게 처리되는가

쓰기 요청의 개념적인 흐름은 다음과 같습니다.

1. Client가 쓰기 요청을 보낸다.
2. Primary가 트랜잭션을 실행한다.
3. 변경 내용이 Primary의 Replication Log에 기록된다.
4. 설정된 완료 조건을 만족하면 Client에 성공을 반환한다.
5. Secondary가 Replication Log를 수신한다.
6. Secondary가 로그를 자신의 데이터에 적용한다.

 

이를 그림으로 표현하면 다음과 같습니다.

Client         Primary               Secondary
   │              │                       │
   │── write ────▶│                       │
   │              │── transaction         │
   │              │── log record          │
   │◀── success ──│                       │
   │              │── Replication Log ───▶│
   │              │                       │── apply

 

여기서 중요한 부분은 Primary가 성공을 반환하는 시점과 Secondary가 변경을 적용하는 시점이 반드시 같지는 않다는 점입니다.

 

애플리케이션이 받은 쓰기 성공은 설정에 따라 다음 중 하나를 의미할 수 있습니다.

  • Primary에만 변경이 기록됨
  • Secondary 변경 로그 수신
  • Secondary 로그 저장
  • Secondary에서 로그를 실제 데이터에 적용

어느 단계까지 완료되어야 성공을 반환할지는 Replication 방식과 설정에 따라 달라집니다.

 

이에 대한 자세한 내용은 다음 글에서 동기 Replication과 비동기 Replication을 비교하며 살펴보겠습니다.

 

이번 글에서 기억해야 할 핵심 포인트는 다음과 같습니다.

Primary에서 쓰기가 성공했다고 해서 모든 Secondary의 조회 결과에도 즉시 반영되었다고 볼 수는 없다.

6. 읽기 요청은 어디에서 처리할 것인가

읽기 요청은 Primary와 Secondary 모두에서 처리할 수 있습니다.

다만 모든 읽기를 Secondary로 보내면 최신 변경이 아직 반영되지 않은 데이터를 조회할 수 있습니다.

반대로 모든 읽기를 Primary로 보내면 Secondary를 구성한 읽기 확장 효과가 사라집니다.

 

따라서 읽기 요청의 특성에 따라 경로를 구분해야 합니다.

최신성이 중요한 읽기
Client → Primary

일정 수준의 지연을 허용하는 읽기
Client → Secondary

 

예를 들어 다음과 같은 데이터는 짧은 지연을 허용할 수 있습니다.

  • 상품 설명
  • 게시글 목록
  • 과거 주문 내역
  • 추천 후보
  • 통계성 데이터
  • 인기 콘텐츠
  • 실시간성이 낮은 대시보드

이러한 읽기는 Primary의 변경 사항이 Secondary에 조금 늦게 반영되더라도 서비스의 정상적인 동작에 큰 영향을 주지 않을 수 있습니다.

따라서 Secondary로 분산하기에 적합합니다.

 

반면 다음 데이터는 오래된 상태를 기준으로 후속 작업을 수행하면 업무 오류로 이어질 수 있습니다.

  • 현재 재고
  • 결제 상태
  • 계좌 잔액
  • 사용자 권한
  • 예약 가능 수량
  • 중복 요청 처리 여부
  • 상태 전이 가능 여부

이러한 데이터는 Primary에서 조회하거나, 필요한 변경 사항을 충분히 반영한 Secondary에서만 조회해야 합니다.

 

중요한 점은 데이터의 종류만으로 읽기 경로를 정할 수 없다는 것입니다.

같은 데이터라도 어떤 유스케이스에서 사용하는지에 따라 최신성 요구가 달라질 수 있습니다.

 

예를 들어 과거 주문 목록은 Secondary에서 조회해도 될 수 있습니다.

하지만 주문 생성 직후 생성된 주문이 정상적으로 저장되었는지 확인하는 화면은 Primary에서 조회해야 할 수 있습니다.


7. Replication Lag은 왜 발생하는가

Primary와 Secondary의 데이터는 항상 같은 순간에 변경되지 않습니다.

Primary에서 변경이 커밋된 후 Secondary의 조회에 반영되기까지 여러 단계를 거칩니다.

Primary에서 트랜잭션 Commit
        ↓
Replication Log 전송
        ↓
Secondary가 로그 수신
        ↓
Secondary가 로그 저장
        ↓
Secondary가 로그를 데이터에 적용
        ↓
Secondary의 조회 결과에 변경이 표시됨

 

Primary에서 변경이 완료된 시점과 Secondary에서 해당 변경을 확인할 수 있는 시점 사이의 차이를 Replication Lag이라고 합니다.

 

Replication Lag은 다음과 같은 원인으로 증가할 수 있습니다.

  • Primary와 Secondary 사이의 네트워크 지연
  • Secondary의 디스크 I/O 부족
  • Secondary의 CPU 부족
  • 대량의 쓰기 작업
  • Secondary에서 실행되는 무거운 조회
  • 로그 적용 과정의 오류 또는 대기
  • 긴 트랜잭션이나 Recovery 충돌

Secondary가 정상적으로 연결되어 있다고 해서 항상 Primary와 동일한 상태라는 의미는 아닙니다.

각 Secondary의 처리 성능과 상태에 따라 반영된 로그 위치가 다를 수 있습니다.

Primary      : W1, W2, W3, W4
Secondary A  : W1, W2, W3
Secondary B  : W1, W2

 

이 상황에서 Secondary A와 Secondary B는 모두 정상적으로 동작하고 있을 수 있지만, 두 Secondary에서 조회되는 데이터는 서로 다를 수 있습니다.

그러므로 읽기 요청을 단순히 아무 Secondary에나 전달해서는 안 됩니다.

해당 읽기에 필요한 데이터 반영 수준과 Secondary의 Replication 상태를 함께 고려해야 합니다.


8. Stale Read란

Secondary에 Primary의 최신 변경이 아직 반영되지 않은 상태에서 조회하면 이전 데이터가 반환될 수 있습니다.

이를 Stale Read라고 합니다.

 

사용자가 배송지를 A에서 B로 변경했다고 가정하겠습니다.

1. 배송지 변경 요청이 Primary에서 Commit된다.
2. Primary가 Client에 성공을 반환한다.
3. 애플리케이션이 사용자 정보를 Secondary에서 조회한다.
4. Secondary에는 아직 배송지 변경이 적용되지 않았다.
5. 화면에 이전 배송지 A가 표시된다.

 

쓰기 자체는 성공했지만 사용자는 자신의 변경이 반영되지 않은 것처럼 느낄 수 있습니다.

Client         Primary               Secondary
   │              │                       │
   │── A → B ────▶│                       │
   │              │── commit              │
   │◀── success ──│                       │
   │                                      │
   │──────────── read ───────────────────▶│
   │◀────────── address: A ───────────────│

 

애플리케이션 입장에서는 데이터베이스가 잘못된 것이 아닙니다.

Primary에는 배송지 B가 정상적으로 저장되어 있고, Secondary가 아직 해당 변경을 따라가지 못한 상태입니다.

 

하지만 사용자는 내부 구조를 알지 못합니다.

이처럼 성공 메시지를 받았지만 여전히 이전 값이 표시된다면 사용자는 변경 작업이 실패했다고 판단할 수 있습니다.


9. Read-After-Write Consistency

사용자가 쓰기를 수행한 뒤 자신의 변경 결과를 다음 읽기에서 확인할 수 있도록 하는 성질을 Read-After-Write Consistency라고 합니다.

 

모든 읽기에서 항상 최신 상태를 요구하는 것은 아닙니다.

하지만 사용자가 직접 변경한 데이터를 바로 다시 확인하는 상황에서는 Read-After-Write Consistency가 중요한 경우가 많습니다.

 

대표적인 예는 다음과 같습니다.

  • 프로필 수정 후 프로필 화면 조회
  • 배송지 변경 후 주문 정보 조회
  • 게시글 작성 후 게시글 상세 조회
  • 댓글 등록 후 댓글 목록 조회
  • 주문 생성 후 주문 상세 조회

이 문제를 해결하기 위해 모든 읽기를 무조건 Primary로 보낼 수도 있습니다.

그러나 그렇게 하면 Secondary를 이용한 읽기 확장 효과가 사라집니다.

 

따라서 쓰기 직후 읽기와 일반적인 읽기를 구분하는 정책이 필요합니다.


10. 읽기 요청을 분산하는 방법

일정 시간 동안 Primary에서 읽기

쓰기 이후 해당 사용자나 세션의 읽기를 일정 시간 Primary로 보내는 방식입니다.

쓰기 직후
Client → Primary

일정 시간 이후
Client → Secondary

 

이 방법은 구현이 비교적 단순합니다.

 

예를 들어 사용자가 데이터를 수정하면 애플리케이션이 해당 세션에 최근 쓰기 시각을 기록할 수 있습니다.

최근 쓰기 이후 일정 시간이 지나지 않았다면 Primary에서 읽고, 시간이 지난 후에는 Secondary에서 읽습니다.

 

다만 적절한 시간을 결정하기 어렵다는 문제가 있습니다.

 

설정 시간이 실제 Replication Lag보다 짧으면 여전히 Stale Read가 발생할 수 있습니다.

반대로 지나치게 길면 많은 읽기가 Primary에 집중되어 읽기 분산 효과가 감소합니다.


쓰기 위치를 추적한다

쓰기 완료 시 해당 변경의 Replication Log 위치를 기록하고, 그 위치까지 적용한 Secondary만 읽기 대상으로 선택하는 방식입니다.

쓰기 완료 위치: W100

Secondary A 적용 위치: W105
→ 읽기 가능

Secondary B 적용 위치: W97
→ 아직 읽기 불가

 

일정 시간 동안 Primary에서 읽는 방법보다 정확하게 최신성을 판단할 수 있습니다.

다만 애플리케이션이나 데이터베이스 라우팅 계층이 다음 정보를 처리할 수 있어야 합니다.

  • 쓰기가 완료된 로그 위치
  • Secondary별 로그 수신 위치
  • Secondary별 로그 적용 위치
  • 요청이 요구하는 최소 로그 위치

구현 복잡도는 높지만 Replication Lag이 일정하지 않은 환경에서 더 정확한 제어가 가능합니다.


업무별로 읽기 경로를 고정한다

유스케이스별로 최신성 요구를 정의하고 읽기 경로를 고정하는 방식입니다.

예를 들면 다음과 같습니다.

상품 목록 조회
→ Secondary

상품 설명 조회
→ Secondary

주문 생성 직후 주문 상세 조회
→ Primary

과거 주문 목록 조회
→ Secondary

결제 상태를 기준으로 후속 처리
→ Primary

현재 재고를 기준으로 주문 가능 여부 확인
→ Primary

 

이 방식은 데이터 자체보다 해당 조회가 어떤 업무 판단에 사용되는지를 기준으로 경로를 결정합니다.

 

예를 들어 상품 재고는 단순 화면 표시와 실제 주문 가능 여부 판단에서 요구되는 최신성이 다를 수 있습니다.

상품 화면의 참고용 재고 표시
→ 짧은 지연을 허용할 수 있다면 Secondary

주문 생성 전 실제 재고 검증
→ Primary

 

업무별 읽기 경로를 명확하게 정하면 애플리케이션 코드에서도 데이터 일관성 요구를 드러낼 수 있습니다.


Lag이 큰 Secondary를 읽기 대상에서 제외한다

Secondary의 Replication Lag이 정해진 기준을 초과하면 읽기 대상에서 제외하는 방법도 사용할 수 있습니다.

Secondary A Lag: 100ms
→ 읽기 대상 포함

Secondary B Lag: 8초
→ 읽기 대상 제외

이를 위해서는 Secondary별 Replication 상태를 지속적으로 관찰해야 합니다.

단순히 데이터베이스 연결이 살아 있는지만 확인해서는 부족합니다.

연결은 정상이어도 로그 적용이 크게 뒤처질 수 있기 때문입니다.

 

다음과 같은 정보를 함께 확인해야 합니다.

  • 마지막으로 수신한 로그 위치
  • 마지막으로 저장한 로그 위치
  • 마지막으로 적용한 로그 위치
  • 현재 Replication Lag
  • 로그 적용 오류 여부

다만 Lag 기준만으로 모든 읽기 요청의 안전성을 판단할 수는 없습니다.

허용 가능한 지연은 업무마다 다르기 때문입니다.

 

게시글 목록에서는 2초의 지연이 허용될 수 있지만, 결제 상태 조회에서는 허용되지 않을 수 있습니다.

 

따라서 Lag 기준과 업무별 최신성 요구를 함께 사용해야 합니다.


11. Secondary가 추가되어도 읽기가 자동으로 분산되지는 않는다

Primary-Secondary 구조를 구성했다고 해서 애플리케이션의 읽기 요청이 자동으로 Secondary에 전달되는 것은 아닙니다.

애플리케이션이나 데이터베이스 접근 계층에서 읽기 경로를 구분해야 합니다.

 

예를 들어 다음과 같은 구성이 필요할 수 있습니다.

[Application]
    │
    ├─ Write DataSource ─→ Primary
    │
    └─ Read DataSource ──→ Secondary

 

애플리케이션에서 다음과 같은 정책을 정의해야 합니다.

  • 쓰기는 항상 Primary로 보낸다.
  • 최신성이 중요한 읽기는 Primary로 보낸다.
  • 지연을 허용할 수 있는 읽기는 Secondary로 보낸다.
  • Secondary의 Lag이 기준을 초과하면 읽기 대상에서 제외한다.
  • Secondary 읽기가 실패하면 Primary로 전환할지 결정한다.
  • 쓰기 직후의 읽기는 별도의 정책으로 처리한다.

트랜잭션 안에서 수행되는 조회도 주의해야 합니다.

Primary에서 데이터를 변경한 뒤 같은 트랜잭션 흐름에서 Secondary를 조회하면 변경 전 데이터가 반환될 수 있습니다.

따라서 하나의 업무 처리 안에서 최신 변경을 기준으로 판단해야 한다면 읽기와 쓰기를 모두 Primary에서 처리하는 것이 안전할 수 있습니다.

 

그러므로 읽기 분산은 해당 조회 결과가 이후 업무에 어떤 영향을 주는지까지 고려해서 처리해야 합니다.


12. Primary-Secondary가 읽기 확장에 적합한 이유

Secondary를 추가하면 지연을 허용할 수 있는 읽기 요청을 여러 데이터베이스에 분산할 수 있습니다.

                          ┌─→ [Secondary 1]
[Client] → [Application] ─┼─→ [Secondary 2]
                          └─→ [Secondary 3]

쓰기 요청
[Client] → [Application] ───→ [Primary]

 

리포트, 통계, 검색, 목록 조회와 같은 읽기 중심 기능을 Secondary로 분리하면 Primary가 쓰기 트랜잭션을 처리하는 데 더 많은 자원을 사용할 수 있습니다.

하지만 Secondary 수를 늘린다고 해서 읽기 성능이 무조건 비례해서 증가하는 것은 아닙니다.

Secondary에서도 읽기 작업과 Replication Log 적용이 동일한 자원을 사용할 수 있기 때문입니다.

Secondary에서 매우 무거운 조회를 실행하면 다음 문제가 발생할 수 있습니다.

  • CPU 사용량 증가
  • 디스크 I/O 증가
  • Buffer Cache 경쟁
  • Replication Log 적용 지연
  • Replication Lag 증가
  • 더 오래된 데이터 조회

즉, Secondary는 Primary의 부담을 줄이기 위한 자원이지만 무제한으로 사용할 수 있는 자원은 아닙니다.

Secondary의 읽기 부하와 Replication 처리 상태도 함께 관찰해야 합니다.


마무리

Primary-Secondary Replication은 하나의 Primary가 쓰기를 담당하고, 하나 이상의 Secondary가 Primary의 변경을 따라가는 구조입니다.

 

정상 상태에서의 역할은 다음과 같이 정리할 수 있습니다.

Primary
→ 쓰기 처리
→ 최신성이 중요한 읽기 처리
→ Replication Log 생성

Secondary
→ Primary의 변경 사항 적용
→ 지연을 허용할 수 있는 읽기 처리
→ Primary 장애 시 Promotion 후보

 

Secondary를 읽기 요청에 활용하면 Primary의 읽기 부하를 줄일 수 있습니다.

 

하지만 Primary에서 성공한 변경이 모든 Secondary에 즉시 반영되는 것은 아닙니다.

Primary의 변경이 Secondary의 조회 결과에 표시되기까지 Replication Lag이 발생할 수 있으며, 이로 인해 Stale Read가 발생할 수 있습니다.

 

따라서 읽기 요청은 다음과 같이 구분해야 합니다.

지연을 허용할 수 있는 읽기
→ Secondary

최신 상태가 중요한 읽기
→ Primary 또는 필요한 위치까지 따라온 Secondary

쓰기 직후 읽기
→ Primary 또는 쓰기 위치를 반영한 Secondary

 

결국 Primary-Secondary를 이용한 읽기 확장의 핵심은 Secondary의 수를 늘리는 것이 아닙니다.

각 읽기 요청이 어느 정도의 데이터 지연을 허용할 수 있는지 판단하고, 그 기준에 따라 읽기 경로를 설계하는 것입니다.

 

이번 글에서는 Primary-Secondary Replication의 기본 구조와 읽기 요청 분산 방법을 살펴보았습니다.

 

하지만 아직 중요한 질문이 남아 있습니다.

Primary가 클라이언트에 쓰기 성공을 반환했을 때 Secondary는 해당 변경을 어디까지 처리한 상태인가?

 

다음 글에서는 동기 Replication과 비동기 Replication을 비교하고, PostgreSQL의 synchronous_commit 설정을 통해 쓰기 성공이 의미하는 보장 범위를 살펴보겠습니다.