MySQL replication lag 가이드: 복제 지연 원인을 가장 빨리 좁히는 순서
DB
마지막 업데이트

MySQL replication lag 가이드: 복제 지연 원인을 가장 빨리 좁히는 순서


MySQL에서 read replica를 붙여 읽기 부하를 분산하면 어느 순간 꼭 마주치는 문제가 replication lag입니다. 쓰기는 이미 source(primary)에 반영됐는데 replica가 아직 따라오지 못해서, 사용자는 방금 저장한 데이터가 안 보이거나 화면마다 다른 결과를 보게 됩니다.

여기서 중요한 건 replication lag를 단순히 “복제가 조금 늦다” 정도로 보면 안 된다는 점입니다. 실제 운영에서는 보통 아래 다섯 가지가 섞여 있습니다.

  • source에서 변경이 너무 많이 발생한다
  • 긴 트랜잭션이나 대량 배치가 한 번에 쏟아진다
  • replica가 조회 트래픽 때문에 apply를 못 따라간다
  • 디스크, I/O, 네트워크 같은 인프라 병목이 있다
  • 애플리케이션이 read-after-write에 민감한 화면까지 replica로 보내고 있다

운영 중이던 서비스에서 “주문했는데 주문 내역에 안 보여요”라는 CS가 하루 20건씩 들어온 적이 있습니다. 원인은 replica lag가 피크 시간에 5~8초까지 벌어지는 건데, 주문 완료 직후 목록 조회가 replica로 가고 있었습니다. 주문 관련 read-after-write를 source로 2초간 고정하니 CS가 거의 사라졌습니다.

그래서 replication lag를 줄이는 가장 빠른 방법은 “복제가 느리다”라고 뭉뚱그리지 않고, 무엇이 replica를 못 따라오게 만드는지 순서대로 분리하는 것입니다.

빠르게 요약하면 이렇습니다.

  1. 지금 lag가 일시적 스파이크인지, 상시 누적형인지 구분합니다.
  2. SHOW REPLICA STATUS\G로 복제 스레드 상태와 최근 에러를 먼저 확인합니다.
  3. source 쪽에서 긴 트랜잭션, 대량 쓰기, 배치 작업이 있었는지 봅니다.
  4. replica가 느린 조회 때문에 apply 시간을 빼앗기고 있지 않은지 확인합니다.
  5. 마지막으로 앱이 어떤 읽기를 replica로 보내는지 라우팅 전략을 점검합니다.

이 글에서는 그 순서를 기준으로 replication lag를 좁히는 방법을 정리하겠습니다.

replication lag는 DB 내부 지표가 아니라 읽기 일관성 문제다

replication lag는 source에 기록된 변경이 replica에서 아직 보이지 않는 시간차입니다. 정의는 단순하지만, 서비스에서 보이는 증상은 꽤 거칠게 나타납니다.

  • 저장 직후 목록에 방금 만든 데이터가 안 보임
  • 상세 화면에서는 수정된 값이 보이는데 목록은 이전 상태임
  • 같은 사용자가 같은 흐름 안에서 서로 다른 결과를 봄
  • 운영자는 “쓰기 성공” 로그를 보는데 고객은 “반영이 안 됐다”고 느낌

즉 이 문제는 단순한 성능 이슈가 아니라 신뢰와 정합성 경험에 직결됩니다. 특히 주문, 결제, 권한, 재고, 프로필 수정처럼 사용자가 “방금 저장했으니 바로 보여야 한다”고 기대하는 화면에서는 몇 초 차이도 매우 크게 느껴집니다.

그래서 replication lag를 볼 때는 “몇 초 늦었나”보다 먼저 어떤 화면과 어떤 흐름이 이 지연에 민감한가를 같이 봐야 합니다.

먼저 일시적 스파이크인지 상시 누적인지 구분하자

lag가 생겼다고 바로 replica 스펙부터 올리면 자주 헛손질하게 됩니다. 먼저 현재 패턴이 무엇인지 나눠보는 편이 훨씬 빠릅니다.

1. 특정 시간대에만 튀는 스파이크형 lag

이 경우는 대개 아래 같은 원인이 많습니다.

  • 정해진 시간에 도는 배치 작업
  • 대량 UPDATE 또는 DELETE
  • 백필, 마이그레이션, 재색인 같은 운영 작업
  • 이벤트나 프로모션 시점의 쓰기 폭증

이 패턴이라면 평소에는 replica가 따라가지만, 특정 순간에만 한꺼번에 밀리는 구조일 가능성이 큽니다.

2. 계속 쌓이는 누적형 lag

이 경우는 replica가 평소에도 충분히 못 따라가고 있다는 뜻입니다.

  • replica 인스턴스 스펙이 workload보다 약함
  • 조회 트래픽이 replica 자원을 지속적으로 잡아먹음
  • 느린 쿼리가 자주 반복됨
  • 디스크 throughput이나 IOPS가 부족함

이 패턴에서는 “피크 때만 느리다”가 아니라, 기본 구조 자체가 빡빡할 가능성이 큽니다.

이 구분 하나만 해도 원인 탐색 범위가 크게 줄어듭니다.

시작은 SHOW REPLICA STATUS\G부터 하는 편이 좋다

원인을 좁힐 때 가장 먼저 볼 만한 기본 명령은 아래입니다.

SHOW REPLICA STATUS\G

MySQL 버전과 설정에 따라 세부 필드는 조금 다를 수 있지만, 운영에서 특히 먼저 보는 항목은 보통 아래와 같습니다.

  • Replica_IO_Running: source에서 로그를 읽어오는 쪽이 정상인지
  • Replica_SQL_Running: replica가 이벤트를 실제로 적용하는 쪽이 정상인지
  • Seconds_Behind_Source: 현재 따라잡지 못한 시간차가 얼마나 되는지
  • Last_SQL_Error: SQL apply 단계에서 에러가 있었는지
  • Relay_Log_Space: relay log가 계속 쌓이고 있는지

여기서 핵심은 숫자 하나만 보지 않는 것입니다.

예를 들어 Seconds_Behind_Source만 보고 “지금은 2초니까 괜찮네”라고 결론 내리면 놓치는 게 많습니다. 실제로는:

  • SQL thread가 멈춰 있어서 아예 적용이 안 되고 있을 수도 있고
  • 특정 대량 트랜잭션 때문에 체감 지연이 더 크게 느껴질 수도 있고
  • critical flow는 2초도 치명적일 수 있습니다

그래서 복제 상태를 볼 때는 스레드가 살아 있는지, 최근 에러가 없는지, relay log가 쌓이는지, 지연이 줄어드는지를 함께 봐야 합니다.

replication lag 뒤에 숨은 대표 원인 네 가지

replication lag는 이름은 하나지만 실제 원인은 꽤 다릅니다. 운영에서는 아래 네 가지 범주로 나눠 보면 정리가 잘 됩니다.

1. source가 replica가 처리할 수 있는 것보다 더 빨리 변경을 만든다

가장 단순한 형태입니다. source에서 binlog가 빠르게 쌓이는데 replica apply 속도가 그만큼 안 나오는 경우입니다.

대표적인 상황은 이렇습니다.

  • 대량 배치가 짧은 시간에 많은 row를 바꿈
  • 한 번의 트랜잭션이 너무 큼
  • 특정 시점에 write QPS가 급증함

이 경우 replica 자체가 고장 난 건 아닐 수 있습니다. 단지 “들어오는 일의 양”이 “처리 가능한 양”보다 순간적으로 많아졌을 뿐입니다. 그래서 이때는 replica만 보지 말고 source 쪽 작업 이력을 함께 봐야 합니다.

특히 대량 수정이 있었다면 “배치를 더 잘게 쪼갤 수 있는가”, “긴 트랜잭션을 나눌 수 있는가”를 먼저 검토하는 게 효과가 큽니다.

2. replica가 조회 트래픽 때문에 apply를 못 따라간다

read replica를 붙여놓으면 “읽기 전용이니까 비교적 안전하겠지”라고 생각하기 쉽지만, 실제 운영에서는 replica가 느린 조회 때문에 더 바빠지는 경우가 많습니다.

예를 들면:

  • 정렬과 필터가 큰 범위에서 일어나는 리스트 조회
  • 인덱스가 맞지 않아 많은 row를 읽는 검색
  • 페이지네이션이 뒤로 갈수록 점점 무거워지는 목록
  • join 결과가 크게 불어나는 리포트성 조회

이런 조회가 replica CPU, 메모리, 디스크를 계속 점유하면 apply thread가 따라갈 여유를 잃습니다. 즉 lag는 복제 메커니즘 문제가 아니라 replica에 태운 읽기 workload 문제일 수 있습니다.

이 구간은 아래 글들과 같이 보면 원인을 좁히기 쉽습니다.

3. 디스크, I/O, 네트워크가 병목이다

replication lag를 SQL만의 문제로 보면 놓치는 구간입니다. replica가 이벤트를 적용하려면 결국 로그를 받고, 읽고, 쓰고, flush해야 합니다. 그래서 아래가 함께 병목이 될 수 있습니다.

  • 디스크 IOPS 부족
  • burst 후 throughput 저하
  • 네트워크 지연 또는 일시적 품질 저하
  • 인스턴스 스펙 부족으로 인한 CPU 경쟁

이 경우 SQL만 손봐서는 충분히 줄지 않을 수 있습니다. lag가 커지는 시점의 CPU, 디스크 큐, 스토리지 처리량, 네트워크 지표를 같이 봐야 합니다.

실무에서는 “쿼리는 큰 문제 없는데 replica만 자꾸 밀린다”는 상황이 종종 나오는데, 이런 경우 인프라 자원 병목이 숨어 있는 경우가 꽤 많습니다.

4. 에러나 대기로 인해 apply가 사실상 멈췄다

가장 놓치면 안 되는 경우입니다. lag가 크다고 해서 항상 “조금 느리게 따라가고 있다”는 뜻은 아닙니다. 실제로는 SQL thread가 에러로 멈췄거나, 특정 대기 상태에 막혀 있을 수 있습니다.

이때는 Last_SQL_Error와 replication thread 상태를 먼저 봐야 합니다. 숫자만 보고 “나중에 따라잡겠지”라고 넘기면 안 됩니다.

또한 replica에서 lock wait이나 다른 장시간 대기가 있으면 apply가 밀릴 수 있습니다. lock 성격이 섞여 있다면 아래 글도 같이 보는 편이 좋습니다.

긴 트랜잭션은 lag를 한 번에 크게 만든다

replication lag를 볼 때 자주 나오는 함정이 “평소에는 괜찮은데 한 번 밀리면 회복이 오래 걸린다”는 패턴입니다. 이때는 긴 트랜잭션이 원인일 때가 많습니다.

예를 들어 수백만 row를 한 번에 바꾸는 작업은 source에서도 부담이지만, replica에도 큰 덩어리로 전달됩니다. 이 경우 사용자는 몇 초가 아니라 더 긴 시간 동안 일관성 문제를 겪을 수 있습니다.

그래서 대량 데이터 수정 작업은 가능하면:

  • 작은 배치로 나누고
  • 트랜잭션 크기를 줄이고
  • 운영 트래픽이 낮은 시간대에 실행하고
  • lag를 보면서 속도를 조절하는 편이 좋습니다

replication lag 대응은 종종 replica 튜닝보다 source에서 만들어지는 일의 모양을 바꾸는 것이 더 효과적입니다.

앱 라우팅을 같이 보지 않으면 체감 문제는 남는다

lag를 줄이는 것과, lag가 보여도 사용자가 덜 느끼게 만드는 것은 다른 문제입니다. 그래서 애플리케이션 레이어의 읽기 전략을 같이 봐야 합니다.

대표적으로 많이 쓰는 방식은 아래와 같습니다.

  • 쓰기 직후의 읽기는 잠시 source로 보낸다
  • 결제, 권한, 주문 같은 critical flow는 strong read를 유지한다
  • 검색, 피드, 통계처럼 약간의 지연을 허용할 수 있는 화면만 replica로 보낸다
  • 세션 단위로 “방금 쓴 사용자”를 잠시 source에 고정한다

여기서 중요한 건 모든 읽기를 replica로 보내는 것이 항상 정답이 아니라는 점입니다. 인프라는 효율적이어도 사용자 경험은 더 나빠질 수 있습니다.

즉 replication lag는 DB 운영 문제이면서 동시에 제품 라우팅 정책 문제이기도 합니다.

replication lag를 볼 때 자주 하는 실수

1. replica를 하나 더 붙이면 해결될 거라고 믿는 것

원인이 source write 폭증, 긴 트랜잭션, 느린 조회, 디스크 병목이라면 replica 수만 늘려도 본질은 그대로 남습니다.

2. Seconds_Behind_Source 숫자만 보고 끝내는 것

숫자는 시작점일 뿐입니다. thread 상태, 최근 에러, relay log 적체, 특정 시간대 패턴을 함께 봐야 합니다.

3. 읽기 일관성이 중요한 화면까지 replica로 보내는 것

트래픽 분산만 보고 라우팅하면, 사용자가 가장 민감한 순간에 “저장했는데 안 보인다”를 겪게 됩니다.

4. replica 조회 성능을 따로 안 보는 것

replica는 읽기 전용이 아니라 읽기 경쟁이 몰리는 곳입니다. 느린 조회가 누적되면 apply budget을 계속 깎아먹습니다.

튜닝 후에는 “lag가 줄었는지”보다 “문제가 덜 보이는지”까지 비교하자

개선 작업을 한 뒤에는 단순히 lag 그래프만 보지 말고 아래를 같이 비교해야 합니다.

  • 피크 시간대 lag 최대치가 줄었는가
  • lag가 발생하는 시간 길이가 짧아졌는가
  • 저장 직후 안 보임 같은 사용자 이슈가 줄었는가
  • critical flow를 source read로 우회한 뒤 오류 문의가 줄었는가

운영에서 중요한 건 “평균 몇 초”보다 문제가 얼마나 자주, 얼마나 크게 사용자에게 드러나는가입니다.

FAQ

Q. replication lag에 가장 민감한 서비스는 어떤 종류인가요?

사용자가 저장 직후 결과를 바로 확인해야 하는 서비스입니다. 주문, 결제, 재고, 권한, 프로필 수정, 관리자 반영 화면이 대표적입니다.

Q. source를 먼저 봐야 하나요, replica를 먼저 봐야 하나요?

보통은 replica 상태를 먼저 확인하고, 바로 source의 write 패턴과 배치 작업으로 이어서 보는 편이 빠릅니다. replica만 보면 “왜 못 따라가는지”가 안 보이고, source만 보면 “지금 실제로 어디가 멈췄는지”가 안 보이기 쉽습니다.

Q. replication lag를 완전히 0으로 만들 수 있나요?

비동기 read replica 구조에서는 항상 0을 보장하기 어렵습니다. 제품이 강한 read-after-write 일관성을 요구한다면, 일부 흐름은 source read를 유지하거나 아키텍처 수준에서 일관성 전략을 따로 가져가는 편이 현실적입니다.

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.

광고