사전 준비

MariaDB 이중화, 다중화 순서

마스터 구성

(1) 바이너리 로그 활성화
(2) 마스터에 고유한 server_id 부여
(3) --log-basename 옵션 사용해 복제 로그에 고유 이름 지정
(4) 로그 포맷 지정

슬레이브 구성

(1) 슬레이브에 고유한 server_id 부여

파일 구성

  • 환경변수 파일 (.env)
1
2
3
4
MARIADB_ROOT_PASSWORD=mariadbpasswd
MARIADB1_PORT=19000
MARIADB2_PORT=19001
MARIADB3_PORT=19002
  • docker-compose 파일 (docker-compose.yml)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
services:

  mariadb_1:
    # master
    image: mariadb:11.8.1-rc
    container_name: mariadb_1
    environment:
      MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
    ports:
      - "${MARIADB1_PORT}:3306"
    volumes:
      - ./mariadb1/data:/var/lib/mysql
      - ./mariadb1/conf.d:/etc/mysql/conf.d
      - ./mariadb1/backup:/backup

  mariadb_2:
    # slave
    image: mariadb:11.8.1-rc
    container_name: mariadb_2
    environment:
      MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
    ports:
      - "${MARIADB2_PORT}:3306"
    volumes:
      - ./mariadb2/data:/var/lib/mysql
      - ./mariadb2/conf.d:/etc/mysql/conf.d
      - ./mariadb2/backup:/backup

  mariadb_3:
    # master
    image: mariadb:11.8.1-rc
    container_name: mariadb_3
    environment:
      MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
    ports:
      - "${MARIADB3_PORT}:3306"
    volumes:
      - ./mariadb3/data:/var/lib/mysql
      - ./mariadb3/conf.d:/etc/mysql/conf.d
      - ./mariadb3/backup:/backup

MariaDB 들 실행 (Docker-Compose)

1
sudo docker compose up -d

마스터 구성

마스터 DB 설정 수정

  • mariadb1/conf.d 디렉터리에 커스텀 설정파일을 만듭니다.
  • 바이너리 로그 활성화
  • server_id 지정
  • 로그 베이스네임 지정
  • 로그 포맷 지정
  • 접근 가능 호스트 지정 (선택사항)
1
vi mariadb1/conf.d/custom.cnf
1
2
3
4
5
6
[mysqld]
log-bin
server_id=1
log-basename=master1
binlog-format=mixed
bind-address=0.0.0.0

MariaDB 재시작

  • 설정 적용을 위해 MariaDB 를 재시작해줍니다.
1
sudo docker restart mariadb_1

복제 전용 유저 생성

  • 마스터 MariaDB 에 root 계정으로 접속합니다.
  • 그리고 복제 전용 유저를 생성해주겠습니다.
1
docker exec -it mariadb mariadb -uroot
1
2
CREATE USER 'replication_user'@'%' IDENTIFIED BY 'bigs3cret';
GRANT REPLICATION SLAVE ON *.* TO 'replication_user'@'%';

설정 체크

  • 아래 두 가지 옵션은 원격지의 마스터-슬레이브에 장애가 됩니다.
  • 원격지 간 마스터-슬레이브 구축이 필요하다면 아래 두 옵션에 대한 조치를 진행하세요.
  • skip-networking=1 : 로컬 호스트로만 연결 가능. 모든 원격 슬레이브의 연결을 차단.
  • bind-address : TCP/IP 연결을 수신(허용)하는 주소.

skip-networking

  • 마리아DB 설정파일들에서 skip-networking 옵션을 제거하거나 주석처리 합니다.
  • 기본적으로 skip-networking 은 비활성화 되어있습니다.

bind-address

  • bind-address 옵션을 사용한 곳이 있다면 원격지 서버가 접근 가능하도록 추가합니다.
  • bind-address 옵션을 사용한 곳이 없다면, 아래와 같이 추가해줍니다.
1
vi mariadb1/conf.d/custom.cnf
1
2
3
[mysqld]
...
bind-address=0.0.0.0

슬레이브 구성

슬레이브 DB 설정 수정

  • mariadb2/conf.d 디렉터리에 커스텀 설정파일을 만듭니다.
  • server_id 지정
1
vi mariadb2/conf.d/custom.cnf
1
2
3
[mysqld]
server_id=2
bind-address=0.0.0.0

MariaDB 재시작

1
sudo docker restart mariadb_2

마스터의 바이너리 로그 위치 얻기

  • 본 작업이 진행되는 동안에는 데이터가 변경되지 않아야 합니다.
  • 그래야 슬레이브에게 복제 시작의 정확한 시점을 알려줄 수 있기 때문입니다.
  • 따라서 본 작업 실행 전 마스터에서 모든 테이블을 플러시하고 잠금을 수행합니다.
1
sudo docker exec -it mariadb_1 mariadb -uroot
1
FLUSH TABLES WITH READ LOCK;
  • 다음으로 마스터의 바이너리 로그 위치를 확인합니다.
1
2
3
4
5
6
7
8
SHOW MASTER STATUS;

>> +--------------------+----------+--------------+------------------+
>> | File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |
>> +--------------------+----------+--------------+------------------+
>> | master1-bin.000001 |      672 |              |                  |
>> +--------------------+----------+--------------+------------------+

기존 데이터 가져오기

  • 만약 마스터에 이미 데이터가 있다면, 완벽한 복제를 위해 데이터 가져오기를 실행합니다.
  • 자세한 내용은 아래 DOC 참고하시기 바랍니다.
  • MariaDB - 데이터 가져오기

슬레이브 데이터베이스 시작

  • 슬레이브 데이터베이스에 접속하여, 마스터 데이터베이스를 지정해줍니다.
  • 설정파일로 설정은 안되고, 반드시 명령어로 수행해야 합니다.
1
sudo docker exec -it mariadb_2 mariadb -uroot
1
2
3
4
5
6
7
8
9
10
CHANGE MASTER TO
  MASTER_HOST='master.domain.com', // master DB  IP  주소 입력
  MASTER_USER='replication_user',  // master DB  복제 전용 유저이름
  MASTER_PASSWORD='bigs3cret',     //  유저의 비밀번호
  MASTER_PORT=19000,               // master DB  서비스 포트
  MASTER_LOG_FILE='master1-bin.000096',  // master DB 바이너리 로그 위치
  MASTER_LOG_POS=568,                    // master DB 바이너리 로그 POS
  MASTER_CONNECT_RETRY=10;          // master DB 연결 시도 횟수

>> Query OK, 0 rows affected, 1 warning (0.265 sec)

마스터 잠금 해제

  • 완료되었다면 마스터의 잠금을 해제합니다.
1
sudo docker exec -it mariadb_1 mariadb -uroot
1
UNLOCK TABLES;

마스터 슬레이브 테스트

테스트용 계정 생성

  • 테스트를 위해 마스터에 사용자 계정을 만들었습니다.
1
sudo docker exec -it mariadb_1 mariadb -uroot
1
2
3
CREATE USER 'test_user'@'%' IDENTIFIED BY 'strongpasswd';
GRANT ALL PRIVILEGES ON *.* TO 'test_user'@'%';
FLUSH PRIVILEGES;

접속 테스트

  • 마스터 계정 접속 테스트
1
2
3
4
5
6
sudo docker exec -it mariadb_1 mariadb -utest_user -p
# strongpasswd

>> Your MariaDB connection id is 26
>> ...
>> MariaDB [(none)]>
  • 슬레이브 계정 접속 테스트
1
2
3
4
5
6
sudo docker exec -it mariadb_2 mariadb -utest_user -p
# strongpasswd

>> Your MariaDB connection id is 26
>> ...
>> MariaDB [(none)]>
  • 슬레이브엔 계정을 명시적으로 만들어주지 않았었습니다.
  • 하지만, 마스터의 로그를 가져와 슬레이브에서도 계정 생성이 수행되어 있습니다.

테이블 생성

  • 마스터에서 DB 및 테이블을 생성하고, 몇 가지 데이터를 넣어보겠습니다.
1
sudo docker exec -it mariadb_1 mariadb -utest_user -p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- DB 생성 및 선택
CREATE DATABASE TEST_DB;
USE TEST_DB;

-- 테이블 생성
CREATE TABLE TEST_TABLE (
	ID INT AUTO_INCREMENT PRIMARY KEY,
	NAME VARCHAR(10),
	INPUT_DT TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 데이터 입력
INSERT INTO TEST_TABLE (NAME) VALUE ('김마스터');
INSERT INTO TEST_TABLE (NAME) VALUE ('김슬레이브');
1
2
3
4
5
6
7
8
9
-- 입력 데이터 확인
SELECT * FROM TEST_TABLE;

>> +----+-----------------+---------------------+
>> | ID | NAME            | INPUT_DT            |
>> +----+-----------------+---------------------+
>> |  1 | 김마스터        | 2025-06-10 06:32:13 |
>> |  2 | 김슬레이브      | 2025-06-10 06:32:18 |
>> +----+-----------------+---------------------+

슬레이브 조회

  • 슬레이브에서 테이블이 잘 복제되었는지 확인합니다.
1
sudo docker exec -it mariadb_2 mariadb -utest_user -p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- DB부터 확인
SHOW DATABASES;

>> +--------------------+
>> | Database           |
>> +--------------------+
>> | TEST_DB            |
>> ...
>> +--------------------+

-- 테이블 및 내용 확인
USE TEST_DB;
SHOW TABLES;

>> +-------------------+
>> | Tables_in_TEST_DB |
>> +-------------------+
>> | TEST_TABLE        |
>> +-------------------+

-- 테이블에서 데이터 조회
SELECT * FROM TEST_TABLE;

>> +----+-----------------+---------------------+
>> | ID | NAME            | INPUT_DT            |
>> +----+-----------------+---------------------+
>> |  1 | 김마스터        | 2025-06-10 06:32:13 |
>> |  2 | 김슬레이브      | 2025-06-10 06:32:18 |
>> +----+-----------------+---------------------+

실험

슬레이브에서 데이터를 삽입하면?

  • 슬레이브에서 데이터를 삽입하면 어떻게 될까?
1
2
3
4
5
6
7
8
9
10
11
12
-- 데이터 삽입
INSERT INTO TEST_TABLE (NAME) VALUE ('슬레이브삽입');

-- 데이터 조회
 SELECT * FROM TEST_TABLE;
>> +----+--------------------+---------------------+
>> | ID | NAME               | INPUT_DT            |
>> +----+--------------------+---------------------+
>> |  1 | 김마스터           | 2025-06-10 06:32:13 |
>> |  2 | 김슬레이브         | 2025-06-10 06:32:18 |
>> |  3 | 슬레이브삽입       | 2025-06-10 06:37:03 |
>> +----+--------------------+---------------------+
  • 마스터에서 확인해보면 슬레이브에서 삽입한 데이터는 들어와있지 않다.
  • 이렇게 되면 이중화/다중화가 깨지는 것이므로, 슬레이브에 삽입하지 않게 주의!
1
sudo docker exec -it mariadb_1 mariadb -utest_user -p
1
2
3
4
5
6
7
8
SELECT * FROM TEST_TABLE;

>> +----+-----------------+---------------------+
>> | ID | NAME            | INPUT_DT            |
>> +----+-----------------+---------------------+
>> |  1 | 김마스터        | 2025-06-10 06:32:13 |
>> |  2 | 김슬레이브      | 2025-06-10 06:32:18 |
>> +----+-----------------+---------------------+

참고

  • 마스터-슬레이브 구조 뿐만 아니라, 마스터-마스터 구조 또한 가능하다.
  • 하지만 마스터-마스터는 데이터 충돌의 가능성, 복잡한 관리 때문에 피하는 게 권장된다.
  • 마스터-마스터 구조가 필요할 경우, 직접적인 연결보다는 메시지 큐나 로그 브로커를 이용한 비동기 이벤트 전파 방식이 더 안정적이고 확장성도 좋아 권장된다.
  • full 백업도 있다. 참고 - MariaDB-backup
  • 이번 마스터-슬레이브 구조 구축을 통해 장애발생에 따른 대응, 읽기 부하 분산을 얻을 수 있다.

Reference

MariaDB - Setting Up Replication
MariaDB - CHANGE MASTER TO
MariaDB - Option - skip networking
MariaDB - binary log
MariaDB - log option - log-basename

Comments