Database/Mysql

[Real MySQL] 16-2. 복제: 타입

noahkim_ 2025. 3. 14. 15:49

백은빈, 이성욱 님의 "Real MySQL" 책을 정리한 포스팅 입니다.

 

  • 소스 서버의 바이너리 로그에 기록된 변경내역들을 식별하는 방식에 따라 나뉨

 

1. 바이너리 로그 파일 위치 기반 복제

  • 소스 서버의 바이너리 로그 파일명과 파일 내에서의 위치로 개별 바이너리 로그 이벤트를 식별해서 복제함
    • 이벤트 하나하나를 바이너리 로그 파일명과 파일내에서의 위치값의 조합으로 식별함
  • 레플레카 서버에서 소스 서버의 어떤 이벤트부터 동기화를 수행할 것인지 설정해야 함
    • 어느 이벤트까지 로컬 디스크로 가져왔고 적용했는지 관리
    • 다음번에 가져올 이벤트를 표시하려는 목적

 

필수 사항

  • 복제 구성원이 되는 MySQL 서버가 고유의 server_id를 가지고 있어야 함
  • 소스 서버에서 반드시 바이너리 로그가 활성화돼 있어야 함
    • 기본적으로 활성화 되어 있음
    • 서버 시작 시 데이터 디렉터리 밑에 "binlog"라는 이름으로 자동으로 생성됨

 

실습

소스 서버 설정
[mysqld]
server_id=1 # 기본값 1
sync_binlog=1
binlog_cache_size=5M
max_binlog_size=512M
binlog_expire_logs_seconds=1209600
  • server_id: 레플리케이션 시, 노드를 구분하는 유일값
  • sync_binlog: 바이너리 로그를 디스크에 동기화하는 주기를 설정
    • 1: 트랜잭션이 커밋될 때마다 디스크에 즉시 기록
    • 0: 운영체제가 캐시한 후 비동기적으로 기록
    • N: N개의 트랜잭션마다 1번 동기화
  • binlog_cache_size: 바이너리 로그 캐시의 크기를 설정하는 값
    • 바이너리 로그에 기록될 내용을 메모리에 캐싱하고, 커밋 시 디스크에 기록
  • max_binlog_size: 단일 바이너리 로그 파일의 최대 크기
  • binlog_expire_logs_seconds: 바이너리 로그를 자동으로 삭제하는 주기 (초 단위)

 

레플리카 서버 설정
[mysqld]
server_id=2 
relay_log=/relay-log/path/relay-log-name
relay_log_purge=ON
read_only
log_slave_updates
  • relay_log: 릴레이 로그가 저장될 경로 및 파일 이름
  • relay_log_purge: 릴레이 로그가 레플리카 서버 리포지토리에 반영될 경우, 릴레이 로그 파일 자동 삭제
  • log_slave_updates: 레플리카 서버가 소스 서버로 승격될 경우, 갱신 작업

 

복제 계정 준비
CREATE USER 'repl'@'%' IDENTIFIED BY 'replpassword';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
  • 레플리카 서버가 소스 서버로부터 바이너리 로그를 가져오려면 접속 계정이 있어야 함

 

소스 서버: 데이터 덤프 (mysqldump)
mysqldump -u root -p \
--all-databases --single-transaction --flush-logs --master-data=2 > backup.sql
  • --single-transaction
    • 데이터를 덤프할 때 하나의 트랜잭션을 사용해서 덤프
    • 테이블이나 레코드에 잠금을 걸지 않고 일관된 데이터를 덤프받도록 함
  • --master-data
    • 덤프 시작 시점에 복제 설정 구문이 덤프 파일 헤더에 기록될 수 있게 하는 옵션 (바이너리 로그 파일명, 위치정보)
    • "FLUSH TABLE WITH READ LOCK"으로 글로벌 락을 검 (바이너리 로그 파일의 위치를 고정시키기 위함)

 

레플리카 서버: 데이터 복사
mysql> SOURCE /tmp/backup.sql # 레플리카 서버에 덤프 파일이 있다 가정
  • 소스 서버의 덤프 파일을 레플리카 서버로 옮기기

 

복제 시작
  • 소스 서버의 바이너리 로그 정보 확인
    • show master status;
    • File, Position

 

change replication source to 
  source_host='127.0.0.1',
  source_port=3306,
  source_user='repl',
  source_password='password!',
  source_log_file='binlog.000246',
  source_log_pos=826,
  get_source_public_key=1;
  • 레플리카 서버) 소스 서버 정보 셋팅

 

start replica;
  • 레플리카 서버) 복제 명령 실행

 

show replica status;
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 192.168.35.179
                  Source_User: repl
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000247
          Read_Source_Log_Pos: 156
               Relay_Log_File: mysql-relay-bin.000003
                Relay_Log_Pos: 366
        Relay_Source_Log_File: binlog.000247
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 156
              Relay_Log_Space: 741
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File: 
           Source_SSL_CA_Path: 
              Source_SSL_Cert: 
            Source_SSL_Cipher: 
               Source_SSL_Key: 
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Source_Server_Id: 1
                  Source_UUID: b06df802-6ea5-11ea-9ec3-edc515152da1
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 86400
                  Source_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Source_SSL_Crl: 
           Source_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Source_TLS_Version: 
       Source_public_key_path: 
        Get_Source_public_key: 0
            Network_Namespace:
  • 레플리카 서버) 복제 상태 확인
    • Replica_IO_Running과 Replica_SQL_Running 값이 "YES" 이면 동기화 된것임

 

트랜잭션 건너뛰기

  • 종종 소스서버로부터 넘어온 트랜잭션이 레플리카 서버에서 제대로 실행되지 못하고 에러가 발생함
  • 단 이런경우는 트랜잭션 자체가 잘못되었을 경우가 많음
  • 이러한 경우 트랜잭션을 무시하고 넘어갈 수 있음
    • sql_slave_skip_count 시스템 변수를 1로 설정하고 SQL_THREAD를 재시작
    • 지정한 숫자는 무시할 이벤트 그룹 수를 의미함
    • 현재 처리중인 이벤트 그룹의 모든 이벤트 무시

 

2. 글로벌 트랜잭션 아이디 기반 복제

바이너리 로그 파일 위치 기반 복제의 문제점

  • 레플리카 서버들이 같은 이벤트에 대해 서로 다른 식별값을 가짐
  • 이로 인해 복제 토폴로지를 변경하는 작업은 불가능함
  • 복제 토폴로지 변경은 레플리카 서버들 중 장애가 발생하였을 때 필요함
  • 즉, 장애 복구가 어려움

 

GUID

  • 모든 레플리카 서버들이 각 이벤트들에 대해 동일하게 부여된 고유 식별값
  • 이를 기반으로 복제가 진행됨

 

필요성
  • 레플리카 서버 중 한 서버가 지연이 발생해 동기화가 60%까지 진행됨
  • 이때 소스 서버에서 장애가 발생하여 비정상적으로 종료됨
  • 그러면 완전히 동기화된 레플리카 서버가 소스 서버로 승격함
  • 이렇게 되면 완전히 동기화되지 않은 레플리카 서버에서 부하 분산용으로 트래픽을 처리할 경우 모순이 일어남

 

동작 방식
  • 특정 레플리카 서버가 승격되면, 완전히 동기화되지 않은 레플리카 서버는 승격된 서버를 대상으로 동기화를 시도함
  • 이 떄, 승격된 레플리카에서 사용중인 로그 파일을 알 필요 없음

 

구성
  • 서버에서 커밋된 각 트랜잭션과 연결된 고유 식별자
    • SELECT 쿼리나 sql_log_bin 설정이 비활성화 돼있는 상태에서 발생한 트랜잭션은 할당되지 않음
  • 소스 아이디와 트랜잭션 아이디 값의 조합 (콜론으로 구분됨)
    • 소스 아이디: 트랜잭션이 발생된 소스 서버 식별값 (server_uuid 시스템 값)
    • 트랜잭션 아이디: 서버에서 커밋된 트랜잭션 순서대로 부여되는 값 (1씩 증가하는 형태)

 

확인
select * from mysql.gtid_executed;

 

실습

다음 장에 계속...