VIP는 마스터를 바라보는데, 왜 슬레이브에도 UPDATE가 됐을까
이전 글 → MaxScale GTID 복제 중단 트러블슈팅
저번에 MaxScale GTID 복제 중단 이슈를 분석하고,
유지보수 업체가 와서 복제를 재동기화했다.
그런데 이번엔 또 다른 이상한 현상이 발생했다.
시스템 구성
저번 글과 동일한 구성이다.
VIP (DBM) 192.168.0.10
- 가상 IP, 평상시 1번 DB(마스터)를 가리킴
- 1번 DB 장애 시 2번 DB로 자동 전환
Master DB (DBA) 192.168.0.11
- 쓰기 전담
Slave DB (DBB) 192.168.0.12
- 읽기 전담 (복제 대상)
프로젝트 모듈의 DB 접속 설정은 DBM:3306 (VIP)로 구성되어 있다.
문제 발생
유지보수 업체 담당자가 복제 재동기화 작업을 마친 후
이런 말을 남기고 갔다.
“VIP 포트로 접속하면 무조건 마스터로만 라우팅됩니다.
슬레이브로 쿼리가 가는 건 정상적인 구조에서 불가능해요.”
그런데 그 직후, 프로젝트에서 UPDATE를 실행했더니
1번 DB(마스터)와 2번 DB(슬레이브) 양쪽 모두에 반영되어 있었다.
로그를 확인해봤다.
1
2
1번 DB (DBA) UPDATE 반영 시각: 10:00:00.100 ← 먼저
2번 DB (DBB) UPDATE 반영 시각: 10:00:00.300 ← 0.2초 후
마스터가 먼저 반영되고, 0.2초 후 슬레이브에 복제됐다.
원인 분석
복제 흐름 자체는 정상이다
순서만 보면 정상적인 복제다.
마스터가 먼저 COMMIT되고, 0.2초 후 슬레이브에 반영됐다.
정상적인 복제 흐름은 아래와 같다.
1
2
3
Master COMMIT → GTID 발급 → Binary Log 기록
→ Slave IO Thread 감지 → Relay Log 복사
→ Slave SQL Thread 실행 → 데이터 반영
이번 케이스는 이 순서 그대로다.
그럼 왜 이슈로 인지했는가
업체 담당자는 이렇게 말했다.
“VIP 포트로 접속하면 무조건 마스터로만 라우팅됩니다.”
즉, 슬레이브는 읽기 전담이고 쓰기는 마스터에서만 일어나야 한다.
그런데 UPDATE 하나를 실행했을 뿐인데
두 DB 모두에 데이터가 반영된 것을 보고 이상하다고 느낀 것이다.
결론적으로 슬레이브에 반영된 건 복제(Replication)가 정상 동작한 결과였다.
마스터에 UPDATE → 슬레이브로 복제, 이 흐름이 맞다.
그래도 확인이 필요한 부분
저번 GTID 이슈 때 슬레이브에 직접 쓰기가 발생한 이력이 있었다.
그때 근본 원인인 MaxScale 라우팅 설정과
슬레이브 read_only 설정이 제대로 잡혔는지 확인이 필요하다.
1
2
저번: MaxScale 불안정 → 쓰기가 슬레이브로 라우팅 → GTID 꼬임 → 복제 중단
이번: 복제 재동기화 이후 → 마스터 UPDATE → 슬레이브 정상 복제 (0.2초 후)
표면상 정상이더라도, 근본 설정이 잡혀있지 않으면 언제든 재발할 수 있다.
확인 방법
Binary Log에서 실행 시점 추적
두 DB 각각의 Binary Log를 비교하면
어느 서버에서 먼저 쿼리가 실행됐는지 정확히 확인할 수 있다.
1
2
3
4
5
6
7
8
-- 바이너리 로그 활성화 여부 및 경로 확인
SHOW VARIABLES LIKE 'log_bin%';
-- 바이너리 로그 파일 목록
SHOW BINARY LOGS;
-- 특정 파일 내용 조회
SHOW BINLOG EVENTS IN 'binlog.000001';
시간 범위를 좁혀서 보고 싶다면 mysqlbinlog을 사용한다.
1
2
3
mysqlbinlog --start-datetime="2026-04-02 10:00:00" \
--stop-datetime="2026-04-02 10:01:00" \
/var/lib/mysql/binlog.000001
Binary Log 설정 파일 위치
1
2
3
4
5
6
7
8
9
10
# 메인 설정 파일
/etc/my.cnf
/etc/mysql/my.cnf
# conf.d 디렉토리에 분리된 경우
/etc/mysql/conf.d/
/etc/mysql/mariadb.conf.d/
# 어느 파일이 적용됐는지 한 번에 확인
mysqld --print-defaults | grep log_bin
설정 파일 안에서는 이런 형태로 잡혀 있다.
1
2
3
4
[mysqld]
log_bin = /var/lib/mysql/binlog
binlog_format = ROW
expire_logs_days = 7
슬레이브 read_only 설정 확인
1
2
3
-- 슬레이브에서 실행
SHOW VARIABLES LIKE 'read_only';
SHOW VARIABLES LIKE 'super_read_only';
슬레이브에 쓰기가 허용된 상태라면 반드시 아래 설정을 추가해야 한다.
1
2
3
[mysqld]
read_only = ON
super_read_only = ON
마무리
이번엔 다행히 복제 흐름 자체는 정상이었다.
다만 처음 보고 이상하다고 느낀 건,
저번 이슈 이후 두 DB 모두에 데이터가 반영되는 상황 자체가 낯설게 느껴졌기 때문이다.
마스터에서 슬레이브로 0.2초 차이는 복제 지연이지 이상 징후가 아니다. Binary Log 시각을 비교하면 순서만 봐도 직접 실행인지 복제인지 구분할 수 있다.
다만 저번 이슈의 근본 원인이 완전히 해결됐는지는 따로 확인이 필요하다. 표면만 수습한 거랑 원인을 해결한 건 다르니까. read_only 설정도 반드시 확인해야 한다. 슬레이브에 쓰기가 허용된 상태면 언제든 다시 꼬인다.
정상과 비정상의 경계를 알려면 정상이 어떻게 생겼는지를 먼저 알아야 한다.