저자: Russell Dyer, 역 한동훈
원문: http://www.onlamp.com/pub/a/onlamp/2005/06/16/MySQLian.html
대규모로 운영중인 MySQL 데이터베이스의 문제는 서버를 중단시키지 않고 전체 백업(clean backup)을 하는 것이다. 백업은 시스템을 느리게 만들며, 백업을 수행중인 테이블과 관련된 데이터가 변경될 수 있기 때문에 데이터 일관성을 해칠 수도 있다. 서버를 다운시키면 일관된 데이터를 얻을 수 있지만 이는 사용자에게 서비스 중단을 의미한다. 반드시 필요하고 어쩔 수 없는 경우라면 서버를 다운시킬 수 있지만, 데이터를 백업하기 위해 매일 서버를 중단하는 것은 받아들이기 어려운 일이다. 날마다 서버를 중단하지 않고 안정적인 백업을 받는 방법은 MySQL에 복제(replication)를 설정하는 것이다.
역주1: 업무상 DB 전체 백업에 해당하는 것이 원어에서는 clean backup이다. 따라서 클린 백업 대신 전체 백업으로 옮겼다.
역주2: MySQL 복제 서비스는 MySQL 3.2 부터 지원한다.
복제는 MySQL 서버의 시스템 구성으로 설정할 수 있으며, 마스터 서버는 데이터를 저장하고, 클라이언트 요청을 처리하며, 슬레이브 서버는 마스터 서버 데이터의 완전한 복사본을 갖고 있으며, 마스터 서버에 변경이 일어나자마자 그에 해당하는 모든 SQL 문장을 복제한다. 로드 밸런싱을 위해 복제를 사용하는 경우도 있지만, 여기서는 데이터 백업을 위해 복제를 사용하는 것에만 관심을 둘 것이다. 슬레이브로 사용할 별도의 서버를 설정하고, 매일 전체 백업을 받기 위해 복제를 중단할 수 있다. 전체 백업이 끝난 다음에 복제를 재시작하면 슬레이브에서는 마스터와 연결되어 있지 않은 시간 동안 변경된 내용들을 마스터에 자동으로 요청한다. 복제는 매우 훌륭한 기능이며 MySQL에 있는 기능이다. 여러분이 할 일은 복제를 설정하는 것 뿐이다.
복제 수행 과정
복제를 설정하는 방법을 설명하기 전에 MySQL이 복제 서버를 어떻게 관리하는지부터 간단하게 살펴봐야 한다. MySQL 복제 서버 관리는 MySQL 버전에 따라 다르지만, 대부분의 시스템에서는 최신 버전을 사용하고 있기 때문에 여기서는 MySQL 4.0 이상의 버전에 대해서만 설명할 것이다.
복제를 사용중일 때 마스터 서버에서 SQL 문장이 실행되면 MySQL은 바이너리 로그(bin.log)에 이를 로그 식별 번호와 같이 기록한다. 그러면 슬레이브 서버는 IO 스레드를 사용해서 정기적으로 변경사항을 추적하기 위해 마스터 서버의 바이너리 로그 파일을 읽어들인다.
변경사항이 있으면 릴레이 로그(relay.log)에 문장을 복사하고, 슬레이브 서버에 마스터 파일(master.info)에 새 식별 번호를 기록한다. 슬레이브 서버는 같은 IO 스레드를 사용해서 마스터 서버의 바이너리 로그를 확인한다. 릴레이 로그에 변경된 내용이 있으면 슬레이브 서버는 SQL 스레드를 사용해서 릴레이 로그에 새 SQL 문장을 기록한다. 슬레이브 서버는 안전 장치로 SQL 스레드를 사용해서 슬레이브 서버의 데이터와 마스터 서버의 데이터가 일치하는지 확인하기 위해 마스터 서버에 질의한다. 비교 결과가 일치하지 않는다면 복제는 중단되고 슬레이브 서버의 에러 로그(error.log)에 에러 메시지를 기록한다. 비교 질의 수행 결과가 일치한다면 슬레이브 서버의 릴레리 로그 파일(relay-log.info) 파일에 새 로그 식별 번호를 기록하고, 마스터 서버의 릴레이 로그 파일의 변경을 모니터링한다.복제 과정은 복잡해 보이지만, 모든 과정은 빠르게 수행되며 마스터 서버 자원을 많이 소비하지 않으면서 안정적인 복제를 보장한다. 또한, 복제 서비스는 마스터 서버와 슬레이브 서버의 my.cnf 설정 파일에 옵션을 몇 줄 추가하는 것으로 설정할 수 있으며, 설정과정도 쉽다. 새로운 서버를 설치하는 경우에도 단순히 마스터 서버의 데이터베이스를 슬레이브 서버에 복사하고, 슬레이브 서버에서 복제를 시작하면 된다.
복제 사용자
복제를 설정하기 위해서는 몇 가지 간단한 절차를 수행하면 된다. 첫번째는 복제 용도로만 사용할 사용자 계정을 설정하는 것이다. 보안상 기존 계정은 사용하지 않는 것이 가장 좋다. 사용자 계정을 설정하기 위해 마스터 서버에 다음 명령을 수행한다. 다음 명령은 root나 GRANT OPTION 권한을 가진 사용자 계정으로 로그인해서 수행해야한다.
GRANT REPLICATION SLAVE, REPLICATION CLIENT
ON *.*
TO "replicant"@"slave_host"
IDENTIFIED BY "my_pwd";
SQL 문장에서 사용자 계정 replicant는 복제에 필요한 권한만 설정되었다. 사용자 이름은 어떤 것이든 사용할 수 있다. "replicant" 대신에 호스트 이름이나 IP 주소를 사용할 수도 있다. 슬레이브 서버에서도 위와 같은 질의를 수행시키면 된다. "slave_host"는 마스터 서버의 호스트 이름이나 IP 주소로 변경하면 된다. 이와 같이 설정하면, 마스터 서버에 장애가 발생해서 잠시 사용할 수 없는 경우 사용자를 DNS 설정이나 다른 방법을 사용해서 슬레이브 서버를 이용하게 할 수 있다. 마스터 서버가 복원된 이후에는 슬레이브 서버에 변경된 데이터를 마스터 서버에 반영하기 위해 복제를 사용할 수 있다. 공교롭게도 이전 버전의 MySQL에서 4.0 버전으로 업그레이드한 경우에 mysql 데이터베이스는 업그레이드되지 않기 때문에 위의 GRANT 문장이 실행되지 않는다. 이전 버전에는 복제와 관련된 권한이 없기 때문이다. 이 문제를 해결하기 위해서는 MySQL 문서에서
Grants 테이블 업그레이드하기를 참고하기 바란다.
서버 설정하기
마스터와 슬레이브에 복제 사용자를 모두 설정했으면, 이번에는 두 서버의 MySQL 설정 파일을 수정해야 한다. 운영중인 운영체제의 종류에 따라 설정 파일은 my.cnf 또는 my.ini일 것이다. Unix 계열 운영체제에서 설정 파일은 /etc 디렉터리에 있으며, 윈도우 시스템에서는 c:\ 또는 c:\windows에 있다. 텍스트 편집기를 사용해서 설정 파일에 [mysqld] 그룹 아래에 다음을 추가한다.
server-id = 1
log-bin = /var/log/mysql/bin.log
서버 식별 번호는 마스터 서버를 식별하기 위한 임의의 숫자다. 대부분의 경우에 어떤 숫자든 사용할 수 있다. 슬레이브 서버에 다른 식별 번호만 부여하면 된다. 두번째 줄은 MySQL에서 바이너리 로그를 수행할 경로와 파일명을 지정하는 것이다. 실제로 사용할 경로와 파일 이름은 원하는 대로 지정할 수 있다. 설정 파일의 디렉터리고 실제로 있는지 확인하고 mysql 사용자가 소유자이거나 또는 디렉터리에 쓰기 권한이 있기만 하면 된다. 또한, 여기서는 파일 이름의 접미어로 ".log"를 사용했지만 서버가 재시작하거나 로그 정보를 다시 시작할 때 ".000001"과 같은 일련번호로 대체된다.
슬레이브 서버의 설정 파일에도 다음을 추가해야 한다. 마스터 서버 연결을 위한 정보와 로그 파일 옵션을 추가한다.
server-id = 2
master-host = mastersite.com
master-port = 3306
master-user = replicant
master-password = my_pwd
log-bin = /var/log/mysql/bin.log
log-bin-index = /var/log/mysql/log-bin.index
log-error = /var/log/mysql/error.log
relay-log = /var/log/mysql/relay.log
relay-log-info-file = /var/log/mysql/relay-log.info
relay-log-index = /var/log/mysql/relay-log.index
꽤 많은 내용을 추가하는 것 같지만 실제로 들여다보면 어렵지 않게 이해할 수 있을 것이다. 첫번째 줄은 슬레이브 서버의 식별 번호이며, 슬레이브 서버를 여러 대 설정할 경우에는 다른 번호를 부여하면 된다. 그러나 단순히 데이터를 백업하는 것을 원하는 경우에는 슬레이브 서버를 한 대이상 설정할 필요는 없을 것이다. 그 다음 섹션은 마스터 서버의 호스트 이름, IP 주소와 같은 마스터 서버 정보에 대한 것이다. 마스터 포트는 MySQL 기본 설정인 3306 포트를 사용하지만 수행성능이나 보안상의 이유로 다른 포트 번호를 사용할 수도 있다. 그 다음은 마스터 서버에 로그인하기 위한 사용자 이름과 비밀번호다.
다음 두 섹션은 로그를 설정하기 위한 것이다. 처음 섹션은 마스터 서버에서 했던 것처럼 슬레이브 서버에서 바이너리 로그를 기록하기 위한 것이다. 이 설정은 앞에서 얘기한 것처럼 필요시 마스터 서버와 슬레이브 서버간에 역할을 서로 바꿀 수 있게 하기 위한 것이다. 바이너리 로그 인덱스 파일(log-bin.index)는 현재 사용하는 바이너리 로그 파일 이름을 기록하기 위한 것이다. 서버가 재시작되거나 로그들을 정리한 경우에 현재 로그 파일이 변경되며, 변경된 로그 파일 이름이 log-bin.index 파일에 기록된다. log-error 옵션은 에러 로그를 기록한다. 복제와 관련된 문제가 모두 기록되기 때문에 반드시 이 설정을 해야한다. 마지막 섹션은 릴레이 로그와 관련된 파일들을 설정한다. 릴레이 로그는 성능을 위해 마스터 서버 바이너리 로그의 각 항목을 복사한다. relay-log-info-file 옵션은 마스터 서버의 바이너리 로그에 대한 슬레이브 서버의 로그 파일 위치를 설정한다. 릴레이 로그 인덱스 파일은 복제를 위해 현재 사용중인 릴레이 로그 파일 이름을 관리한다.
데이터베이스 복사와 복제 시작하기
새 마스터 서버에 데이터가 없다면 슬레이브 서버를 재시작하면 된다. 그러나, 데이터가 있는 운영중인 서버에 복제를 설정했다면 복제를 위한 데이터베이스 초기 백업을 수행하는 것과 이 백업을 슬레이브 서버에 복사해야 한다. 데이터베이스를 백업하는 방법은 다양하다. 예를들어, mysqldump를 사용해서 운영중인 서버를 백업할 수 있다. 그러나, 여기에는 운영중인 서버의 데이터 일관성 문제가 남는다. 복제를 설정한 후에는 백업을 받기 위해 서버를 중단시키지 않아도 된다는 사실을 생각해보자. 즉, 일관성을 유지하면서 전체 백업을 받기 위해 사용자가 연결하지 못하게 하는 것도 생각해 볼 수 있다. root만 접근할 수 있는 마스터 서버를 만들기 위해 max_connections 변수를 다음과 같이 초기화할 수 있다.
SHOW VARIABLES LIKE "max_connections";
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 100 |
+-----------------+-------+
SET GLOBAL max_connections = 0;
첫번째 SQL 문장은 필요없지만, 백업이 완료된 후에 max_connections 변수 값을 원래대로 복원하기 위해 초기 값을 알 필요는 있을 것이다. max_connections 값을 0으로 하는 것은 어떤 연결도 허용하지 않지만, 실제로 1개의 연결은 root 사용자를 위해 남겨져 있다. 물론, 이것은 새로운 연결만을 받아들이지 않는다. 따라서 현재 실행중인 연결을 보기 위해서는 SHOW PROCESSLIST;를 입력한다. 수행중인 프로세스를 종료하기 위해 KILL 문장을 사용할 수 있다.
서버에 독점적으로 액세스할 수 있으면 mysqldump는 매우 빠르게 수행된다. 마스터 서버의 명령줄에서 다음 명령을 입력한다.
mysqldump --user=root --password=my_pwd \
--extended-insert --all-databases \
--master-data > /tmp/backup.sql
위 문장은 모든 데이터베이스와 테이블을 생성하고, 데이터를 생성하는 SQL 문장으로 구성된 텍스트 파일을 생성한다. --extended-insert 옵션은 한번에 여러 줄을 넣을 수 있는 INSERT 문장을 만들어 주기 때문에 결과적으로 보다 빠르게 백업을 수행할 수 있으며, 최소한의 다운 타임을 갖는데 도움이 된다. --master-data 옵션은 덤프하는 동안 데이터가 변경되지 못하게 모든 테이블을 잠그지만, 사용자가 테이블을 읽어들이는 것은 허용한다. 독점적인 액세스 환경인 경우 이 기능은 필요하지 않다. 그러나, 이 옵션은 덤프 파일의 마지막에 다음과 같은 내용을 추가해준다.
--
-- Position to start replication from
--
CHANGE MASTER TO MASTER_LOG_FILE="bin.000846" ;
CHANGE MASTER TO MASTER_LOG_POS=427 ;
슬레이브 서버에서 덤프 파일이 실행될 때, 위 내용은 테이블이 잠겨 있는 동안 마스터 서버의 바이너리 로그 파일 이름과 백업 시점에서의 로그 위치를 기록한다. 복제가 시작될 때 이 로그 파일에 액세스하게 되고, 해당 위치부터 시작해서 기록된 SQL 문장을 수행한다. 즉, 슬레이브 서버가 설정되는 동안 변경된 데이터가 누락되지 않게 해준다. 슬레이브 서버에서 데이터베시으와 데이터를 설정하기 위해 덤프 파일을 실행하기 위해 덤프 파일을 슬레이브 서버에 복사한다. MySQL이 실행중인지 확인하고 슬레이브 서버에서 다음과 같이 입력한다.
mysql --user=root --password=my_pwd < /tmp/backup.sql
위 명령은 덤프 파일에 있는 CREATE, INSERT 문을 포함한 모든 SQL 문장을 실행한다. 백업된 데이터베이스가 슬레이브 서버에 모두 올라온 다음에는 슬레이브에 root로 로그인해서 다음 SQL 문장을 실행한다.
START SLAVE;
이 문장을 실행하면, 슬레이브는 마스터에 연결하고, 백업 이후로 누락된 변경사항을 가져온다. 이 시점부터 마스터 서버의 바이너리 로그 파일을 지속적으로 검사하면서 항상 최신의 상태를 유지한다.
복제를 이용한 백업
복제가 실행중일 때, 데이터 백업을 하는 것은 쉬운 작업이다. 먼저, 슬레이브 서버에 root 또는 SUPER 권한이 있는 사용자로 로그인하여 다음 SQL 문을 입력해서 슬레이버 서버의 복제를 잠시 중단시킨다.
STOP SLAVE;
슬레이브 서버는 마스터 서버의 바이너리 로그에 남겨진 위치를 알고 있다. 따라서, 슬레이브 서버에서 복제된 데이터베이스를 백업하면 된다. 백업 유틸리티 등을 사용하여 백업을 하고, 백업이 모두 완료되면 다음 명령을 실행해서 복제를 재시작하면 된다.
START SLAVE;
위 문장을 입력하면, 슬레이브 서버는 중단된 시점부터의 SQL 문장을 실행하고, 다시 최신의 상태를 유지하게 된다.
백업 자동화하기
복제와 백업이 올바르게 동작한다면 슬레이브 서버에서 복제를 중단하고, 데이터를 백업받고, 다시 슬레이브를 시작하는 간단한 쉘 스크립트를 작성할 수 있다.
#!/bin/sh
date = `date +%Y%m%d`
mysqladmin --user=root --password=my_pwd stop-slave
mysqldump --user=root --password=my_pwd --lock-all-tables \
--all-databases > /backups/mysql/backup-${date}.sql
mysqladmin --user=root --password=my_pwd start-slave
이 예제에서는 슬레이브에서 복제를 중단하고 시작하기 위해 mysqladmin을 사용했다. 첫번째 줄에서 시스템 함수 date와 적절한 형식(예, 20050615)을 사용한 데이터를 사용해서 스크립트에서 mysqladmin에서 날마다 덤프 파일의 이름을 변경할 수 있게 했다. 물론, 덤파 파일의 경로와 이름을 원하는 대로 설정할 수 있다. date 함수와 서식지정 코드는 (")아 아니라 (`)을 사용한 것에 주의해야한다.
이것은 간단한 스크립트이고, 여러분은 보다 정교한 것을 작성하거나 오류 점검을 할 수 있는 것을 작성할 수도 있다. 공간을 절약하기 위해 덤프 파일을 압축하고, 압축한 파일을 테이프나 CD와 같은 매체에 저장할 수도 있다. 스크립트를 설정했으면 잘 동작하는지 테스트하기 바란다. 스크립트가 잘 동작한다면 crontab이나 서버에서 사용하는 스케줄링 유틸리티를 사용해서 스크립트를 추가하면 된다.
결론
복제는 MySQL에서 유용한 관리 기능이다. 복제는 데이터베이스의 주기적인 백업을 보장하는 훌륭한 방법이다. 복제에 대해 여기서 설명한 것보다 더 많은 옵션과 SQL 문장이 있으며, 이에 대해서는 내가 쓴 MySQL in a Nutshell에서 다루었다. 운영중인 대규모 시스템에서는 보다 강력한 데이터 보호를 위해 슬레이브 서버를 한 대 이상 설정할 수도 있다. 다중 슬레이브 서버 구성은 단일 슬레이브 서버 구성과 마찬가지로 설정과 개념은 동일하다. 극단적으로 많은 트랜잭션이 발생하는 데이터베이스에 대해서는
Emic과 같은 소프트웨어를 고려해볼 수 있다. Emic의 소프트웨어는 비싸지만, 백업과 로드 밸런싱을 위한 슬레이브 서버 관리를 위한 작업을 훌륭하게 수행한다.