
지난 포스팅에서는 DB 이중화의 기본 개념과 MariaDB의 Master-Slave 구조 구현법을 살펴보았습니다. 이 구조는 트래픽 분산에는 효과적이지만 쓰기 권한을 가진 Master 서버가 단일 장애점(SPOF)이 된다는 한계가 있습니다.
특히 별도 프로젝트에서 구축한 중앙 로그 모니터링 시스템은 데이터 조회(Read)보다 실시간 기록(Write) 비중이 압도적으로 높기 때문에 만약 Master 서버에 장애가 발생하면 복구 전까지 모든 로그 수집이 중단되어 심각한 데이터 유실과 서비스 다운타임을 겪을 수 밖에 없습니다.
이러한 문제를 해결하기 위해 단순히 데이터를 복제하는 수준을 넘어 Master 장애 시 Slave를 새로운 Master로 즉시 승격시켜 서비스 연속성을 보장해야합니다. 이번 포스팅에서는 지능형 DB 프록시인 MariaDB MaxScale을 도입하여 장애 감지부터 승격까지의 과정을 자동화하는 방법을 직접 구현해보겠습니다.
MaxScale은 데이터베이스와 애플리케이션 사이에 위치하는 지능형 데이터베이스 프록시(Proxy)입니다.

애플리케이션이 직접 DB 서버에 접속하는 대신 MaxScale에 접속하면 MaxScale이 뒤에 있는 DB들의 상태를 체크하여 쿼리를 적절한 서버로 보내주거나 장애 발생 시 자동으로 복구 작업을 수행합니다.
DB 이중화와 자동 장애 초기(Failover)를 지원하는 도구는 MaxScale 외에도 여러 가지가 있습니다.

그 중에서도 MariaDB MaxScale을 선택한 이유는 무엇보다 별도의 툴 조합 없이 MaxScale 하나만으로 모니터링, 자동 장애 조치(Failover), 그리고 읽기/쓰기 분리(Read-Write-Split)를 모두 해결할 수 있다는 점입니다.
특히 제가 구축한 로그 모니터링 시스템의 특성을 고려했을 때 실시간으로 대량의 로그를 쏟아붓는 환경에서는 데이터 일관성을 위해 성능을 희생하는 동기 방식보다, 성능 위주의 복제 방식이 유리합니다. MaxScale은 이러한 고부하 쓰기 환경에 최적화 되어 있습니다.
애플리케이션이 DB에 쿼리를 보낼 때 MaxScale 내부에서는 다음과 같은 순서로 일이 처리됩니다.
감시 (Monitoring) : 백엔드 DB들(Master, Slave)의 상태를 실시간으로 체크하여 누가 마스터이고, 누가 죽었는지 확인합니다.
분석 (Routing/Splitting) : 들어온 SQL이 SELECT인지 INSERT인지 분석합니다.
결정 및 배달 (Dispatching) : 분석 결과에 따라 쓰기 쿼리는 Master로, 읽기 쿼리는 Slave로 보냅니다.
서버 : MaxScale이 트래픽을 관리할 백엔드 MariaDB 또는 MySQL 인스턴스
모니터 : 백엔드 서버의 상태(ex. 기본 서버, 복제 서버, 다운 서버)를 모니터링하는 플러그인
라우터 : 클라이언트 쿼리가 백엔드 서버로 전달되는 방식을 결정하는 플러그인으로 readwritesplit 쓰기 작업은 기본 서버로, 읽기 작업은 복제 서버로 전달하는 라우터
서비스 : 라우터와 서버 세트, 그리고 필요한 필터를 조합하여 정의
리스너 : 클라이언트가 MaxScale에 연결하는 방법(포트, 프로토콜)과 연결하는 서비스를 정의
필터 : MaxScale을 통과하는 쿼리를 검사, 수정 또는 기록할 수 있는 선택적 구성 요소
MaxScale 설정 전에 먼저 Replication 작업을 진행해야 합니다. 이부분은 이전 포스팅을 참고하여 설정 후 정상 동작되는 부분까지 확인이 필요합니다.
https://blog.naver.com/wltn5012/224161196031
/etc/my.cnf.d/mariadb-server.cnf 파일에 아래 설정을 추가하겠습니다.
binlog_format=ROW # 복제 데이터 일관성을 위해 ROW 포맷 필수
log_slave_updates=ON # Master로부터 받은 데이터를 자신의 binlog에도 기록 (Failover 필수값)
binlog_format=ROW : 데이터 변경 점을 '쿼리 문장'이 아닌 '실제 바뀐 데이터 값' 단위로 기록합니다. 복제 시 데이터 불일치 오류를 최소화해주므로 이중화 환경에서 권장됩니다.
log_slave_updates=1 : 나중에 Master가 죽어서 Slave가 새로운 Master가 되었을 때, 그동안 받아온 데이터를 자신의 바이너리 로그에도 남겨놔야 다른 Slave들이 데이터를 이어받을 수 있기 때문에 MaxScale 자동 장애 조치(Failover) 구성을 하려면 필수입니다.
# MariaDB 리포지토리 설정 (MaxScale 포함)
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash
# MaxScale 설치
sudo dnf install -y maxscale
# 서비스 활성화 및 시작
sudo systemctl enable --now maxscale
MaxScale에서 백엔드 DB를 감시하고 관리하기 위해 DB에 MaxScale 용 계정을 생성합니다. Slave에는 별도로 계정 생성해주지 않아도 Master에서 Replication 을 통해 동기화되므로 Master DB에만 계정을 생성하겠습니다.
-- MaxScale 모니터링 및 관리용 계정
CREATE USER 'maxscale_user'@'%' IDENTIFIED BY '비밀번호';
GRANT SELECT ON mysql.user, mysql.db, mysql.tables_priv, mysql.roles_mapping TO 'maxscale_user'@'%';
GRANT SHOW DATABASES, REPLICATION CLIENT, REPLICATION SLAVE, SUPER, RELOAD ON *.* TO 'maxscale_user'@'%';
GRANT REPLICATION CLIENT ON *.* TO 'maxscale_user'@'%';
-- 실제 서비스 로그 데이터 접속용 계정 (App용)
CREATE USER 'log_writer'@'%' IDENTIFIED BY '비밀번호';
GRANT ALL PRIVILEGES ON log_db.* TO 'log_writer'@'%';
FLUSH PRIVILEGES;
MaxScale의 설정은 주로 메인 설정 파일인 /etc/maxscale.cnf 에서 이루어집니다.
MaxScale 서비스 전체의 동작 방식을 제어하는 글로벌 설정 영역
[maxscale]
threads=auto
log_info=true
Master-Slave 대상인 백엔드 DB에 대한 설정입니다.
[server1]
type=server
address=10.5.0.36 # Master DB IP
port=3306
protocol=MariaDBBackend
ssl=false
[server2]
type=server
address=10.5.0.37 # Slave DB IP
port=3306
protocol=MariaDBBackend
ssl=false
[server3]
type=server
address=10.5.0.38 # Slave DB IP
port=3306
protocol=MariaDBBackend
ssl=false
MaxScale이 백엔드 서버의 상태와 역할을 모니터링하고 서버들을 클러스터로 그룹화하는 설정입니다.
[MariaDB-Monitor]
type=monitor
module=mariadbmon
servers=server1,server2,server3 # 모니터링할 서버 지정
user=maxscale_user # Master DB에서 생성한 모니터링용 계정
password=P@ssw0rd
monitor_interval=2s # 2초마다 백엔드 DB 상태 체크
auto_failover=true
auto_rejoin=true
auto_failover=true : Master DB 다운 시 자동으로 Slave 중 하나를 Master로 승격시키기 위해 해당 값 활성화
auto_rejoin=true : 죽었던 이전 Master가 다시 살아나면 자동으로 새로운 Master의 Slave로 편입 / 죽었던 Master 서버를 복구 했을 때 직접 Slave로 동기화 하는 작업 단계를 줄일 수 있다는 장점이 있습니다.
섹션은 사용자 인증 정보 조회(User-Mapping)을 위한 설정으로 애플리케이션에서 DB 및 테이블에 접근하고자 할 때 해당 권한이 있는지 확인합니다.
[Read-Write-Service]
type=service
router=readwritesplit # 읽기쓰기 분할 라우터
servers=server1,server2,server3 # 라우팅 대상 백엔드 서버
user=maxscale_user
password=P@ssw0rd
[Read-Write-Service] 섹션 : MaxScale이 쿼리를 라우팅하는 방식을 구성할 수 있으며, 읽기/쓰기 분할 라우터 설정을 통해 읽기 작업은 로드 밸런싱하고, 쓰기 작업은 기본 노드로 라우팅이 가능합니다.
현재는 모니터링용 계정과 사용자 인증 정보 계정을 maxscale_user로 통일해서 사용하고 있으나 각각 필요한 권한이 다르기 때문에 별도 계정 생성 및 권한을 부여하여 운영하는 것이 보안성 측면에서 안전할 것 같습니다.

MaxScale이 수신 클라이언트 연결을 수신할 포트와 프로토콜, 그리고 해당 연결을 어떤 서비스로 보낼지 지정합니다.
[Read-Write-Listener]
type=listener
service=Read-Write-Service
protocol=MariaDBClient
port=4000
MaxScale 서비스 재시작 후 MaxScale에서 모니터링 하고 있는 DB 서버들을 확인하겠습니다.
# maxsctrl list servers

State 값을 통해 각각 DB 서버가 Master인지, Slave인지 확인 가능하며, GTID를 통해 정상적으로 데이터 동기화가 되는지 확인 가능합니다.
이제 로그 서버(애플리케이션)에서 DB 설정 정보를 MaxScale 을 바라보도록 변경합니다.

그리고 DB에 INSERT 쿼리가 수행되도록 했을 때 Master와 Slave에 데이터가 정상적으로 쌓이는지 확인됩니다.

GTID 값이 변경된 것도 확인할 수 있습니다.

이번 포스팅에서는 MariaDB에서 제공하는 MaxScale을 사용해 DB 이중화를 구현해보았습니다. 공식 문서를 통해 다양한 기능을 추가할 수 있으니 한 번 확인해 보시면 좋을 것 같습니다!