콘텐츠로 이동

Replication Lag and Read Consistency

Source가 쓰기를 처리하고 Replica가 읽기를 분담하는 비동기 복제 환경에서는, 커밋 성공 이후에도 Replica별로 해당 쓰기의 반영 시점이 다를 수 있다.

  • 최종 일관성 (Eventual Consistency)의 보장: 새로운 쓰기가 멈추고 복제가 정상적으로 진행되면 복제본들이 결국 같은 상태로 수렴
  • 보장하지 않는 범위: 자신의 쓰기가 직후 조회에 보이는지와 이전 조회보다 과거 상태를 읽지 않는지

애플리케이션에서 허용하지 않을 현상에 맞춰 필요한 읽기 보장을 선택한다.

읽기 보장방지하는 현상
Read Your Writes내가 쓴 댓글이 직후 조회에서 보이지 않음
Monotonic Reads한 번 읽은 댓글이 과거 상태로 돌아가 사라짐

자신의 쓰기 읽기는 같은 세션에서 성공한 쓰기가 이후 자신의 읽기에 반영되도록 하는 보장이다.

  • 보장 대상: 같은 세션에서 자신이 수행한 쓰기
  • 보장 범위 밖: 다른 사용자가 쓴 데이터까지 항상 최신 상태로 읽는 것

댓글 저장 요청이 끝난 뒤, 별도의 댓글 조회 요청이 들어온 상황을 가정한다. Source에는 댓글이 저장되어 있지만 Replica에는 아직 반영되지 않았다.

두 방식의 차이는 이후 조회 요청을 어디서 처리하느냐에 있다. 그림의 1번과 2번은 서로 다른 사용자 요청을 나타낸다.

Source에는 이미 댓글이 있으므로 Replica의 반영을 기다릴 필요가 없이 댓글을 바로 조회할 수 있다.

sequenceDiagram
participant A as 애플리케이션
participant S as Source
Note over A,S: 1. 댓글 저장 요청
A ->> S: 댓글 저장
S -->> A: 커밋 성공
Note over A,S: 저장 응답 반환 · 요청 종료
Note over A,S: 2. 이후 댓글 조회 요청
A ->> S: 댓글 조회
S -->> A: 작성한 댓글 반환
  • 읽기 위치: Source
  • 대기 대상: Replica 반영 대기 없음
  • 비용: 쓰기 직후의 읽기까지 Source에 집중
  • 댓글 저장 요청: Source의 커밋 성공 응답에서 쓰기 식별자를 받아 사용자 세션에 보관하고, 사용자에게 저장 성공 응답
  • 이후 댓글 조회 요청: 읽을 Replica를 선택하고, 보관한 식별자로 해당 쓰기의 반영을 확인한 뒤 댓글 조회
sequenceDiagram
participant A as 애플리케이션
participant S as Source
participant R as Replica
Note over A,S: 1. 댓글 저장 요청
A ->> S: 댓글 저장
S -->> A: 커밋 성공 + w42(해당 쓰기를 가리키는 설명용 식별자)
Note over A,S: w42 보관 · 저장 요청 종료
Note over A,R: 2. 이후 댓글 조회 요청
A ->> R: w42 반영 확인 SQL
S -) R: w42 비동기 복제
R ->> R: 댓글 반영
R -->> A: 확인 SQL 성공 반환
A ->> R: 댓글 조회 SQL
R -->> A: 작성한 댓글 반환

반영 확인 SQL은 w42가 적용될 때까지 반환을 기다리며, 복제는 그동안 별도로 진행된다. (이미 반영된 상태라면 즉시 성공을 반환)

  • 읽기 위치: w42 적용을 확인한 Replica
  • 대기 시점: 저장 요청이 끝난 뒤 들어온 조회 요청에서, 댓글 조회 SQL을 실행하기 전
  • 대기 대상: 해당 쓰기의 적용 완료
  • 비용: Replica가 뒤처진 만큼 조회 응답이 늦어질 수 있음
  • 대기 시간 초과: 해당 쓰기를 보존한 Source로 우회하거나 요청을 실패 처리

MySQL에서는 GTID (Global Transaction Identifier)가 쓰기 식별자 역할을 한다. GTID 대기 동작 흐름

단조 읽기는 같은 세션에서 한 번 읽은 상태보다 과거의 상태를 다음 조회에서 반환하지 않도록 하는 보장이다.

  • 보장 대상: 자신이 쓴 데이터뿐 아니라 다른 사람이 쓴 데이터를 읽은 경우도 포함
  • 읽기 기준: 이미 관측한 변경 이력을 유지하거나 더 새로운 상태를 읽음 (매번 가장 최신 상태를 읽어야 하는 것은 아님)

복제본 변경으로 읽기가 후퇴하는 경우

섹션 제목: “복제본 변경으로 읽기가 후퇴하는 경우”

다른 사람이 작성한 댓글을 두 번 조회하는 상황을 가정한다.

sequenceDiagram
participant C as 애플리케이션
participant A as Replica A
participant B as Replica B
Note over C,A: 1. 첫 번째 댓글 조회 요청
C ->> A: 댓글 조회
A -->> C: 댓글 있음
Note over C,B: 2. 다음 댓글 조회 요청
C ->> B: 댓글 조회
B -->> C: 댓글 없음
Note over C: 과거 상태를 반환
  • 첫 조회에서 댓글을 봤지만, 다음 조회가 뒤처진 Replica B로 가면서 댓글 생성 전의 상태를 반환
  • 이처럼 읽기 대상이 바뀌어 이미 관측한 변경을 잃는 현상 방지 필요
댓글이 사라진 이유상태 변화단조 읽기 위반
댓글 생성 전의 Replica 상태를 읽음과거로 후퇴해당
이후 실제 삭제가 커밋되어 반영됨더 새로운 변경을 관측해당하지 않음

첫 조회를 Replica A에서 처리했다면 다음 조회도 A로 보낸다.

  • 라우팅 예시: 사용자 ID의 해시로 대상 Replica를 정해 같은 사용자의 조회를 같은 서버에 전달
  • 보장 조건: 해당 Replica의 읽기 상태 자체가 후퇴하지 않아야 함. 오래된 트랜잭션 스냅샷을 재사용하는 경우도 확인 필요
  • 한계: 장애나 증설로 대상이 B로 바뀌면 B가 이전 관측 상태를 포함하는지 추가 확인 필요

이전 읽기의 버전을 보관하고 다음 조회에서 확인

섹션 제목: “이전 읽기의 버전을 보관하고 다음 조회에서 확인”

Replica가 바뀌어도 보장을 유지하려면, 백엔드가 이전 조회에서 읽은 버전을 사용자 세션에 보관한다.

  • 버전 10: 변경 1~10까지 반영한 상태. 첫 조회에서 댓글을 읽음
  • 버전 8: 변경 1~8까지만 반영한 상태. 첫 조회에서 본 댓글이 아직 없음
  • 다음 조회의 최소 기준: 버전 10. 버전 8인 Replica에서는 그대로 조회하지 않음

다음 조회에서는 그 버전 이상을 읽을 수 있는 Replica를 선택하거나 해당 버전까지 반영될 때까지 기다린다.

sequenceDiagram
participant C as 애플리케이션
participant A as Replica A
participant B as Replica B
Note over C,A: 1. 첫 번째 댓글 조회 요청
C ->> A: 댓글 조회
A -->> C: 댓글 + 읽기 버전 10
Note over C,A: 기준 10 보관 · 요청 종료
Note over C,B: 2. 다음 댓글 조회 요청
C ->> B: 버전 10 반영 확인
Note over B: 현재 버전 8
B ->> B: 비동기 복제로 10까지 반영
B -->> C: 반영 확인 성공
C ->> B: 댓글 조회
B -->> C: 댓글 + 읽기 버전 10

서비스에서 허용하지 않을 현상에 맞춰 읽기 경로가 확인할 이력을 정한다.

방법적용하기 좋은 요구조건과 비용
쓰기 직후 Source 읽기자신의 쓰기 읽기Source 읽기 부하 증가. 스냅샷과 장애 전환 후 쓰기 보존 여부 확인 필요
같은 Replica로 라우팅복제본 이동으로 인한 읽기 후퇴 방지Replica 자체의 상태가 후퇴하지 않아야 하며, 대상 변경 시 추가 검증 필요
쓰기·읽기 토큰으로 적용 대기자신의 쓰기 읽기, 단조 읽기버전 정보와 세션 상태 관리 필요. 복제 지연만큼 대기 가능

조건을 만족하는 서버가 없을 때의 처리도 정해야 한다.

  • 대기: 대상 Replica가 필요한 쓰기를 적용할 때까지 대기
  • 우회: 같은 조건을 만족하는 다른 서버에서 조회
  • 실패: 제한 시간 안에 보장할 수 없다면 요청을 실패 처리

두 보장은 자신의 쓰기 반영과 이전에 읽은 상태의 유지에 대한 조건이다. 다음 개념과는 구분해야 한다.

개념두 읽기 보장과의 구분
최신성데이터가 얼마나 최근 상태인지를 판단한다. 오래된 Replica도 자신의 쓰기를 반영하고 이전에 읽은 상태보다 후퇴하지 않으면 두 보장을 만족할 수 있다. 반대로 한 번 최신 데이터를 읽었어도 다음에 후퇴하면 단조 읽기 위반이다.
선형성 (Linearizability)완료된 연산의 실시간 선후관계를 지킨다. 두 보장만으로 모든 읽기가 실시간으로 가장 최근에 완료된 쓰기를 반영하지는 않는다.
트랜잭션 격리 수준동시 실행되는 트랜잭션 사이에서 어떤 변경이 보이는지를 다룬다. REPEATABLE READ만으로 서로 다른 Replica에 걸친 요청의 단조 읽기가 제공되지는 않는다.

마지막 업데이트:

Large-Scale System