EDB Postgres Distributed에서 발생하는 충돌과 해결 방법 이해하기

작성자: Vaijayanti Bharadwaj | 2025년 7월 18일

EDB Postgres Distributed(PGD)를 사용하는 사용자들은 일반적으로 Raft 알고리즘에 의해 선택된 노드인 write-leader를 통해 데이터베이스에 쓰기 작업을 수행합니다. 지역별 또는 하위 그룹별로 write-leader를 구성하더라도, 각 write-leader는 서로 다른 스키마 또는 테이블에 쓰기를 수행합니다. 그러나 시스템 충돌이나 네트워크 분할로 인해 write-leader가 다른 노드로 전환되면, 데이터 충돌(conflict) 이 발생할 수 있습니다.

이러한 충돌은 정상적인 상황에서는 자주 발생하지 않으며, 자주 발생한다면 PGD 사용 방식에 문제가 있다는 신호일 수 있습니다.

충돌 감지와 해결의 두 가지 측면

충돌은 기본적으로 감지(detection)와 해결(resolution)의 두 단계로 처리됩니다. PGD 문서에는 충돌에 대한 간결하고 포괄적인 요약이 제공되어 있으며, 기본 충돌 해결 방식은 커스터마이징이 가능합니다. 본 블로그에서는 자주 발생하는 충돌 유형과 그 감지 방식 및 기본 해결 방식에 대해 예시와 함께 설명합니다.


1. insert_exists: 동일한 행 중복 삽입 충돌

두 노드가 동일한 행을 삽입하려고 할 때 발생합니다. 이 충돌은 해당 행에 고유 제약 조건(unique constraint) 이 있을 때만 감지됩니다. 최신 커밋 타임스탬프를 가진 삽입이 유지되며, 고유 제약 조건이 없다면 충돌로 간주되지 않고 단순 삽입됩니다.

주의사항: 타임스탬프가 노드 간 다를 경우 최신 행이 과거 행에 의해 덮어씌워질 수 있지만, 모든 노드가 동일한 결정을 내리므로 데이터 분기(divergence)는 발생하지 않습니다.


2. update_origin_change: 다른 노드에서 업데이트된 행 변경

가장 흔하게 발생하는 충돌 유형입니다. 이는 문제가 있는 것은 아니지만, 이해하고 관리할 필요가 있습니다.

  • 정의: 이전 버전의 행이 다른 노드에서 생성되었고, 현재 업데이트는 또 다른 노드에서 발생한 경우 감지됩니다.
  • 일반적으로 고유 제약 조건 또는 기본 키가 있는 테이블에서 발생합니다.
  • write-leader 전환 시 자주 발생합니다.

예시:

  • node1node2가 각각 거의 동시에 트랜잭션 T1, T2를 처리합니다.
  • node2가 T2를 먼저 커밋하고, 이후 node1이 복구되면서 T1을 전파합니다.
  • T2의 값이 <17321, 1200>, T1이 <17321, 1100>일 경우,
  • PGD는 origin이 다름을 감지하고, 타임스탬프를 비교해 마지막 작성자 승(last-writer-wins) 전략을 사용합니다.
  • 이 경우, 업데이트 손실(lost update) 이 발생할 수 있습니다.

주의: 시계 불일치(clock skew)가 있을 경우, 노드 간 다른 결정을 내리게 되어 데이터 분기가 발생할 수 있습니다. 이 문제는 아래 ‘충돌 방지’ 섹션에서 다룹니다.


3. update_missing: 업데이트 대상 행이 누락된 경우

이 충돌은 다음과 같은 다양한 상황에서 발생할 수 있습니다.

① 삽입과 업데이트가 교차

  • node1이 A를 삽입하고 충돌
  • node2가 삽입 후 A를 A1로 업데이트
  • node3이 삽입 전 업데이트를 먼저 수신하면 update_missing 충돌이 발생하고 apply_remote로 upsert 실행
  • 이후 삽입 수신 시에는 insert_exists 충돌이 기록되며 기본 해결은 update_if_newer
  • 시계 불일치가 존재한다면, 더 오래된 삽입이 최신 업데이트를 덮을 수 있어 데이터 분기 발생 가능

② 업데이트와 삭제 교차

  • node1이 A 삭제
  • node2가 A를 A1로 업데이트
  • node1이 업데이트를 받으면 삭제된 행과 비교
    • 삭제된 행을 찾으면 update_recently_deleted로 간주하고 업데이트 무시
  • 못 찾으면 update_missing으로 간주하여 apply_remote → 데이터 분기 가능

③ 고유 제약 조건 없는 테이블에서 발생

  • REPLICA IDENTITY FULL 설정된 테이블에서, 두 노드에서 동일 행을 동시 업데이트
  • 이전 버전이 로컬에서 이미 업데이트되어 존재하지 않음 → update_missing 발생, apply_remote로 처리되어 둘 다 적용됨


4. delete_recently_updated: 최근에 업데이트된 행 삭제 시

  • 삭제 요청의 타임스탬프가 업데이트보다 과거일 경우 발생
  • 기본 해결 방식: 삭제 무시(skip delete)

5. update_pkey_exists: 기본 키 충돌

  • 기본 키가 변경되었는데, 새 기본 키가 이미 다른 노드에 존재할 경우
  • 두 노드에서 기본 키 변경이 교차되었을 때 발생
  • 해결 방식: 최신 타임스탬프 우선 (last-writer-wins)

6. delete_missing: 삭제된 행을 찾을 수 없음

  • 두 노드가 동시에 삭제할 경우 발생
  • 이미 삭제된 행이 재삭제 요청되면 해당 행을 찾을 수 없음 → 무시(skip)

7. multiple_unique_conflicts: 다중 고유 제약 조건 충돌

  • 기본 키가 아닌 인덱스와의 충돌로 발생
  • 충돌하는 두 명령이 같은 행을 참조하지 않을 수 있음
  • 자동 해결이 불가능해 오류(error) 를 발생시켜 사용자가 직접 수동 조치 필요


충돌 방지 전략 (Avoiding Conflicts)

시계 불일치로 인한 충돌은 다음 방법으로 방지할 수 있습니다:

1. 미래 커밋 방지 설정

ALTER SYSTEM SET bdr.maximum_clock_skew = 0;
ALTER SYSTEM SET bdr.maximum_clock_skew_action = 'wait';
SELECT pg_reload_conf();

  • 미래 시점의 커밋은 적용되지 않도록 설정하여, 데이터 분기를 방지합니다.

2. Row-version 기반 충돌 감지 사용

  • REPLICA IDENTITY FULL 설정과 함께 사용 시 시계 불일치로 인한 오탐지와 데이터 분기 없음
  • 여전히 last-writer-wins 전략은 적용되므로, 일부 업데이트 손실 가능성은 존재

마무리: EDB Postgres Distributed에서 데이터 일관성 유지하기

PGD의 설계 철학은 “데이터 일관성 유지”입니다. 충돌이 감지되더라도, 모든 노드가 동일한 결정을 내림으로써 데이터 분기 없이 복제본 간 동기화 상태를 유지합니다. 하지만 write-leader 전환, 시계 불일치, 고유 제약 조건 설정 등에 따라 충돌이 발생할 수 있으며, 이러한 충돌을 정확히 이해하고 대응 전략을 설정하는 것이 중요합니다.

추가적인 커스터마이징이나 예외 처리 로직은 공식 PGD 문서에서 확인하실 수 있습니다.

메일: salesinquiry@enterprisedb.com