使用中のマスター/スレーブ複製システムで単一のmysqlデータベースを回復する


10

忙しいレプリケートされたシステムで単一のデータベースを特定の時点にリカバリするための戦略またはツールを探しています。

マスタースレーブ複製構成の2つのMySQL 5.0.77サーバーで実行されている12のデータベースがあります。読み取り専用スレーブのフルダンプが毎日取得され、これらのバックアップがオフサイトにある増分SQLダンプが利用可能であり、レプリケーションステータスが監視されます。

編集:テーブルはInnoDBとmyISAMの混合であるため、エンジン固有のソリューションは利用できません。

したがって、マスターサーバーに完全な障害が発生した場合、レプリケーションを中断してスレーブサーバーを昇格させることができます。また、新しいサーバーを再構築してオフサイドのフルバックアップから構成し、スレーブから1時間ごとに取得した差分を適用することもできます。

ただし、部分的な障害、または単一のデータベースの障害に対処する方法を心配しています。かなりありそうな2つのシナリオを考えることができます。

  1. データベース7(たとえば)が破損し、壊れていることに誰かが気付くまで、またはログファイルからアラートが出されるまで、いくつかの要求を処理し続けます...
  2. 「データベースの削除」、「テーブルの削除」、「更新場所...」タイプのクエリなどのクエリは、単一のデータベース、またはその一部のサブセットを作成します。

現時点では、FULL- $ DATE-all-databases.sql.gzファイルとしての一連のフルダンプと、DIFF- $ DATE-all-databases.sql.gzとしてフルダンプに適用できる差分があります。

データベース7を特定の時点に復元するには、FULLおよびDIFFファイルを介したgrepと、そのSQLの手動による適用が必要です。

マスターデータベースへの以前のDIFFダンプの1つに回復できるようにするには、どうすればよいですか?

個々のデータベースファイルにバックアップする必要がありますか?

mysqldump --databases "database1" | gzip > database1.sql.gz
mysqldump --databases "database2" | gzip > database2.sql.gz
mysqldump --databases "database3" | gzip > database3.sql.gz

のではなく..

mysqldump --master-data --lock--all-databases --all-databases | gzip > all-databases.sql.gz

個別のmysqldumpファイルを使用する場合、マスターデータのバイナリログはどうなりますか?マスターサーバーのリカバリダンプに--master-dataを設定する必要がありますか?

回答:


7

すべてのデータベースでInnoDBのみを使用している場合は、良いお知らせがあります。

すべてのデータベースをスレーブから並列にダンプする必要があります。

実際、すべてのデータベースを同じ時点に強制できます。

スレーブについて最初に覚えておくべきことは、スレーブが他のスレーブのマスターでない場合は、バイナリログを有効にする必要がないことです。

--master-data各ダンプは、各ダンプファイルの22行目に異なる位置に書き込まれるため、並列ダンプにはオプションを使用できません。マスターの最後のログファイルを記録し、を使用して実行されたスレーブを配置することをお勧めしSHOW SLAVE STATUS\Gます。このように、すべてのデータベースは同じ時点の位置を持っています。

すべてのデータベースを収集し、すべてのデータベースの並列ダンプをスクリプト化できます。

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
done 
wait 

mysql -h... -u... -p... -e"START SLAVE;"

データベースが多すぎる場合は、次のように一度に10個または20個ずつダンプします。

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

単一のテーブルをリカバリする必要がある場合は、サイズ順に一度に20個のテーブルを並列ダンプできます。

これを試して:

TBLIST=/tmp/ListOfTablesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql','performance_schema') ORDER BY data_length" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DBTB in `cat ${TBLIST}` 
do
    DB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $1}'`
    TB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $2}'`
    DUMPFILE=$DB-{DB}-TBL-${TB}.sql.gz
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} ${TB} | gzip >  ${DUMPFILE} & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

データベースまたは個々のテーブルをダンプするスクリプトが作成されたので、そのデータを自由にロードできます。マスターのバイナリログからSQLを実行する必要がある場合は、それを使用mysqlbinlogして日時の位置を指定し、SQLを他のテキストファイルに出力できます。バイナリログのタイムスタンプから必要なデータ量を見つけるために、十分な注意を払う必要があります。OS内のすべてのバイナリログのタイムスタンプは、最後に書き込まれた時刻を表すことに注意してください。


素晴らしい答えはありがとう。xfsに読み取り専用のスレーブがあると、たくさんのオプションが得られると思います。あなたのスクリプトは本当に役に立ちました。
トムH

大量のテーブルをスレーブのバックアップからマスターにリカバリする必要があるシナリオでは。マスターでテーブルを再構築し、20GBのデータであってもすべての変更をスレーブに複製する必要がありますか?プロセスは1)キーを無効にする、2)マスターとスレーブにテーブルをドロップする3)テーブルをマスターに復元する4)キーを有効にする---マスターにすべての20GBをスレーブに複製させる
トムH

これらのデータベースがinnodbでない場合でも、並行してダンプできますか?
トムH

はい、1)ダウンタイムのスケジュール、2)実行service mysql restart --skip-networking、3)並列ダンプの実行、4)実行の場合service mysql restart。次に、必要なテーブルをリロードします。
RolandoMySQLDBA 2012年

おそらく、再起動の目的がデータベースへのネットワーク接続の書き込みを防ぐことだった場合、iptables i.e. iptables -I INPUT -p tcp --dport 3306 -j DROPeth0とlo を使用して同じ効果を得ることができます
Tom H
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.