[MariaDB] Mariabackup을 이용한 증분 백업

김성수·2020년 10월 14일
2

개요

  • 사내에서 하루 최소 300백만 건 이상 쌓이는 데이터들을 효율적으로 백업하고자 사용한 방법을 썼습니다.

  • Mariabackup 모듈을 이용한 Master_Database의 데이터 백업 방식을 기술합니다.

  • Mariabackup의 세부 조작 명령어는 MariaDB 문서에서 이미 상세하게 기술하고 있으므로 굳이 작성하지 않았습니다.

  • 대신, 키워드마다 상세 내용을 참조할 수 있는 링크를 걸어 두었으므로 참고하시기 바랍니다 :)



운영 환경

  • 호스트 OS:
$ cat /etc/issue
Ubuntu 16.04.6 LTS
  • MariaDB 도커 이미지:
REPOSITORY          TAG    
mariadb/server      latest
  • 컨테이너 OS:
$ cat /etc/issue
Ubuntu 18.04.3 LTS
  • 컨테이너 MariaDB 버전:
$ mysql
> select version()
10.4.8-MariaDB-1:10.4.8+maria~bionic-log


백업 형태

Mariabackup을 이용한 증분백업을 사용한다.

증분 백업 이란?

  • 증분 백업(Incremental Backup)

    • 선택된 디렉토리의 전체 백업 이후, 변경되거나 추가된 데이터만 선택적으로 백업
    • 전체 백업보다 데이터양이 적고 소요 시간이 짧다는 장점이 있으나, 전체 백업에 종속적
  • 전체 백업(Full Backup)

    • 선택된 디렉토리의 데이터를 모두 백업하는 방식
    • 매번 전체 데이터를 백업하기 때문에 복원 과정은 편리하지만, 데이터양의 증가에 따라 백업의 소요 시간이 늘어난다.

증분 백업을 선택한 이유

전체 백업을 매일 수행하면 복원 과정이 편하지만, 증분 백업은 전체 백업과 달리 추가된 데이터만 선택적으로 백업하기 때문에 백업에 드는 시간과 부하가 적다.



백업 도구

mysqldump vs Mariabackup

1. mysqldump

  • SQL 형태로 백업과 복원을 진행하는 논리적 백업.

  • 데이터베이스의 모든 행을 스캔하고 각각의 행과 테이블마다 Insert 구문을 생성한다.

  • 백업 시 생성한 Insert 구문을 그대로 재생하면서 복원이 진행된다.

2. Mariabackup

Mariabackup을 채택한 이유

  • 일반적으로 사용하는 mysqldump 명령어로도 증분 백업을 실행할 수 있지만, 데이터가 증가할수록 백업과 복원에 걸리는 시간이 Mariabackup과 월등히 차이 난다.

  • 백업 및 복원 시간 비교 (데이터 크기: 약 20GB 기준)

-mysqldumpMariabackup
백업3분3분
복원50분4분

참고: 좀 더 큰 스케일의 데이터를 다루는 기업의 비교 결과 ('mysqldump vs XtraBackup' 챕터)



컨테이너(Container) 기반 MariaDB의 증분백업

  • 현재 사내 중앙 데이터베이스로 사용하는 MariaDB 서버는 도커 컨테이너(Docker Container) 상에서 운영하고 있다.

  • 일반적으로 Mariabackup은 원격으로 접근이 불가하다.

  • 호스트에서 Mariabackup을 실행하여 컨테이너 상의 DB 서버를 백업할 수 없다. (그림 1-1)

  • 그러므로, 호스트에서 해당 MariaDB 서버가 위치한 컨테이너로 접근하여 컨테이너 상에서 Mariabackup을 실행하도록 한다. (그림 1-2)

  • 백업 파일은 호스트-컨테이너 간 볼륨을 설정하여 백업 시 호스트의 볼륨 디렉토리에도 저장하도록 한다. (그림 2)

  • Mariabackup 명령어 앞에 해당 DB 컨테이너에 접근하는 명령어를 먼저 작성한다.

docker exec "컨테이너 이름" /usr/bin/mariabackup ...

그림 1. Mariabackup으로 컨테이너 형태의 MariaDB를 백업하는 방법


그림 2. 호스트-컨테이너 간 볼륨(Volume) 설정



백업

백업 스케쥴

  • 1주를 기준으로 트래픽이 가장 적은 요일의 시간대에 전체 백업, 그 외의 요일에는 증분 백업을 한다.

  • 처음 한 번만 전체 백업을 하고 계속 증분 백업만 하는 방식도 있지만,
    추후 복원 작업 시 모든 증분 데이터를 맨 처음의 전체 백업 데이터에 업데이트시켜주어야 하기 때문에 복원 과정이 복잡하다.

$ crontab -l

SHELL=/bin/bash

# Full backup - Every Sunday - 매주 일요일 새벽 2시 전체 백업
0 2 * * SUN /masterdb/master/backup_scr/fullback.sh >> /masterdb/master/backup_scr/log/full.log 2>&1
 
# Incremental backup - Every Monday to Saturday - 매주 월 ~ 토 새벽 2시 증분 백업
0 2 * * 1-6 /masterdb/master/backup_scr/increback.sh >> /masterdb/master/backup_scr/log/inc.log 2>&1

참고: 실행하는 .sh 파일은 root 권한이 필요하다. chmod +x '스크립트 이름' 명령어로 파일에 접근 권한을 부여한다.


1. 전체 백업(Full Backup)

  • 증분 백업이 참조할 기본 백업 데이터

  • 증분 백업을 실행하기 이전에 반드시 전체 백업을 먼저 실행해야 한다.


2. 증분 백업(Incremental Backup)

  • 전체 백업 데이터의 LSN(로그 시퀀스 번호)을 참조하여 마지막으로 변경된 지점부터 백업을 실행한다.

  • LSN은 백업 데이터 디렉토리의 'xtrabackup_checkpoints' 파일에 표기된다.

  • 첫 증분 백업은 전체 백업 데이터를 참조하지만, 이후에 추가로 진행되는 증분 백업은 가장 최근에 진행된 증분 백업 데이터를 참조한다.

  • 전체 백업 데이터의 xtrabackup_checkpoints 내용:

backup_type = full-backuped
from_lsn = 0 (시작 지점)
to_lsn = 22886365542 (종료 지점)
last_lsn = 22886365551
  • 증분 백업 데이터의 xtrabackup_checkpoints 내용:
backup_type = incremental
from_lsn = 22886365542 (기본 백업 데이터의 'to_lsn'을 기준으로 백업을 실행)
to_lsn = 22886370181
last_lsn = 22886370190

복원

복원 준비(Prepare)

  • 복원 준비를 통해 백업 중에 발생했던 데이터의 업데이트 사항들을 반영하여 데이터의 일관성을 유지한다.

  • 만약 백업 중에 업데이트가 발생했으나 복원 준비를 하지 않은 상태에서 복원을 시도하면, InnoDB 엔진이 이를 발견하고 복원을 거부한다.


1. 전체(기본) 백업 복원 준비

$ mariabackup --prepare --target-dir="$Full Backup"

2. 증분 백업 복원 준비

  • 전체 백업 데이터를 Target으로 하여 기존의 증분 백업 데이터를 순차적으로 업데이트 한다.
$ mariabackup --prepare --target-dir="$Full Backup" --incremental-dir="inc1"

예:

전체 백업 데이터 복원 준비:
$ mariabackup --prepare --target-dir="$Full Backup"

전체 백업 데이터 <- 증분1:
$ mariabackup --prepare --target-dir="$Full Backup" --incremental-dir="inc1"

전체 백업 데이터 <- 증분2:
$ mariabackup --prepare --target-dir="$Full Backup" --incremental-dir="inc2"

전체 백업 데이터 <- 증분3:
$ mariabackup --prepare --target-dir="$Full Backup" --incremental-dir="inc3"

...

복원(Restore) 실행

복원 조건

  1. 복원을 위해 MariaDB의 서비스를 잠시 중단

  2. DB data 디렉토리(일반적으로 '/var/lib/mysql/')가 비워져 있어야 한다.

  3. 앞서 준비된 전체 백업 데이터로 복원을 진행한다.

컨테이너 형태의 MariaDB 복원 (그림 3)

  • 복원 조건 1. 을 충족시키려면 컨테이너를 정지해야 한다. ($ docker stop)

  • 정지한 컨테이너에서는 Mariabackup 명령어를 내릴 수 없으므로,
    원본 컨테이너의 DB 데이터 및 백업 데이터 디렉토리에 접근할 수 있는 또 하나의 DB 컨테이너(이하 Mirror )를 띄운다.

  • Mirror에서 Mariabackup 명령어로 복원을 진행한다.

  • 원본 컨테이너를 재시작하면, Mirror와 볼륨을 공유하므로 복원한 데이터가 원본 컨테이너에도 그대로 적용된다.

  • 복원 명령

$ mariabackup --copy-back --target-dir=/var/mariadb/backup/
  • docker를 이용한 복원 명령
$ sudo docker exec "$MirrorContainer" /usr/bin/mariabackup --copy-back \
	--target-dir="$backupPath"

그림 3. 컨테이너 상에서 Mariabackup을 이용한 복원 구조



Binary_Log 를 이용한 복원

Binary_Log

앞서 증분 백업을 통해 매일 새벽 2시에 백업을 하도록 설정했다.

만약 당일 오후 4시에 DB의 데이터가 손실되는 상황이 발생했다면

백업 이전까지의 데이터는 생성된 백업 파일을 통해 1차로 복원이 가능하다.

하지만 백업 시점 이후 ~ 다음 백업 시점 이전(오늘 새벽 2시 ~ 내일 새벽 2시)의 데이터는 어떻게 복원해야 할까?

이 경우, binary_log(이하 bin_log)를 통해 나머지 데이터의 복원을 진행할 수 있다.


  • bin_log는 데이터베이스에 대한 모든 변경 사항을 기록하는 이진 숫자 로그 파일이다.

  • 데이터베이스에서 일어났던 select, insert, update, delete 등의 데이터 조작 명령을 그대로 기록하기 때문에 데이터 복원에 활용할 수 있다.


Binary_Log 활성화

  • bin_log 기능은 기본적으로 비활성화되어 있다.

  • DB를 구동할 때 옵션(--log-bin)을 주거나, 설정 파일(/etc/mysql/my.cnf)에서 활성화할 수 있다.


도커 컨테이너에서 Bin_Log 활성화

  • 컨테이너에 접근하여 직접 설정 파일을 수정할 수도 있지만, 컨테이너를 재시작할 때마다 수정해야 하므로 번거롭다.

  • (1) 내가 설정하려는 항목들만 작성한 설정 파일(.cnf)을 볼륨 설정하면, DB 전체 설정에 추가로 반영할 수 있다.

  • (2) 혹은, docker-compose 파일에서 컨테이서 생성 시 bin-log 활성화 명령어를 설정할 수 있다.


1. 사용자 설정 파일(custom.cnf)

.cnf 작성

[mysqld]
log_bin          = /var/log/mysql/mariadb-bin (bin-log 활성화 여부 결정 및 저장할 디렉토리와 파일 이름 결정. 
                                                  'mariadb-bin.000001, mariadb-bin.000002 ... '로 생성된다.)

expire_logs_days = 3  (보관 기간 - 생성된 지 3일이 지난 로그는 삭제한다.)

max_binlog_size  = 100M  (작성하는 로그 파일의 크기가 100MB를 넘으면 새로운 로그 파일을 생성한다.)

참고: 사용자 설정 파일을 어떤 디렉토리에 넣어야 할지는 mariadb.cnf에서 알 수 있다.

/etc/mysql/mariadb.cnf:

# Import all .cnf files from configuration directory
!includedir /etc/mysql/mariadb.conf.d/

💡👀'_!incluedir'는 지정된 디렉토리 이하의 파일을 추가 설정 파일로 읽어 들인다._

적용

  • 사용자 설정 파일을 컨테이너 내 지정된 디렉토리와 볼륨 설정한다.

그림 4. 사용자 설정 파일(.cnf) 볼륨 설정


  • 컨테이너를 재구동한 뒤, /var/log/mysql에서 생성된 bin_log를 통해 활성화 여부를 확인할 수 있다.

그림 5. 생성된 bin-log


2. Docker-Compose 파일에서 명령어 작성

.yml 작성

version: '3'
services:
        mariadb:
          image: mariadb/server:latest
          container_name: master_db
          restart: always
          ports:
                - "3306:3306"
          environment:
                MYSQL_ROOT_PASSWORD: ${MYSQL_PW}
                TZ: Asia/Seoul

          volumes:
                  - /data/db/maria/fic/data:/var/lib/mysql
                  - /data/db/maria/fic/backup:/var/mariadb/backup
                  - /data/db/maria/fic/binlog:/var/log/mysql
          command: ['mysqld','--character-set-server=utf8mb4','--collation-server=utf8mb4_unicode_ci', '--log-bin=/var/log/mysql/mariadb-bin', '--expire-logs-days=3', '--max-binlog-size=100M' ]
          

💡👀'command' 행에 다음과 같이 명령어를 작성해준다.
['mysqld', 
'--log-bin=/var/log/mysql/mariadb-bin', 
'--expire-logs-days=3', 
'--max-binlog-size=100M'
]

💡 bin_log 옵션에 관한 자세한 설명은 아래의 링크를 참조할 수 있다.


복원

  • 미리 백업한 데이터를 통해 1차로 복원했다면, 백업 시점 이후 백업되지 않은 데이터들은 bin_log를 통해 복원 작업을 완료할 수 있다.

  • 해당 백업 시점의 마지막 포지션과 일치하는 bin_log 파일 및 포지션을 찾아야 한다.


포지션 확인

백업 당시 마지막 포지션은 xtrabackup_binlog_info 파일에서 찾을 수 있다.

  • xtrabackup_binlog_info
bin_log_파일_이름    포지션 
mariadb-bin.000001  21876   0-1-40

해당 bin_log 수정

복원을 진행하기 전에 bin_log를 텍스트 형태로 변환하여 장애가 발생한 쿼리가 있다면 확인하여 삭제해준다.

  • bin_log를 사람이 읽을 수 있는 형태로 변환
$ mysqlbinlog "$bin_log_name" > binlog.sql 

복원 실행

mysqlbinlog 명령어로 해당 bin_log를 이용하여 복원을 진행한다.

$ mysqlbinlog --start-position=21876 mariadb-bin.000001 | mysql -u root -p

Binary_Log 원격 저장

  • 도커 컨테이너 형태로 DB 서버를 운영하고 있으면, DB 서버에 장애가 발생해 컨테이너로 접근할 수 없는 경우를 대비해야 한다.

  • 컨테이너 생성 시 볼륨을 설정하면 컨테이너에서만 접근할 수 있는 bin_log를 호스트에서도 관리할 수 있게 된다. (그림 6)

그림 6. bin_log 볼륨 설정


권한 설정

1.

단순히 볼륨만 설정하고 컨테이너를 생성하면, 컨테이너가 계속해서 재시작하며 정상적으로 운영되지 않는다.

$ sudo docker logs '컨테이너 이름'

2020-01-03 14:34:59 0 [Note] mysqld (mysqld 10.4.7-MariaDB-1:10.4.7+maria~bionic-log) starting as process 1 ...
2020-01-03 14:34:59 0 [ERROR] mysqld: File '/var/log/mysql/mariadb-bin.index' not found (Errcode: 13 "Permission denied")
2020-01-03 14:34:59 0 [ERROR] Aborting

💡👀위의 로그를 살펴보면 "Permission denied "라는 문구를 볼 수 있다.


2.

컨테이너 내부에서 bin_log를 저장하는 디렉토리의 권한은 기본적으로 "mysql: adm(소유자:그룹)"으로 구성되어 있다.

$ ls -al
             
drwxr-xr-x 2 mysql  adm  4096 Jan 10 16:00 mysql
            (소유자)(그룹)

3.

디렉토리에 대한 권한을 얻으려면 그룹을 변경해주면 된다.

소유자가 속한 그룹을 우리가 사용하는 그룹인 root 그룹으로 바꿔줘야 한다.


컨테이너 구동 후, 도커 명령어로 컨테이너 쉘에 접근하여 변경한다.
$ sudo docker exec mifdb chown mysql:root /var/log/mysql

4.

위의 명령어를 수행한 후, bin_log 디렉토리의 소유자 그룹이 다음과 같이 변경되어 있음을 확인할 수 있다.

$ ls -al
             
drwxr-xr-x 2 mysql  root  4096 Jan 10 16:00 mysql
            (소유자) (그룹)

호스트의 볼륨 디렉토리에 bin_log 파일이 들어 있다면 볼륨 설정이 완료된다.



결론

Mariabackup을 이용한 증분 백업과 Binary_Log를 이용한 백업 방식을 알아보았습니다.

지속적으로 쌓이는 데이터들을 안정적으로 백업할 수 있는 방식 중 하나로써 사용할 수 있을 것 같습니다.

내용 중 부족한 점이 있다면 얼마든지 댓글 달아주세요 :)

profile
뿌리가 튼튼한 사람이 되고자 합니다.

0개의 댓글