Database JUNKY

MySQL,MariaDBを中心としたブログです

レプリケーションを利用したMySQLのサービス無停止バックアップ

MySQLのバックアップってどうやってますか?単純なバックアップであれば、mysqldumpでもデータディレクトリを丸ごとコピーでも好きな方法でやればいいと思いますが、じゃあそれが止めることが許されないサービスだったら?というところを突き詰めて「サービス無停止バックアップ」について考えてみたいと思います。

 

ここで説明する想定の条件は以下の通りとします。

MySQLのサーバ数は、20台で、20台それぞれが異なるスキーマである ・MySQLのテーブルはInnoDBテーブルのみ ・MySQLサーバーを止めずにバックアップする ・4重のバックアップ手法をとり、どんなことがあろうと障害復旧時点までリカバリできる構成を作ること

ここでは、有償の製品の話は割愛しますね。MySQLinnodbのバックアップ方法は2通りあり、一つは、前述の通りなのですが、MySQLサービスを停止して、ディレクトリごと、丸々コピーする方法と、mysqldumpでスキーマのバックアップをとる方法があるのですが、そちらにしてもサービスは止まり、ディレクトリごとバックアップする方法に関しては、そもそもサービスを停止する方法があるのでNGですし、mysqldumpに関しては、mysqldump取得時に、テーブルにロックがかかりますよね。なので、「止めることが許されないサービス」には当てはまらないのです。Oracle社は公式に、バックアップはサービスを止めてディレクトリ毎コピーすることを推奨しております。

・・で以下の4つを中心に考え、サービス無停止バックアップを考えてみます。

MySQLのバックアップは、mysqldumpを利用 mysqldumpはmysqldumpであってバックアップではないの理解しつつ、あえてこれを利用します

レプリケーションを利用する 上記方法だけは要件を満たすことができないため、今回はMySQLレプリケーションを応用して検討します

▼ バイナリログのローテートを活用する バイナリログのローテート先を対象DBサーバとは別の筐体に保存し、ハードディスク障害のリスクを分散します。

▼ バックアップ集中サーバを構築する 潤沢に資金があるのであれば、1サーバ毎に1バックアップサーバでいけるのですが、ただバックアップのためにだけ・・それらのサーバを容易するのは、金銭面で苦労するでしょう。なのでバックアップ集中サーバは一台で回していきます。

今回の検証では、以下のサーバがあると仮定します。

・マスターサーバ > ブログスキーマ * 1台 : <<host;sqdbm01>> > ログ * 1台 : <<host:sqdbm03>>

・バックアップサーバ > バックアップ集中サーバ * 1台 : <<host:sqdbm99>>

・ファイルサーバ > NFSサーバ * 1台 : <<host:sqnas01>>

というわけで合計 5台です。今回ここで説明するのは、バックアップサーバの話だけです。バックアップサーバ集中サーバ以外のホストにつきましては、別に何も設定は必要ではありません。


▼集中バックアップサーバを構築する MySQLのインストール手順については割愛します、mysqlrpmでインストールしております。

・my.cnfの編集 my.cnfの編集をします。図のとおり、複数のDBサーバから一台のバックアップスレーブサーバにデータをレプリケーションする構成のため、MySQLのマルチ起動をする必要があります。mysqlには、mysqld_muiti というユティリティがあるのですが、私的には、my.cnfの管理がしずらく、あまり便利なユティリティにも思えなかったため、mysqld_safe で個々にプロセスを起動する方法をとりました。なので手順は一般的なものと違いますので、mysqld_muitiでやりたい方は、その設定に併せてください。

・ポート毎のディレクトリを作成 ポート毎(socket毎)にデータディレクトリを分けます。 [shell] [root@sqdbm99 ~]# su - mysql -bash-3.2$ mkdir /var/lib/mysql/data1 -bash-3.2$ mkdir /var/lib/mysql/data2 -bash-3.2$ mysql_install_db --datadir=/var/lib/mysql/data1/ -bash-3.2$ mysql_install_db --datadir=/var/lib/mysql/data2/ [/shell]

・my.cnf の編集 バックアップサーバは・・・ここの環境は、あまりスペックの良いPCではありません。なので、my-small.cnfをベースにします。 レプリケーションマスターは二台なので、二台分のmy.cnfを作成します。変更箇所は、server-idとソケットディレクトリ、およびポート番号です [shell]

[root@sqdbm99 ~]# cp /usr/share/mysql/my-small.cnf /etc/my.cnf

[root@sqdbm99 ~]# diff /usr/share/mysql/my-small.cnf /etc/my.cnf 20,21c20,21 < port = 3306

< socket = /var/lib/mysql/mysql.sock

> port = 3307 > socket = /var/lib/mysql/data1/mysql.sock 28c28

< socket = /var/lib/mysql/mysql.sock

> socket = /var/lib/mysql/data1/mysql.sock 46c46

< server-id = 1

> server-id = 1010

[root@sqdbm99 ~]# cp -arf /etc/my.cnf /etc/my.cnf1 [root@sqdbm99 ~]# cp -arf /etc/my.cnf /etc/my.cnf2 [root@sqdbm99 ~]# vi /etc/my.cnf2 ※ディレクトリとポート番号および、サーバIDのみ変更してください [/shell] ・ポート(ソケット)毎にmysqldを起動する rpmおよびyumでインストールされた方は。/etc/init.d/mysql startとかやっちゃいがちですが、以下のようなパラメータを添えてポート毎に起動してください [shell]

mysqld_safe --defaults-file=/etc/my.cnf1 --datadir=/var/lib/mysql/data1 &

mysqld_safe --defaults-file=/etc/my.cnf2 --datadir=/var/lib/mysql/data2 &

[/shell] ・あとはおのおのの、ソケット毎に、レプリケーション設定を入れるだけです。あ、ちなみに、ソケット毎の接続方法は以下の通りです。

・サーバローカルでの接続方法 [shell]

mysql -u root -pmypassword -S /var/lib/mysql/data1/mysql.sock

mysql -u root -pmypassword -S /var/lib/mysql/data2/mysql.sock

[/shell] ・リモートからの接続方法 [shell]

mysql -u root -pmypassword -p 3306

mysql -u root -pmypassword -p 3307

[/shell]

尚、レプリケーションの設定そのものについては、ポートが違おうとデータディレクトリが違おうと、変わりはないので http://www.s-quad.com/wordpress/?p=1017 あたりを参考にしてください。

▼集中バックアップサーバからバックアップファイルをdumpする ポート毎にmysqlが起動できた、そしてポート毎にレプリケーションが行えた!からバックアップ環境ができたわけではありません。 より確実にバックアップを行うためには、このバックアップサーバ外の部分にデータを退避する必要があります。手順としては、

・slaveを停止する ・mysqldumpを実行する(ポート毎) ・slaveを再開する

だと思います。以下簡単ですが、バックアップのshellみたいのを作成しました(本当はエラーチェック等もっと細かく書きます)

[shell]

cat mysql_backup.sh

!/bin/bash

---------------------------------------------

MySQL BACKUP

$1 mysql port no

---------------------------------------------

. /usr/local/shell/include/mysql_common_functions.sh

LOGDIR=/backups/log LOGFILE=$LOGDIR/mysql_dump.log DATE=date +"%Y%m%d"

datetime

_DATE=date +%Y%m%d%H%M

_HOSTNAME=hostname -a

if [ "$1" != "" ]; then SOCK=" -S /var/lib/mysql/$1/mysql.sock" else SOCK="" fi

BACKUPDIR="/backups/${HOSTNAME}/$1"

ログファイルディレクトリが存在しない場合は新規で作成する

if [ ! -d $LOGDIR ]; then mkdir -p $LOGDIR chmod 775 $_LOGDIR fi

バックアップディレクトリが存在しない場合は新規で作成する

if [ ! -d $BACKUPDIR ]; then echo "create directory $shelldir" mkdir -p $BACKUPDIR chmod 775 $BACKUPDIR fi NOW=date echo " MySQL Backup Start ${NOW}" >> $_LOGFILE

DB Config

DBUSER=myuser DBPASSWD=mypass

mysqldump実行

1) flush table

2) slave stop

3) mysqldump (full)

4) slave start

mysql -u ${DBUSER} -p${DBPASSWD} ${SOCK} -e "flush tables;" mysql -u ${DBUSER} -p${DBPASSWD} ${SOCK} -e "stop slave;" mysqldump -u ${DBUSER} -p${DBPASSWD} ${SOCK} -x --all-databases > ${BACKUPDIR}/${DATE}${HOSTNAME}FULL.dump mysql -u ${DBUSER} -p${DBPASSWD} ${SOCK} -e "start slave;" mysql -u ${DBUSER} -p${DBPASSWD} ${SOCK} -e "show slave status\G;"

バックアップファイルを圧縮

cd ${BACKUPDIR}/ tar cvzf ${DATE}${HOSTNAME}FULL.dump.tar.gz ${DATE}${HOSTNAME}FULL.dump rm -f ${DATE}${HOSTNAME}_FULL.dump

7日まえの古いバックアップファイルを削除する

find ${_BACKUPDIR}/ -mtime +7 -exec rm -f {} \;

NOW=date echo "--backup dir ${BACKUPDIR}" >> $LOGFILE echo "--backup file ${BACKUPDIR}/${DATE}${HOSTNAME}FULL.dump.tar.gz" >> $_LOGFILE

echo " MySQL Backup End ${NOW}" >> $LOGFILE

exit 0

[/shell]

ローテートの話にまったく触れてなかったとです・・・。いかがでしょうか?これでサービス無停止バックアップが実現できる状態になったかと思います。