1.리더와 팔로워
복사본을 저장하는 각 노드를 복제 서버(replica)라 하며
하나는 리더(leader )(마스터나 프라이머리(primary) 라고도 함)
나머지는 팔로워(follower)
(read replica, 슬레이브(slave), secondary, 핫 대기(hot standby) 라고도 함)
쓰기 요청은 오직 리더에게만 가능
-> 리더가 먼저 데이터를 저장
-> 리더는 변경 내용을 복제 로그로 팔로워에게 전송
-> 팔로워는 로그를 받아 리더와 같은 순서로 데이터 반영함
1)동기식 대 비동기식 복제
구분 | 동기식 복제 (Synchronous) | 비동기식 복제 (Asynchronous) |
쓰기 처리 방식 | 리더가 팔로워 응답을 기다림 | 리더가 팔로워 응답을 기다리지 않음 |
속도 | 느릴 수 있음 (팔로워 지연 시 대기) | 빠름 (지연 없이 바로 처리) |
데이터 일관성 | 쓰기 성공 시 팔로워도 최신 상태 보장 | 팔로워는 지연될 수 있음 |
장애 발생 시 | 팔로워에 최신 복사본 존재 보장 가능 | 복제 지연 중이면 데이터 유실 위험 |
단점 | 팔로워 장애 시 전체 시스템 멈춤 위험 | 일관성 낮음, 지속성 보장 안 됨 |
일반 구성 | 1개 팔로워만 동기식, 나머지는 비동기식 → 반동기식(semi-sync) |
전체 비동기식도 가능 (지연 적음) |
활용 상황 | 높은 일관성이 필요한 경우 | 팔로워가 많거나 지리적으로 분산된 경우 |
2)새로운 팔로워 설정
❓ 새로운 팔로워가 리더의 데이터 복제본을 정확히 가지고 있는지 어떻게 보장하지
- 단순한 파일 복사는 일관성 문제 때문에 충분하지 않음
❗아래와 같은 과정 수
특정 시점의 스냅숏(백업)을 생성해 팔로워에 복사
팔로워가 그 이후 변경 사항들(복제 로그)을 리더에게 요청해서 따라잡음
모든 변경을 반영한 뒤부터는 리더를 실시간으로 따라가며 정상 복제가 이뤄짐
3)노드 중단 처리
노드 중단은 예기치 않거나 계획적으로 발생할 수 있음
-> 전체 시스템이 계속 동작하도록 설계하는 것이 중요하다.
a) 팔로워 장애: 따라잡기 복구
팔로워는 리더로부터 수신한 데이터 변경 로그를 로컬 디스크에 보관
->로그를 기반으로 끊긴 시점 이후의 변경만 리더에게 요청
->쉽게 복구가능
팔로워와 달리 리더의 장애를 처리하는 일은 까다로움
- 팔로워 중 하나를 새로운 리더로 승격필요
- 새로운 리더로 쓰기를 전송하기 위해 클라이언트 재설정이 필요
- 다른 팔로워는 새로운 리더로부터 데이터 변경을 소비 시작필요
=> 이 과정을 장애 복구(failover)라 함
failover의 과정
- 리더가 장애인지 판단
- 새로운 리더 선택
- 새로운 리더 사용을 위해 시스템을 재설정
이러한 failover를 수행할 때 주의해야할 점
- 비동기 복제에서는 이전 리더의 일부 쓰기가 새 리더에 반영되지 않아 데이터 유실 위험이 있음
- 복제되지 않은 쓰기를 폐기하면 외부 시스템과 데이터 불일치 가능성 존재
- 스플릿 브레인(split brain):두 노드가 모두 리더라고 착각
->충돌과 데이터 오염 발생 가능 - 장애 감지 타임아웃 설정 시간 고려
-> 너무 길면 복구 지연, 너무 짧으면 불필요한 복구 시도로 오히려 시스템 악화
그래서 자동 복구보다 수동 장애 복구를 선호하기도
4)복제 로그 구현
a) 구문기반 복제
리더가 모든 쓰기 SQL 구문을 기록한
-> 팔로워에게 전달
-> 팔로워는 이를 직접 받은 것처럼 파싱 후 실행
b)WAL(쓰기 전 로그 배송)
완전히 동일한 로그를 사용해 복제 서버를 구축
-> 팔로워가 이 로그를 처리하면서 복제 유지
-> 변경 내용 기록
-> 외부 복제 프로세스 작동
->필요한 로직 적용 후 복제
2.복제 지연 문제
애플리케이션이 비동기 팔로워에서 데이터를 읽을 때
❓팔로워가 뒤쳐지면
= 데이터베이스에 불일치 발생
이러한 복제 지연은 일시적 상태이나
❌실 서비스에 문제가 됨
❓복제지연을 해결할 수 있는 방법
1)자신이 쓴 내용 읽기
사용자가 자신의 페이지를 재로딩했을 때
항상 자신이 제출한 모든 갱신을 볼 수 있음을 보장
-> 다른 사용자에 대해서는 보장하지 않음
❗동일 사용자여도 디바이스 간(cross-device) 일관성이 제공되어야함
2)단조 읽기 (monotonic read)
사용자가 각기 다른 복제 서버에서 여러 읽기를 수행할 때
시간이 거꾸로 흐르는 이상현상을 목격할 수 있음
사용자의 읽기가 항상 동일한 복제 서버에서 수행
= 단조 읽기
즉, 사용자가 읽은 데이터 보다 이전의 데이터을 볼 수 없게 함
3)일관된 순서로 읽기
인과성이 있는 쓰기를 동일한 파티션에 기록
= 모든 사용자는 동일한 순서로 쓰여진 데이터를 보게 됨
3. 다중 리더 복제
지금까지 리더가 하나만 존재하고 모든 쓰기는 해당 리더를 거 쳐야 했음
❓ 리더에 연결할 수 없다면
->쓰기를 허용하는 노드를 하나 이상 두는 것으로 확장
= 다중 리더 설정( 마스터/마스터나 액티브/액티브 복제라고도 함)
1)쓰기 충돌 다루기
한 페이지를 동시에 두 사용자가 편집
-> 각 변경 을 로컬 리더는 성공적으로 적용
-> 변경을 비동기로 복제할 때
-> 쓰기 충돌 감지 (조금 감지가 늦은감이..)
❓충돌 감지를 동기식으로 만들면
쓰기가 성공한 사실을 모든 복제가 복제하기를 기다려야함
다중 리더 복제의 장점 (각 복제가 독립적으로 쓰기를 허용)을 잃음
❓충돌을 회피할 순 없나
특정 레코드의 모든 쓰기가 동일한 리더를 거치도록 함
-> 트래픽 재 라우팅,리더 변경 시 충돌 회피 실패
2)다중 리더 복제 토폴로지
쓰기를 한 노드에서 다른 노드로 전달하는 통신 경로
= 복제 토폴로지
a. 원형(circular): 각 노드가 다음 노드에 전달
b.별모양(star): 루트 노드가 전체 전송
c. 전체 연결(all-to-all): 모든 노드가 서로 연결
4.리더 없는 복제
리더의 개념을 버리고 모든 복제가 쓰기를 받을 수 있게 허용
= 다이나모 스타일
1)노드가 다운 시
리더가 없기때문에 장애복구X
읽기 요청을 병렬로 여러 노드에 전송
-> 응답 중 버전 숫자를 비교해서 가장 최신 값 선택
다운된 노드 복구
- 읽기 복구: 클라이언트가 여러 노드에서 병렬로 읽기를 수행, 오래된 응답을 감지
- 안티 엔트로피 처리: 백그라운드 프로세스를 두고 복제 서버간 차이를 감지
2) 읽기와 쓰기를 위한 정족수
n: 전체 복제 서버 수
w: 쓰기 성공으로 간주하기 위한 응답 수
r: 읽기 성공으로 간주하기 위한 응답 수
일반적 정족수
w + r > n이면 읽기 시 최신 값 보장
→ 최소한r개의 노드 중 하나에서 최신 값을 읽을 수 있기 때문
3)정족수 일관성의 한계
r과 w는 노드의 과반수(n/2)선택
-> n/2 노드 장애까지 허용해도 w+r >n을 보장할 수 있기 때문
w와 r을 너무 작게 잡으면
최신 데이터 노드가 포함되지 않을 가능성이 높아짐
즉,정족수는 최신 값 읽을 확률을 높이는 도구일 뿐
절대적인 보장은 아님
4)느슨한 정족수와 암시된 핸드오프
정족수는 내결함성이 없음
❓네트워크 중단등으로 연결이 끊어지면
-> 노드는 살아 있어도 클라이언트 입장에선 죽은 것처럼 보임
-> 일단 연결할 수 있는 노드에 기록
= 느슨한 정족수(loose quorum)
- 복구 시 원래 노드로 재 전송
= 암시적 핸드오프(hinted handoff)
5. 동시 쓰기 감지
여러 클라이언트가 동시에 같은 키에 쓰기 허용
-> 엄격한 정족수를 사용하더라도 충돌이 발생
ex)네트워크 지연 및 장애로 인해 각 노드에 이벤트가 다른 순서로 도착
단순 덮어쓰기를 하면 복제본 간 영구적인 불일치 발생 가능.
이러한 충돌을 어떻게 다룰 수 있을까?
a) 최종 쓰기 승리(LWW)
“최신” 값을 기준으로 이전 값을 덮어쓰는 방식.
일반적으로 타임스탬프가 큰 값을 선택
쓰기 충돌 시 일부 값이 조용히 무시 → 데이터 손실 가능.
안전하게 사용하려면 키에 고유 ID(UUID)를 부여해 불변성 유지가 필요
b)이전 발생 관계(happens-before)
어떤 쓰기가 먼저 발생했는지를 확인해 동시성 판단
서로 인과성이 없으면 동시 작업으로 간주
ex) 장바구니 물품 담기
c) 동시 쓰기 병합
여러 작업이 동시에 발생
-> 동시에 쓴 값을 합쳐 정리 필요
= 형제(sibling)값
단순한 병합 전략(LWW)은 데이터 손실 초래 가능
삭제 시에는 tombstone(삭제 표시) 필요
자동 병합을 위해 CRDT 같은 구조 사용 가능.
d) 버전 벡터
다중 복제본이 있지만 리더가 없는 경우
다중 복제본의 동시 쓰기
-> 단일 버전 번호로는 부족
-> 복제본별 버전 번호 추적 필요
= 버전 벡터(version vector).
버전 벡터는 쓰기 시 포함되며, 동시성 판단과 병합에 사용됨
'IT것이 알고싶다 > 데이터 중심 애플리케이션 설계' 카테고리의 다른 글
07.트랜잭션 (1) | 2025.05.27 |
---|---|
06.파티셔닝 (2) | 2025.05.13 |
04부호화와 발전 (0) | 2025.05.07 |
03저장소와 검색 (0) | 2025.05.06 |
2장 데이터 모델과 질의 언어 (1) | 2025.04.26 |