556. 마스터-슬레이브 복제 지연 (Replication Lag) 불일치 이슈

⚠️ 이 문서는 고가용성과 읽기 분산(Read Scale-out)을 위해 데이터베이스를 쓰기용 마스터(Master)와 읽기용 슬레이브(Slave)로 분리했을 때 필연적으로 발생하는, 마스터의 데이터 변경 사항이 슬레이브로 복제되는 데 걸리는 시차(Lag)로 인해 사용자가 방금 수정한 자신의 정보를 조회하지 못하는 불일치 현상과 그 극복망을 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 마스터 DB에서 쿼리가 성공적으로 끝났더라도(Commit), 그 트랜잭션 로그(Binlog)를 슬레이브 DB가 가져가서 자신의 디스크에 다시 쓰기(Replay) 전까지 존재하는 수 밀리초~수 초의 비동기적 물리적 시간차다.
  2. 가치: 이 지연을 방치하면 쇼핑몰 고객이 결제를 끝내고 '내 주문 내역'을 새로고침 했는데 빈 화면이 보이는 최악의 사용자 경험(UX)과 신뢰도 하락이 발생한다.
  3. 기술 체계: 이를 막기 위해 내가 쓴 데이터는 무조건 마스터에서 다시 읽어오게 하는 'Read-Your-Own-Writes' 패턴, 최신 데이터 캐싱, 또는 반동기(Semi-Sync) 복제 방식 등을 워크로드 특성에 맞게 적용해야 한다.

Ⅰ. 복제 지연(Replication Lag)의 발생 원리

마스터와 슬레이브는 탯줄로 연결된 일심동체가 아니다.

  1. 비동기 복제 (Asynchronous Replication):
    • 대부분의 RDBMS 복제는 속도를 위해 비동기 방식을 쓴다.
    • 마스터 DB는 클라이언트의 쓰기(Insert/Update) 요청을 받으면 자신의 디스크에 로그를 쓰고 "성공!"이라고 클라이언트에게 즉시 응답을 보낸다. (슬레이브가 잘 받았는지 기다리지 않음)
  2. 슬레이브의 Replay 병목:
    • 슬레이브는 마스터가 남겨둔 바이너리 로그(Binlog)를 네트워크를 통해 가져와서(I/O 스레드), 자신의 DB 엔진에 순서대로 다시 실행(SQL 스레드)한다.
    • 마스터는 수십 개의 스레드가 동시다발적으로 쓰는 반면, 과거 슬레이브의 SQL 스레드는 단일 스레드(싱글 스레드)로 동작하는 경우가 많아 병목(Lag)이 생기곤 했다. (현재는 Multi-Threaded Replication 지원)
  3. 읽기 불일치 (Inconsistency):
    • 클라이언트는 쓰기 성공을 확인하고 0.1초 만에 화면을 새로고침하며 슬레이브 DB(읽기 전용)에 쿼리를 날린다.
    • 하지만 슬레이브는 아직 마스터의 로그를 복사해 오지 못한 상태라 과거의 옛날 데이터를 반환하게 된다.

📢 섹션 요약 비유: 본점(Master)에서 가격표를 바꾸고 "수정 완료!"라고 선언했지만, 알바생(네트워크)이 자전거를 타고 분점(Slave)으로 달려가 가격표를 바꿔 달기 전(Lag)에 분점에 손님이 들어오면 옛날 가격을 부르게 되는 난처한 상황입니다.


Ⅱ. 복제 지연을 숨기는 아키텍처적 극복 방안

디스크 복제 속도를 물리적으로 0으로 만들 수는 없으므로 우회 전술을 쓴다.

  1. Read-Your-Own-Writes (내가 쓴 것은 내가 읽기):
    • 가장 확실하고 많이 쓰이는 패턴이다.
    • 사용자가 프로필을 '수정(Write)'하면, 애플리케이션 서버가 이 사용자의 세션(또는 쿠키)에 타임스탬프를 남긴다. 이후 일정 시간(예: 3초) 동안 이 사용자가 자신의 프로필을 '조회(Read)'할 때는, 슬레이브 DB가 아닌 마스터 DB로 강제 라우팅시켜 무조건 최신 데이터를 보게 한다.
    • 다른 사용자들의 프로필은 여전히 슬레이브에서 읽으므로 전체 부하 분산(Scale-out) 효과는 유지된다.
  2. 캐시 (Cache) 활용 전술:
    • 데이터베이스 업데이트와 동시에 Redis 같은 인메모리 캐시에도 바뀐 데이터를 업데이트한다.
    • 조회가 들어오면 DB(슬레이브)가 아닌 캐시에서 먼저 데이터를 읽어오게 하므로, 복제 지연이 있더라도 캐시의 최신 데이터로 덮어버릴 수 있다.

📢 섹션 요약 비유: 분점의 가격표가 아직 안 바뀌었을까 봐 불안하다면, 방금 본점에 전화해서 가격을 바꾼(Write) 손님 본인이 가격을 물어볼 때만 본점 사장님(Master)이 직접 응대하게 하고, 나머지 일반 손님들은 그대로 분점 직원(Slave)이 응대하게 하는 맞춤형 고객 센터와 같습니다.


Ⅲ. 동기식 복제로의 전환과 트레이드오프

완벽한 일치를 원한다면 속도와 가용성을 포기해야 한다.

  1. 반동기 복제 (Semi-Synchronous Replication):
    • 마스터가 "성공!"이라고 응답하기 전에, 최소 1대의 슬레이브가 "나도 마스터 로그를 안전하게 내려받았어(Relay Log 기록 완료)"라고 응답할 때까지 마스터가 기다려주는 방식이다.
    • 장점: 슬레이브로의 복사가 무조건 보장되므로 데이터 유실 위험이 급감한다.
    • 단점: 슬레이브가 응답할 때까지 마스터가 멈춰 있어야 하므로, 클라이언트가 체감하는 전체 쓰기(Write) 속도가 눈에 띄게 느려진다.
  2. 다중 마스터 또는 분산 합의 (Galera Cluster, Paxos/Raft):
    • MySQL Galera Cluster나 분산 DB들은 모든 노드가 동기화될 때까지 엄격한 합의(Quorum)를 거치도록 설계된다. 하지만 이 역시 3대 중 2대가 동의할 때까지 기다려야 하는 엄청난 레이턴시(지연 시간)가 발생한다.
    • 아키텍처의 결론: 완벽한 동기화는 느리다. 대부분의 인터넷 서비스(SNS, 쇼핑몰)는 약간의 지연(Eventual Consistency)을 감수하더라도 빠른 비동기 복제를 채택하고, 애플리케이션 단(캐시, 라우팅)에서 불일치를 숨기는 것이 정석이다.

📢 섹션 요약 비유: 완벽하게 가격표를 맞추고 싶다면 본점 사장님이 분점에 심부름을 보낸 뒤, 알바생이 "분점 가격표 뗐습니다!"라고 무전을 쳐줄 때까지 다음 손님을 아예 안 받고 기다리면(동기 복제) 됩니다. 하지만 이렇게 장사하면 줄이 너무 길어지기 때문에(성능 저하), 보통은 약간의 불일치를 감수하는 쪽을 택합니다.