티스토리 뷰

카테고리 없음

DDIA 3주차

changha. 2026. 6. 19. 23:27

이번 주차는 꽤 재밌는 5장, 복제이다. 

여기부터 본격적인 분산환경에서 발생하는 문제들을 다루고 해결책을 설명한다. 

 

복제가 필요한 이유

  1. 지연 시간 감소 - 데이터를 사용자와 지리적으로 가깝게 둔다.
  2. 내결함성 - 일부 노드가 고장 나도 시스템이 계속 동작하도록 한다.  
  3. 확장성 - 읽기 질의를 처리하는 장비 수를 늘려 확장한다. 

데이터가 안 변하면 복제는 그냥 한 번 복사하면 끝이다. 

복제가 어려운 건 변경을 어떻게 전파하느냐의 문제가 있기 때문이다. 

문제와 해결

오래된 값일 때 어떻게 해야될까?

문제는 리더의 변경이 팔로워에 즉시 도달하지 않는다는 데 있다. 리더에 쓴 내용이 팔로워에 반영되기까지의 시간차를 복제 지연이라 한다.


이 시스템이 보장하는 것은 최종적 일관성 뿐이다. 쓰기를 멈추면 팔로워들은 언젠가는 리더를 따라잡지만, 그 갭이 생각보다 클 수도 있다.

 

아래 세 가지 문제는 모두 이 복제 지연 하나에서 갈라져 나온다. 각각이 깨뜨리는 보장이 다르고, 그래서 해결책도 다르다.

 

🚨 문제 1 - 내가 방금 쓴 글이 새로고침하니까 사라졌다.

 

상황: 사용자가 자신의 프로필을 수정(리더에 쓰기)하고 즉시 새로고침(팔로워에서 읽기)을 한다. 하지만 팔로워에 아직 변경사항이 반영되지 않아 사용자는 수정전의 옛날 정보를 본다. 

해결책: 쓰기 후 읽기 일관성 

방법 1 - 사용자가 수정한 내용을 읽을 때는 리더에서 읽는다. 

보통 마이페이지나 프로필 정보는 소유자만 읽는다. 

항상 사용자 프로필은 리더에서 읽고 다른 사용자의 프로필은 팔로워에서 읽는 방식.

 

방법 2 - 마지막 갱신 시각을 찾아서 마지막 갱신 후 1분 동안은 리더에서 모든 읽기 수행.

팔로워에서는 복제 지연을 모니터링해서 리더보다 1분 이상 늦은 모든 팔로워에 대한 질의를 금지한다. 

 

방법 3 - 복제 서버가 아직 최신이 아니면 다른 복제 서버가 읽기를 처리한다. 또는 복제 서버가 따라잡을 때까지 질의 대기.

클라이언트는 가장 최근 타임스탬프 기억 가능하다. 시스템은 사용자 읽기를 위한 복제 서버가 최소한 해당 타임스탬프까지 갱신을 반영하게 할 수 있다. 

 

 

🚨 문제 2 - 시간이 거꾸로 흘러간다. 

 

상황: 사용자가 페이지를 여러 번 새로고침한다. 첫 읽기는 빠른 팔로워 A에 도달해 최신 글을 봤는데, 두 번째 읽기는 느린 팔로워 B에 도달해 다시 옛날 상태로 돌아간다. 사용자 눈에는 시간이 거꾸로 가는 것처럼 보인다.

 

문제 1과 달리, 여기서 깨지는 건 "내가 쓴 것"이 아니라 읽기들 사이의 시간 순서다.

해결책: 단조 읽기

한 번 최신 데이터를 본 사용자는, 그 뒤로 더 오래된 데이터를 보지 않도록 보장한다. (시간이 뒤로 가지 않게) 

 

방법 - 각 사용자의 읽기가 항상 동일한 복제 서버에서 수행되게 한다.

사용자 ID의 해시를 기반으로 복제 서버를 고정한다. 

 

🚨 문제 3 - 답변이 질문보다 먼저 올라왔다. 

상황: 데이터가 여러 샤드에 나뉘어 저장돼 있다. A가 질문을 쓰고, B가 그에 답변을 단다. 그런데 관찰자에게는 B의 답변이 담긴 샤드가 먼저 복제되고 A의 질문이 담긴 샤드가 나중에 복제되어, 답변이 질문보다 먼저 보인다.

 

질문과 답변 사이에 인과성이 있는데, 그 인과 순서가 뒤집힌 것이다. (샤드별로 복제 지연이 달라 생기는 문제)

해결책: 일관된 순서로 쓰기 

인과성이 있는 쓰기들은 항상 쓰여진 순서대로 읽히도록 보장한다. 

 

방법 - 서로 인과관계가 있는 쓰기는 동일한 샤드에 기록되게 한다. 

이렇게 하면 한 샤드 안에서는 순서가 보존되므로 역전이 일어나지 않는다.

한 샤드로 들어온다는 것 : 단일 리더 + 순서 로그 + 순차 적용

 

정리


느낀점 

회사에서도 단일 DB로 이루어진것이 아니라 read/write DB로 이루어져있다. 

과거 단일 DB로 했던 적이 있는데, 이 때 SPOF문제로 DDos로 DB CPU가 치솟았을 때 웹서버까지 장애가 전파됐었다. 

read/write의 구분은 readOnly 트랜잭션은 조회 전용 DB로 보내서 구분하고 있다. 

 

그러면 동기 or 비동기 중에 무엇을 택했나 하면 비동기 방식을 택했다. (유저 알람 배치 복제 지연 개선)

다만 비동기는 복제 지연이 생기게 되는데, 실제로 지연이 7~8초로 터졌었다. 

이를 해결하기 위해 쓰기 배치 단위를 작게 쪼개고, Insert/Update를 별도 Kafka 토픽으로 비동기 2단계 분리 하였다. 

복제 지연 목표는 1~2초 이내였다. 

 

현재 문제가 없냐 하면 아니다. 

비동기 2단계 분리를 하였다고했는데 Insert(알림 저장), Update(뱃지 카운트) 부분에서 새로운 정합성 문제를 만들게 된다. 

뱃지 숫자와 실제 알림이 안 맞는 구간이 생길 수 있다. 

예를 들어, 알림 목록엔 떴는데 뱃지는 아직 0, 또는 반대. 이 부분이 위에서 기술한 인과성 문제랑 일치하는 것 같다. (알림 생성 -> 뱃지 증가)

다만 이정도는 허용가능한 불일치라서 진행했을 것 같다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함