Featured image of post 16. 복제 (1)

16. 복제 (1)

Real MySQL 8.0

데이터베이스를 사용하고 운영할 때 가장 중요한 두 가지 요소를 꼽으라면 바로 확장성과 가용성이다.

서비스에서 발생하는 대용량 트래픽을 안정적으로 처리하기 위해서는 데이터베이스 서버의 확장이 필수적이며, 사용자가 언제든지 안정적인 서비스를 이용할 수 있게 하려면 DBMS 서버를 포함함 하위 시스템들의 가용성이 반드시 뒷받침돼야 한다.

이 두 요소를 위해 가장 일반적으로 사용되는 기술이 복제(Replication)이다.

개요

복제는 한 서버에서 다른 서버로 데이터가 동기화되는 것을 말하며, 원본 데이터를 가진 서버를 소스(Source) 서버, 복제된 데이터를 가지는 서버를 레플리카(Replica) 서버라고 부른다.

소스 서버에서 데이터 및 스키마에 대한 변경이 최초로 발생하며, 레플리카 서버에서는 이러한 변경 내역을 소스 서버로부터 전달받아 자신이 가지고 있는 데이터에 반영함으로써 소스 서버에 저장된 데이터와 동기화 시킨다.

대부분의 DBMS에서 복제 기능을 제공하며, 일반적으로 서비스에서 사용될 DB 서버를 구축할 때는 메인으로 사용될 소스 서버 한 대와 복제를 통해 소스 서버와 동일한 데이터를 가진 레플리카 서버를 한 대 이상 함께 구축한다.

  • 이는 서비스의 메인 DB 서버인 소스 서버에 문제가 생겼을 때를 대비해려는 목적이 제일 크지만 복제를 통해 레플리카 서버를 구축하는 데는 여러가지 목적이 있다.

스케일 아웃(Scale-out)

서비스를 운영하다 보면 사용자가 늘어나고, 이에 따라 DB 서버로 유입되는 트래픽도 자연히 증가해 DB 서버의 부하가 높아진다.

이러한 경우 서버의 성능을 올리는 스케일 업(Scale-up)으로 애플리케이션의 큰 변화 없이 쉽게 해결할 수 있지만, 서버 한 대에서 처리할 수 있는 트래픽은 한계가 있으므로 일시적인 해결 방법이다.

이러한 경우 동일한 데이터를 가진 DB 서버를 여러개 사용하는 스케일 아웃 방식으로 트래픽 증가를 조금 더 유연하게 대응할 수 있다.

데이터 백업

DB 서버에는 다양한 종류의 데이터가 저장되며, 사용자의 실수로 데이터가 삭제되었을 때 서비스 운영에 치명적인 영향을 줄 수도 있다.

이러한 경우를 대비하기 위해 DB 서버에 저장된 데이터들을 주기적으로 백업하는 것이 필수적인데, 일반적으로 데이터가 저장돼 있는 DB 서버에서 백업 프로그램이 실행되어 백업을 진행한다.

이처럼 동일한 서버 내에서 백업이 실행되는 경우 백업 프로그램과 DBMS가 서버의 자원을 공유하기 때문에 백업으로 인해 실행 중인 쿼리들이 영향을 받아 서비스에 문제가 발생할 가능성이 있다.

이러한 문제를 방지하기 위해 레플리카 서버를 구축하여 백업을 실행한다.

데이터 분석

DB 서버에서는 기본적으로 서비스에 사용되는 쿼리들이 실행되지만, 데이터 분석을 위한 분석용 쿼리들을 실행하기도 하는데, 이러한 쿼리들의 경우 대량의 데이터를 조회, 집계 연산을 위한 조회 등 부하가 큰 쿼리들이 주로 실행되어 서비스에서 사용되는 DB 서버를 사용하면 서비스에 장애가 발생할 수 있다.

이러한 문제를 예방하기 위해 데이터 분석을 위한 레플리카 서버를 구축하여 전용으로 활용하기도 한다.

데이터의 지리적 분산

DB 서버와 애플리케이션 서버가 물리적으로 서로 먼 거리에 있는 경우 두 서버간의 통신 시간은 거리에 비례하여 늘어나게된다.

서비스 응답 속도는 애플리케이션 서버의 처리 속도와 더불어 서버 간의 통신 속도에도 영향을 받으므로 서버의 물리적인 위치를 가깝게 구성하는게 좋은데, DB 서버의 위치를 이동시키지 못한다면 복제를 통해 가까운 곳에 레플리카 서버를 구축해 사용하여 개선될 수 있다.

복제 아키텍처

MySQL 복제는 바이너리 로그를 기반으로 구현되었으며, 소스 서버에서 생성된 바이너리 로그가 레플리카 서버로 전송되고 레플리카 서버에서는 해당 내용을 로컬 디스크에 저장한 뒤 자신이 가진 데이터에 반영함으로써 소스 서버와 레플리카 서버 간의 데이터 동기화가 이루어진다.

  • MySQL 서버에서 발생하는 모든 변경 사항은 별도의 로그 파일에 순서대로 기록되는데, 이를 바이너리 로그(Binary Log)라고 한다.
  • 바이너리 로그에는 데이터 변경 내역 뿐만 아니라 테이블의 구조 변경과 계정이나 권한의 변경 정보까지 모두 저장되며, 바이너리 로그에 기록된 각 변경 정보들을 이벤트라고 한다.
  • 레플리카 서버에서 소스 서버의 바이너리 로그를 읽어 들여 따로 로컬 디스크에 저장해둔 파일을 릴레이 로그라고 한다.

MySQL 복제는 세 개의 스레드에 의해 작동한다.

바이너리 로그 덤프 스레드(Binary Log Dump Thread)

소스 서버에 위치한 스레드이며, 레플리카 서버가 데이터 동기화를 위해 소스 서버에 접속해 바이너리 로그 정보를 요청하면, 소스 서버에서 레플리카 서버가 연결될 때 내부적으로 바이너리 로그 덤프 스레드를 생성해서 바이너리 로그의 내용을 레플리카 서버로 전송한다.

바이너리 로그 덤프 스레드는 레플리카 서벌오 보낼 각 이벤트를 읽을 때 일시적으로 바이너리 로그에 잠금을 수행하며, 이벤트를 읽고난 후에는 바로 잠금을 해제한다.

  • 이 스레드는 소스 서버에서 SHOW PROCESSLIT 명령을 통해 확인할 수 있다.

레플리케이션 I/O 스레드(Replication I/O Thread)

복제가 시작되면(START REPLICA, START SLAVE) 레플리카 서버는 I/O 스레드를 생성하고, 복제가 멈추면(STOP REPLICA, STOP SLAVE)되면 I/O 스레드는 종료된다.

I/O 스레드는 소스 서버의 바이너리 로그 덤프 스레드로부터 바이너리 로그 이벤트를 가져와 로컬 서버의 파일(릴레이 로그)로 저장하는 역할을 담당한다.

  • 소스 서버의 바이너리 로그를 읽어 파일로 쓰는 역할만 하기 때문에 I/O 스레드라 부른다.
  • 이 스레드의 상태는 MySQL의 복제 현황을 보여주는 SHOW REPLICA STATUS(SHOW SLAVE STATUS) 명령의 결과에서 Replica_IO-Running(Slave_SQL_running) 컬럼에 표시된 값을 통해 확인할 수 있다.

레플리케이션 SQL 스레드(Replication SQL Thread)

레플리케이션 I/O 스레드에 의해 작성된 릴레이 로그 파일의 이벤트를 읽고 실행한다.

레플리케이션 I/O 스레드와 같은 방식으로 상태를 확인할 수 있다.

주의사항

레플리카 서버에서 레플리케이션 I/O 스레드와 SQL 스레드는 서로 독립적으로 동작하기 때문에 SQL 스레드에서 이벤트를 적용하는 게 느리더라도 I/O 스레드는 그것과 무관하게 정상적으로 빠르게 소스 서버로부터 이벤트를 읽어올 수 있다.

레플리카 서버에서 소스 서버의 변경 사항들이 적용되는 것은 소스 서버가 동작하는 것과는 별개로 진행되므로 레플리카 서버에 문제가 생기더라도 소스 서버는 전혀 영향을 받지 않는다.

그러나 소스 서버에 문제가 생겨 정상적으로 동작하지 않게 되면 복제는 에러를 발생시키고 중단된다.(복제 기능만)

이에 따라 레플리카 서버에서 처리되는 쿼리는 정상적으로 동작하지만, 동기화가 안되어 예전 상태 데이터를 보게 된다.

이러한 문제를 예방하기 위해 복제가 시작되면 레플리카 서버는 릴레이 로그를 비롯해 총 세가지 유형의 복제 관련 데이터를 생성하고 관리한다.

  • 릴레이 로그(Relay Log)
    • 레플리케이션 I/O 스레드에 의해 작성되는 파일로, 소스 서버의 바이너리 로그에서 읽어온 이벤트(트랜잭션) 정보가 저장된다.
    • 바이너리 로그와 마찬가지로 현재 존재하는 릴레이 로그 파일들의 목록이 담긴 인덱스 파일과 실제 이벤트 정보가 저장돼 있는 로그 파일들로 구성된다.
    • 릴레이 로그에 저장된 트랜잭션 이벤트들은 레플리케이션 SQL 스레드에 의해 레플리카 서버에 적용된다.
  • 커넥션 메타데이터(Connection Metadata)
    • 레플리케이션 I/O 스레드에서 소스 서버에 연결할 때 사용하는 DB 계정 정보 및 현재 읽고 있는 소스 서버의 바이너리 파일명과 파일 내 위치 값 등이 담겨있다.
    • 이러한 정보는 기본적으로 mysql.slave_master_info 테이블에 저장된다.
  • 어플라이어 메타데이터(Applier Metadata)
    • 레플리케이션 SQL 스레드에서 릴레이 로그에 저장된 소스 서버의 이벤트들을 레플리카 서버에 적용하는 컴폰언트이다.
    • 최근 적용된 이벤트에 대해 해당 이벤트가 저장돼 있는 릴레이 로그 파일명과 파일 내 위치 정보 등을 담고 있다.
    • 레플리케이션 SQL 스레드가 이러한 정보들을 바탕으로 레플리카 서베에 나머지 이벤트들을 적용한다.
    • 이러한 정보는 기본적으로 mysql.slave_relay_log_info 테이블에 저장된다.

커넥션 및 어플라이어 메타데이터는 MySQL 시스템 변수 master_info_repository, relay_log_info_repository를 통해 어떤 태로 데이터를 관리할 지 결정할 수 있다.

  • FILE: 커넥션 메타데이터와 어플라이어 메타데이터는 각각 MySQL의 데이터 디렉터리에서 파일로 관리된다.
  • TABLE: MySQL의 mysql 데이터 베이스 내 테이블에 각각 데이터가 저장된다.

FILE 타입은 레플리케이션 I/O 스레드로 SQL 스레드가 동작할 때 파일의 내용이 동기화되지 않는 경우가 빈번하게 발생하여 여러 문제를 발생시켰다.
이로인해 MySQL 8.0.2 버전부터 기본값으로 TABLE이 되었고, FILE 타입은 삭제 예정이다.