Changes between Initial Version and Version 1 of MariaDB 증분 백업


Ignore:
Timestamp:
Nov 11, 2025, 6:48:48 PM (4 weeks ago)
Author:
yongwoo
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • MariaDB 증분 백업

    v1 v1  
     1[[PageOutline]]
     2= MariaDB 증분 백업 =
     3증분 백업을 하기 위해서는 맨 처음 full 백업을 하고, 이 이후에는 변경되는 사항들만 모아놓은 ["MariaDB 바이너리 로그" 바이너리 로그] 파일만 백업하면 된다.
     4
     5증분 백업은 ["MariaDB 바이너리 로그" 바이너리 로그] 포맷에 ROW를 지정할 수 있는 5.1.5 이후 버전부터 실질적으로 가능하다. 안전하지 않은 SQL문은 바이너리 로그에서 제대로 복구할 수 없기 때문이다.
     6
     7다음은 복제를 하지 않는 서버에서의 증분 백업 방법이다.
     8
     9== 1. 로그 파일 생성 ==
     10
     11따라서 MySQL 서버가 먼저 ["MariaDB 바이너리 로그" 바이너리 로그] 파일을 만들도록 해야 한다. 디폴트로는 생성하지 않기 때문이다.
     12
     13/etc/my.cnf 파일에 다음 부분을 추가한다.
     14{{{
     15# incremental 백업을 하거나 복제를 하려면 바이너리 로그를 저장해야 한다.
     16# 로그 파일 기본이름은 명시적으로 지정해주는 것을 권장한다. 생략하면 호스트 이름을
     17# 사용하는데, 호스트 이름이 바뀔 경우에는 따라서 변경되기 때문이다.
     18log-bin=mysqld-bin
     19# ROW 포맷이 가장 안전
     20binlog_format=row
     21# InnoDB 트랜잭션 복제를 하기 위해서 마스터에서
     22# innodb_flush_log_at_trx_commit=1과 sync_binlog=1을 지정.
     23# innodb_flush_log_at_trx_commit의 디폴트 값이 1이므로 그냥 생략해도 무방
     24sync_binlog=1
     25# 바이너리 로그 포맷을 ROW로 지정했기 때문에 함수를 만들 때 실수해도
     26# 복제하는 데 문제가 없다. 따라서 NON DETERMINISTIC 함수도 만들 수 있게끔
     27# log_bin_trust_function_creators를 1로 지정한다. 디폴트는 0.
     28log_bin_trust_function_creators=1
     29}}}
     30실제 만들어지는 파일명은 로그 파일 기본이름 뒤에 확장자로 일련번호가 붙는다.
     31
     32로그 파일 기본이름은 명시적으로 지정해주는 것을 권장한다. 생략하면 호스트 이름을 사용하는데, 호스트 이름이 바뀔 경우에는 따라서 변경되기 때문이다.
     33
     34로그 파일 기본이름에 확장자를 지정하면 확장자는 무시한다.
     35
     36== 2. full 백업 ==
     37incremental 백업을 위한 full 백업을 하려면 백업을 시작하기 전에 먼저 메모리에만 있고 아직 로그 파일에 저장하지 않은 변동 사항은 모두 기존 로그 파일에 저장하고 새로운 로그파일을 생성한다.(--flush-logs) 이 때 로그 저장 시점과 백업 시점을 동일하게 하려면 반드시 --lock-all-tables 이나 --master-data=2 옵션과 같이 사용해야 한다.
     38
     39그리고 기존 로그 파일은 지워버린다.(--delete-master-logs) full 백업을 하면 백업 이전에 저장했던 ["MariaDB 바이너리 로그" 바이너리 로그]는 필요가 없기 때문이다.
     40
     41이렇게 하면 남아있는 바이너리 로그 파일에는 백업 이후에 변동된 사항만 남아있게 된다.
     42
     43바이너리 로그를 사용한다면 ["MariaDB 바이너리 로그" 바이너리 로그] 좌표(파일명과 위치)를 알 수 있기 때문에 꼭 슬레이브를 셋업할 목적이 아니라도 -lock-all-tables 대신 --master-data=2 옵션을 쓰는 것이 좋다.
     44
     45{{{
     46mysqldump --master-data=2 --flush-logs --delete-master-logs --all-databases --events > fullbackup.sql
     47}}}
     48 * --master-data[=value]
     49  - ["MariaDB 바이너리 로그" 바이너리 로그]가 활성화되어 있어야 한다.
     50  - 마스터에서 백업받은 것을 가지고 슬레이브를 셋업하기 위해서 사용한다. ["MariaDB 바이너리 로그" 바이너리 로그] 좌표(파일명과 위치)를 가리키는 CHANGE MASTER TO 문을 백업 파일에 기록한다.
     51  - 이 옵션을 사용하기 위해선 RELOAD 권한이 필요하다.
     52  - value 값의 디폴트는 1이다. 따라서 1일 때는 값을 생략할 수 있다.
     53  - value가 2이라면 CHANGE MASTER TO 문이 주석으로 삽입된다. 주석으로 삽입하기 때문에 실제 영향은 없다.
     54  - --single-transaction을 명시적으로 적어주지 않는다면 --lock-all-tables 옵션이 자동으로 지정된다.
     55  - --lock-tables 옵션을 자동으로 끈다.
     56 * --lock-all-tables, -x
     57  - 백업을 하는 동안 모든 데이터베이스를 읽기만 가능하도록 잠근다(READ LOCK).
     58  - 이 옵션을 설정하면 --single-transaction과 --lock-tables 옵션은 자동으로 꺼진다.
     59  - '''데이터베이스의 일관성은 보장되지만 백업이 진행되는 동안 쓰기가 불가능'''해지므로 대용량 데이터베이스인 경우엔 신중하게 해야 한다.
     60  - full 백업 이후의 변경 사항을 복구(point-in-time 복구, roll-forward)하기 위해서라도 --lock-all-tables 명령 대신 --master-data=2 옵션을 주는 것이 좋다.
     61 * --lock-tables, -l
     62  - 백업을 하는 동안 특정 데이터베이스를 잠근다(READ LOCAL lock).
     63  - READ LOCAL LOCK이므로 진행 중인 insert는 허용한다.
     64  - 여러 데이터베이스를 백업할 때는 주의해야 한다. --lock-tables은 각 데이터베이스를 각각 잠근다. 그래서 데이터베이스간에 '''논리적인 일관성이 보장되지 않는다'''.
     65  - '''백업이 진행되는 동안 특정 데이터베이스에 쓰기가 불가능'''해지므로 대용량 데이터베이스인 경우엔 신중하게 해야 한다.
     66  - InnoDB나 BDB 같은 트랜잭션을 지원하는 테이블에는 --single-transaction이 더 나은 옵션이다. 테이블을 전혀 잠글 필요가 없기 때문이다.
     67 * --flush-logs, -F
     68  - 백업을 시작하기 전에 로그를 파일에 저장한다(flush).
     69  - 이 옵션을 사용하기 위해선 RELOAD 권한이 필요하다.
     70  - --all-databases 옵션과 같이 사용하면 각 데이터베이스가 백업될 때마다 각각 그 로그를 저장(flush)한다는 점에 주의한다.
     71  - 그러나 --lock-all-tables, --master-data 옵션이 사용되면 모든 데이터베이스를 잠근 순간에 한꺼번에 로그를 저장(flush)한다.
     72  - 따라서 백업과 로그 저장을 정확히 같은 시각에 하려면 --flush-logs를 --lock-all-tables, --master-data 옵션과 같이 사용해야 한다.
     73 * --delete-master-logs
     74  - ["MariaDB 바이너리 로그" 바이너리 로그]가 활성화되어 있어야 한다.
     75  -  백업 후에 PURGE BINARY LOGS 명령을 내려 ["MariaDB 바이너리 로그" 바이너리 로그]를 지운다.
     76  - --master-data 옵션을 지정하면 자동으로 활성화된다고 나오지만, 실제로는 그러지 않았다.(5.0.77, 10.3.27에서 확인)
     77  - 슬레이브 서버가 연결되지 않은 상태에서 이 옵션을 지정하면 슬레이브 서버가 미처 ["MariaDB 바이너리 로그" 바이너리 로그] 내용을 동기화하기 전에 지워버리기 때문에 복제가 깨진다. 슬레이브 서버가 연결된 상태라면 슬레이브 서버가 로그 파일을 읽는 중에는 지우지 않고 에러를 내기 때문에 안전하다.
     78 * --events
     79  - 명시적으로 적어줘야 mysql.events 테이블을 백업한다. --all-databases 옵션을 줘도 mysql.events 테이블 스키마만 백업하고 데이터는 다음과 같은 경고를 내면서 백업하지 않는다. Warning: Skipping the data of table mysql.event. Specify the --events option explicitly.
     80  - EVENT 권한이 필요하다.
     81 * --quick
     82  - 디폴트 값이므로 따로 지정해주지 않아도 된다. 큰 테이블을 백업할 때 유용하다. --skip-quick 옵션을 사용하면 테이블 데이터를 모두 메모리에 불러온 다음에 백업 파일에 쓰기 시작한다.
     83
     84
     85mysql 데이터베이스 외에는 모두 InnoDB나 BDB 같은 트랜잭션을 지원하는 테이블이고 백업하는 동안 mysql 데이터베이스를 변경하지 않을 거라면 full 백업은 다음과 같다.
     86{{{
     87mysqldump --master-data=2 --single-transaction --flush-logs --delete-master-logs --all-databases --events > fullbackup.sql
     88}}}
     89 * --single-transaction
     90  - '''쓰기를 막지 않'''고도 일관성있게 데이터베이스를 백업할 수 있다.
     91  -  InnoDB 같은 트랜잭션을 지원하는 테이블에만 유용하다. MyISAM 같은 '''트랜잭션을 지원하지 않는 테이블에서는 논리적인 일관성이 보장되지 않는다'''.
     92  - --lock-tables과 같이 쓸 수 없다.
     93  - MySQL Cluster 테이블에는 사용할 수 없다. (확인 필요)
     94  - 백업하는 중에 ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE 명령을 사용하면 문제가 생길 수 있다.
     95
     96== 3. incremental 백업 ==
     97다음 명령을 내리면 /etc/my.cnf 파일에 지정한 로그 파일 기본이름 뒤에 새로운 일련번호가 붙은 파일이 저장된다.
     98{{{
     99/usr/bin/mysqladmin flush-logs
     100}}}
     101
     102이 파일을 백업하면 된다.
     103
     104== 4. 증분 백업 스크립트 ==
     105매번 이 작업을 할 수 없으니 백업 스크립트를 만들어서 매일 작업하는 것이 좋다.
     106
     107- 이 예에서는 백업 파일을 로컬 하드디스크가 아닌 다른 서버의 하드디스크에 저장하는 것으로 가정했다. (/backup 이라는 디렉토리에 마운트해서)
     108- 복제는 사용하지 않는 것으로 가정했다. 복제를 사용한다면 바이너리 로그를 단순히 옮기는 것이 아니라 복사한 후 purge birary logs 명령으로 지워야 한다.
     109- gzip 대신 zstd를 사용하는 것으로 가정했다.
     110
     111{{{
     112#!/bin/bash
     113
     114# 백업 파일을 저장할 곳 마운트
     115/bin/mount  ... /backup
     116
     117
     118# 마운트가 성공했다면
     119if [ $? ]; then
     120
     121        echo "== mysql DB 백업 =="
     122
     123        # dump가 입력 매개변수라면
     124        if [ "$1" == "dump" ]; then
     125                echo "Full Backup 시작 `date`"
     126
     127                # 이전 full 백업과 incremental 백업 삭제
     128                \rm -f /backup/mysql*.zst
     129
     130                /usr/bin/mysqldump --master-data=2 --flush-logs --delete-master-logs --all-databases --events > /backup/mysql`date +\%Y\%m\%d`.sql
     131                # Full 백업에 시간이 많이 걸리는 경우에는 --single-transaction 옵션을 추가한다.
     132                # /usr/bin/mysqldump --master-data=2 --single-transaction --flush-logs --delete-master-logs --all-databases --events > /backup/mysql`date +\%Y\%m\%d`.sql
     133
     134                RETVAL=$?
     135
     136                /usr/bin/zstd -q --rm /backup/mysql`date +\%Y\%m\%d`.sql
     137
     138                echo "Full Backup 완료"
     139        else
     140                echo "바이너리 로그 저장"
     141
     142                /usr/bin/mysqladmin flush-logs
     143
     144                RETVAL=$?
     145
     146                newestlog=`ls -d /var/lib/mysql/mysqld-bin.?????? | sed 's/^.*\.//' | sort -g | tail -n 1`
     147
     148                for file in `ls /var/lib/mysql/mysqld-bin.??????`
     149                do
     150                        if [ "/var/lib/mysql/mysqld-bin.$newestlog" != "$file" ]; then
     151                                /usr/bin/zstd -q --rm "$file"
     152                        fi
     153                done
     154
     155                \mv /var/lib/mysql/*.zst /backup
     156        fi
     157
     158exit $RETVAL
     159
     160        # 마운트 해제
     161        /bin/umount /backup
     162else
     163        echo "could not mount"
     164
     165        exit 1
     166fi
     167
     168exit $RETVAL
     169}}}
     170
     171== 5. 증분 백업 복구 ==
     172(MyISAM 테이블이 손상되었다면 백업 복구보다는 REPAIR TABLE 이나 myisamchk -r 을 먼저 시도하는 것이 좋다.)
     173
     174=== 5.1. full 백업 복구 ===
     175full 백업받은 것의 압축을 풀고 복구한다.
     176{{{
     177gzip -d full-backup.sql.gz
     178mysql < full-backup.sql
     179}}}
     180
     181 * full 백업받았던 당시에 있던 데이터베이스와 동일한 이름의 '''기존 데이터베이스는 모두 삭제가 되니 주의해야 한다.'''
     182 * 만약 mysql을 처음 설치해서 복구하는 것이라면 test 데이터베이스는 수동으로 삭제해줘야 할 것이다. full 백업 당시에 이미 test 데이터베이스는 삭제한 상태이므로 복구 과정에서 test 데이터베이스는 삭제되지 않는다.
     183
     184=== 5.2. 증분 백업 복구 ===
     185증분 백업받은 것의 압축을 풀고 복구한다.
     186{{{
     187gzip -d mysqld-bin.[0-9]*.gz
     188mysqlbinlog mysqld-bin.[0-9]* | mysql
     189}}}
     190mysqlbinlog는 ["MariaDB 바이너리 로그" 바이너리 로그] 파일을 sql 문으로 변환하는 역할을 한다.
     191
     192full 백업할 때 -master-data=2 옵션을 줘서 바이너리 로그 좌표(파일명과 위치)를 알 수 있다면 그 이후부터의 바이너리 로그만 복원하면 된다.
     193{{{
     194mysqlbinlog --start-position=1 "mysql bin로그 경로" > binlog.sql
     195}}}
     196
     197문제가 되는 시점 이전까지만 복구하려고 하면 --stop-datetime 옵션을 사용하면 된다. 정확한 시점을 모르거나 다시 한번 확인을 하기 위해서는 mysqlbinlog의 결과물을 텍스트 파일에 저장한 후 문제가 되는 시점부터의 데이터를 지우는 편이 낫다.
     198{{{
     199mysqlbinlog mysqld-bin.[0-9]* > /tmp/satements.sql
     200... /tmp/satements.sql 수정 후 ...
     201mysql -u root -p -e "source /tmp/statements.sql"
     202}}}
     203
     204
     205복원 목적이 아니라 어떤 SQL문이 실행되었는지 보는 목적이라면 --short-form 옵션을 사용한다. (["MariaDB 바이너리 로그" 바이너리 로그] 포맷이 STATEMENT일 때)
     206{{{
     207mysqlbinlog --database=ppalbang --stop-datetime="2017-06-13 14:00:00" --short-form mysqld-bin.000002
     208}}}
     209
     210바이너리 로그 포맷이 STATEMENT가 아니라 ROW일 때는 --base64-output=DECODE-ROWS --verbose 옵션을 사용한다. 실행한 SQL문을 볼 수는 없지만 어떤 데이터가 변했는지 알아볼 수 있다.
     211{{{
     212mysqlbinlog --database=ppalbang --stop-datetime="2017-06-13 14:00:00" --base64-output=DECODE-ROWS --verbose mysqld-bin.000002
     213}}}
     214
     215== 6. 바이너리 로그 삭제 ==
     216["MariaDB 바이너리 로그" 바이너리 로그] 파일을 백업받지 않고 삭제했을 때는 반드시 full 백업을 해야 한다. 증분 백업 데이터가 지워졌기 때문이다.
     217
     218== 7. 복제를 하는 경우의 증분 백업 ==
     219복제를 하는 경우 슬레이브 서버에서는 증분 백업을 할 수 없다. (복제 쓰레드 외에는 따로 슬레이브 서버에서 업데이트를 하지 않기 때문에) ["MariaDB 바이너리 로그" 바이너리 로그] 파일에는 데이터베이스 변경 사항이 저장되지 않고, 릴레이 로그 파일에는 데이터베이스 변경 사항이 저장되어 있지만 자동으로 지워지기 때문이다.
     220
     221따라서 복제를 하면서 증분 백업을 하기 위해서는 마스터 서버에서 ["MariaDB 바이너리 로그" 바이너리 로그]를 백업받는 수밖에 없다. 슬레이브 서버가 변경 사항을 다 받아가지 않았을 수 있기 때문에 ["MariaDB 바이너리 로그" 바이너리 로그] 파일이 지워지지 않도록 주의해야 한다.
     222
     223["MariaDB 복제#a2.3.바이너리로그를백업하지않고삭제했을때" 바이너리 로그를 백업하지않고 삭제했을 때]를 참조해서 full 백업을 하고 바이너리 로그는 백업 후 purge binary logs 명령으로 지워야 한다. purge binary logs 명령은 슬레이브 서버가 로그 파일을 읽는 중에는 로그 파일을 지우지 않고 에러를 내기 때문에 안전하다. 다만, 슬레이브 서버가 연결되지 않은 상태에서 이 명령을 내리면 복제가 깨진다.
     224
     225----
     226[WikiStart 처음으로], ["MariaDB mysqldump" mysqldump], ["MariaDB mysqlhotcopy" mysqlhotcopy], ["MariaDB mariabackup" mariabackup]