# 12.4 バックアップとリストア
この節ではアプリケーションプログラムを管理するもうひとつの側面について討論したいとおもいます：サーバ上で生成されたデータのバックアップとリストアについてです。サーバのネットワークが切断されたり、ハードディスクが壊れたり、OSが崩壊したり、データベースが使用できなくなったりという各種以上な状態はよく発生します。そのため、メンテナはサーバ上で発生したアプリケーションとデータに対しリモート障害時のリカバリ、コールドスタンドバイやホットスタンドバイといった準備をする必要があります。以下のご紹介において、どのようにアプリケーションのバックアップを行うか、Mysqlデータベースおよびredisデータベースのバックアップ/リストアについてご説明します。

## アプリケーションのバックアップ
多くのクラスタ環境において、Webアプリケーションプログラムは基本的にバックアップをとる必要はありません。なぜならこれは単なるコードのコピーでしかないからです。ローカルの開発環境またはバージョンコントロールシステムにおいてすでにこれらのコードを保持しています。しかし多くの場合、いくつかの開発サイトにおいてはユーザがファイルをアップロードする必要があり、これらのユーザがアップロードしたファイルに対してバックアップを行う必要があります。現在理にかなった方法はウェブサイトに関係する保存されるべきファイルをクラウドストレージ上に保存するというものです。このようにすることでシステムが崩壊しても、クラウドストレージ上にありさえすれば、データが失われることはありません。

もしクラウドストレージを採用していなかった場合、どのようにしてウェブサイトのバックアップを行うのでしょうか？ここではファイルの同期ツールであるrsyncをご紹介します：rsyncはウェブサイトのコピーを行うことができ、異なるシステムのファイルを同期することができます。もしwindowsであれば、windows版のcwrsyncが必要です。

### rsyncのインストール
rsyncのオフィシャルサイト：http://rsync.samba.org/ において最新版のソースコードを取得できます。当然、rsyncはとても使い勝手のよいソフトウェアですので、多くのLinuxのディストリビューションにおいてその中に収録されています。

ソフトウェアパッケージのインストール

	# sudo apt-get  install  rsync  注：debian、ubuntu 等のライブインストール方法；
	# yum install rsync    注：Fedora、Redhat、CentOS 等のライブインストール方法；
	# rpm -ivh rsync       注：Fedora、Redhat、CentOS 等rpmパッケージによるインストール方法；

その他のLinuxディストリビューションでは、対応するソフトウェアパッケージ管理方法によってインストールしてください。ソースコードパッケージのインストールは

	tar xvf  rsync-xxx.tar.gz
	cd rsync-xxx
	./configure --prefix=/usr  ;make ;make install   注：ソースコードパッケージをコンパイルしてインストールする前にgccといったコンパイルツールをインストールしておく必要があります；

### rsyncの設定
rsyncは主に以下の3つの設定ファイルrsyncd.conf(メインの設定ファイル)、rsyncd.secrets(パスワードファイル)、rsyncd.motd(rsyncサーバの情報)があります。

これらのファイルの設定に関してはみなさんはオフィシャルサイトやその他のrsyncを紹介しているサイトを参考にしていただけます。以下ではサーバサイドとクライアントサイドがどのようにして起動するかご紹介します。

- サーバサイドの起動：

		#/usr/bin/rsync --daemon  --config=/etc/rsyncd.conf

	--daemonオプション方式は、rsyncをサーバモードで実行します。rsyncを起動時に起動するには

		echo 'rsync --daemon' >> /etc/rc.d/rc.local
		
	rsyncのパスワードを設定

		echo 'ユーザ名:パスワード' > /etc/rsyncd.secrets
		chmod 600 /etc/rsyncd.secrets


- クライアントサイドの同期：

	クライアントサイドは以下のコマンドによってサーバ上のファイルと同期することができます：
	
		rsync -avzP  --delete  --password-file=rsyncd.secrets   ユーザ名@192.168.145.5::www /var/rsync/backup
	
	このコマンドの幾つかの要点を以下に簡単に説明します：
	
	1. -avzPとは何か、読者は--helpを使って調べることができます。
	2. --delete はAにおいてファイルを削除すると、同期の際にBは自動的に対応するファイルを削除します。
	3. --password-file クライアントサイドの/etc/rsyncd.secretsで設定されたパスワードで、サーバサイドの /etc/rsyncd.secrets の中のパスワードと一致させる必要があります。このようにcronを実行した場合、パスワードを入力する必要がありません。
	4. このコマンドの中の"ユーザ名"はサーバサイドの /etc/rsyncd.secretsの中のユーザ名です。
	5. このコマンドの中の 192.168.145.5 はサーバのIPアドレスです。
	6. ::www、二つのコロンマークに注意してください。wwwはサーバの設定ファイル /etc/rsyncd.conf にある[www]です。意味はサーバ上の/etc/rsyncd.confに従ってその中の[www]フィールドの内容を同期します。一つのコロンマークの時は設定ファイルに従わず、直接指定したディレクトリを同期します。
	
	同期にリアルタイム性を持たせるため、crontabを設定しrsyncを分毎に同期させてもかまいません。当然ユーザはファイルの重要性によって異なる同期頻度を設定することもできます。
	

## MySQLのバックアップ
アプリケーションのデータベースは現在やはりMySQLが主流です。現在MySQLのバックアップには二種類の方法があります：ホットスタンドバイとコールドスタンドバイです。ホットスタンドバイは現在主にmaster/slave方式をとっています(master/slave方式の同期は現在データベースの読み込みと書き込みを分離しています。ホットスタンドバイでも使用することができます)。どのようにこの方面の資料を設定するのかについては、いくつも検索することができます。コールドスタンドバイの場合、データベースには一定のち円が存在します。しかし、この時間の前のデータを完璧に保証することができます。例えば、誤操作がデータの喪失を引き起こしてしまったような場合、master/slaveモードでは失われたデータを取り戻すことはできません。しかし、コールドスタンドバイではデータの一部を復元することができます。

コールドスタンドバイは一般的にshellスクリプトを使用して時間毎にデータベースのバックアップをとることになります。上で紹介したrsyncによってローカルでないデータセンターのサーバの一つに同期します。

以下はmysqlのバックアップを定期的に行うスクリプトです。mysqldumpプログラムを使用しており、このコマンドはデータベースを一つのファイルにエクスポートします。

	#!/bin/bash

    # 以下の設定情報はご自分で修正してください。
    mysql_user="USER" #MySQLバックアップユーザ
    mysql_password="PASSWORD" #MySQLバックアップユーザのパスワード
    mysql_host="localhost"
    mysql_port="3306"
    mysql_charset="utf8" #MySQLの文字エンコード
    backup_db_arr=("db1" "db2") #バックアップするデータベースの名前、複数の場合は空白によって分けます。例えば("db1" "db2" "db3")
    backup_location=/var/www/mysql  #バックアップされたデータの保存場所、末尾に"/"を含めないようにしてください。この項目はデフォルトのままでもかまいません。プログラムは自動的にディレクトリを作成します。
    expire_backup_delete="ON" #期限の切れたバックアップの削除するかどうか。ONで起動、OFFで停止
    expire_days=3 #期限の日数。デフォルトは3日、この項目はexpire_backup_deleteを起動した時のみ有効です。

    # この行以降は修正する必要はありません。
    backup_time=`date +%Y%m%d%H%M`  #バックアップの詳細な時間を定義
    backup_Ymd=`date +%Y-%m-%d` #バックアップのディレクトリの年月日を定義
    backup_3ago=`date -d '3 days ago' +%Y-%m-%d` #3日前の日時
    backup_dir=$backup_location/$backup_Ymd  #バックアップディレクトリの絶対パス
    welcome_msg="Welcome to use MySQL backup tools!" #ウェルカムメッセージ

    # MYSQLが起動しているか判断します。mysqlが起動していなければバックアップから抜けます。
    mysql_ps=`ps -ef |grep mysql |wc -l`
    mysql_listen=`netstat -an |grep LISTEN |grep $mysql_port|wc -l`
    if [ [$mysql_ps == 0] -o [$mysql_listen == 0] ]; then
            echo "ERROR:MySQL is not running! backup stop!"
            exit
    else
            echo $welcome_msg
    fi

	# mysqlデータベースに接続します。接続できなければバックアップから抜けます。
    mysql -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password <<end
    use mysql;
    select host,user from user where user='root' and host='localhost';
    exit
    end

    flag=`echo $?`
    if [ $flag != "0" ]; then
            echo "ERROR:Can't connect mysql server! backup stop!"
            exit
    else
            echo "MySQL connect ok! Please wait......"
            # バックアップのデータベースが定義されているか判断します。定義されていればバックアップを開始し、そうでなければバックアップから抜けます。
            if [ "$backup_db_arr" != "" ];then
                    #dbnames=$(cut -d ',' -f1-5 $backup_database)
                    #echo "arr is (${backup_db_arr[@]})"
                    for dbname in ${backup_db_arr[@]}
                    do
                            echo "database $dbname backup start..."
                            `mkdir -p $backup_dir`
                            `mysqldump -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password $dbname --default-character-set=$mysql_charset | gzip > $backup_dir/$dbname-$backup_time.sql.gz`
                            flag=`echo $?`
                            if [ $flag == "0" ];then
                                    echo "database $dbname success backup to $backup_dir/$dbname-$backup_time.sql.gz"
                            else
                                    echo "database $dbname backup fail!"
                            fi
                            
                    done
            else
                    echo "ERROR:No database to backup! backup stop"
                    exit
            fi
            # 期限切れのバックアップを削除するよう設定されていれば、削除操作を実行します。
            if [ "$expire_backup_delete" == "ON" -a  "$backup_location" != "" ];then
                     #`find $backup_location/ -type d -o -type f -ctime +$expire_days -exec rm -rf {} \;`
                     `find $backup_location/ -type d -mtime +$expire_days | xargs rm -rf`
                     echo "Expired backup data delete complete!"
            fi
            echo "All database backup success! Thank you!"
            exit
    fi
    
shellスクリプトの属性を修正します：
    
	chmod 600 /root/mysql_backup.sh
	chmod +x /root/mysql_backup.sh

属性を設定すると、コマンドをcrontabに追加します。私達は毎日00:00に定時で自動バックアップを行うよう設定しましたので、バックアップスクリプトのディレクトリ/var/www/mysqlをrsyncの同期ディレクトリに設定します。

	00 00 * * * /root/mysql_backup.sh

## MySQLのリストア
MySQLのバックアップにはホットスタンドバイとコールドスタンドバイがあるとご説明しました。ホットスタンドバイは主にリアルタイムのリストあを実現するために用いられます。例えば、アプリケーションサーバにおいてハードディスクの故障が発生した場合、設定ファイルを修正することでデータベースの読み込みと書き込みをslaveに移すことでサービスの中断をなるべく少ない時間に抑えることができます。

しかし時にはコールドスタンドバイによるバックアップのSQLからデータを復元する必要があります。データベースのバックアップがあるので、コマンドによってインポートすることができます。

	mysql -u username -p databse < backup.sql
	
データベースのデータをエクスポートまたはインポートするのはかなり簡単でしょう。しかしパーミッションや、文字エンコードの設定も管理する必要がある場合、すこし複雑になるかもしれません。しかしこれらはどれもコマンドによって完了することができます。

## redisのバックアップ
redisは現在我々が最もよく使っているNoSQLです。このバックアップにも二種類があります：ホットスタンドバイとコールドスタンドバイです。redisもmaster/slaveモードをサポートしています。ですので、我々のホットバックアップはこの方法によって実現することができます。対応する設定についてはみなさんオフィシャルのドキュメントにある設定をご参考ください。とても簡単です。ここではコールドスタンドバイについてご紹介します。redisは実はメモリ内のキャッシュデータをデータベースファイルの中に定期的に書き込んでいます。我々のバックアップではただ対応するファイルをコピーするだけで十分です。つまり、前にご紹介したrsyncによってローカルでないデータセンターにコピーを行うだけで実現します。

## redisのリストア
redisのリストアはホットバックアップとコールドバックアップに分けられます。ホットバックアップの目的と方法はMySQLのリストアと同じです。アプリケーションで対応するデータベースに接続するだけでかまいません。

しかし時にはコールドバックアップによってデータをリストアする必要もあります。redisのコールドバックアップは実は保存されたデータベースファイルをredisのワーキングディレクトリにコピーするだけです。その後redisを起動すればOKです。redisは起動している間自動的にデータベースファイルをメモリにロードします。起動の速度はデータベースのファイルの大小によって決定します。

## 概要
この節ではアプリケーションのバックアップとリストアについてご紹介しました。ファイルのバックアップからデータベースのバックアップまで、どのように災害に対応するかです。また、rsyncを使った異なるシステムでのファイルの同期についてもご紹介しました。MySQLデータベースとredisデータベースのバックアップとリストアです。この節の紹介を通して開発された本番プロダクトの障害に対するひとつの参考になれば幸いです。
 
## links
   * [目次](<preface.md>)
   * 前へ: [アプリケーションのデプロイ](<12.3.md>)
   * 次へ: [概要](<12.5.md>)
