web-dev-qa-db-ja.com

大規模なデータベースのmysqldumpを最適化するにはどうすればよいですか?

57テーブルで〜2GBのInnoDBデータベースを使用するsymfonyアプリケーションがあります。データベースのサイズの大部分は、単一のテーブル(約1.2GB)にあります。現在、mysqldumpを使用してデータベースを毎晩バックアップしています。

コムキャスト接続のため、ダンプを手動で実行している場合、ダンプが完了する前にサーバーへの接続がタイムアウトして、ダンプを再実行する必要があることがよくあります。 [私は現在、毎晩ダンプを行うcronを実行しています。これは、手動で実行するダンプのためだけです。]

接続タイムアウトの問題のダンプを高速化する方法はありますが、サーバーがこのプロセスで占有されている時間を制限する方法もありますか?

ところで、私は現在、この問題を解決するためにデータベース全体のサイズを減らすことに取り組んでいます。

179
Patrick

このようなダンプの主なボトルネックは、ドライブI/Oです。大量のデータを読み取り、再度書き込みます。いくつかの方法でこれをスピードアップできます:

  • 出力が、データベースファイルが保存されているドライブとは別のドライブに送られていることを確認します。これにより、ドライブヘッドが読み取られている場所の間を常にフリックしないため、回転するディスクに大きな違いが生じます。書き込み先の場所。
  • Mysqldumpの出力は非常に圧縮可能であるため、上記のように出力を入力から分離できない場合は、gzipなどを介して出力をパイプ処理します。これは、実行される書き込みの量を減らします(そのため、全体のIO負荷とヘッドの移動量を減らします)が、CPU時間(ただし、これらの時間はとにかく)。
  • また、(または圧縮の代わりに)ドライブに書き込まれたブロックをさらにグループ化するために大きな書き込みバッファーをサポートするパイプユーティリティ( pv など)を介して出力を渡し、再びヘッドの影響を減らします-移動待ち時間---quickオプションは、RAM大きなテーブルのバックアップによる影響)を低減します。
  • IO負荷が低い場合にのみバックアッププロセスを実行します。

ただし、間違った問題を修正している可能性があります。代わりに、接続のドロップに対処する方が簡単な場合があります(ただし、バックアップによるI/O負荷を減らすと、他のユーザーへの影響を減らすのに役立つため、とにかく試す価値があります)。 screen (または tmux のような同様のツール)を使用して手動バックアップを実行できますか?こうすることで、サーバーへの接続が切断された場合でも、プロセスが中断されることなく、screenセッションに再接続して再接続できます。

接続を介してデータを直接送信する場合(つまり、ローカルマシンでリモートデータベースに対してmysqldumpを実行しているため、ダンプがローカルに表示される場合)、まずサーバーでダンプを実行し、必要に応じて圧縮してから転送することをお勧めします部分的な転送をサポートするツール(rsyncなど)を使用したネットワーク経由のデータ。これにより、接続の切断によって中断された場合に、(再起動する代わりに)転送を再開できます。

「この問題を解決するためにデータベース全体のサイズを削減する」の一環として、データの大きなチャンクは変更されないと思います。 1.2Gbの大きなチャンクをそのメインテーブルから別のチャンクに移動して、mysqldump呼び出しによってコピーされたチャンクから削除することができる場合があります。変更されない場合は、毎回このデータをバックアップする必要はありません。この方法でテーブルとデータベース間でデータを分割することは、通常、データパーティション化と呼ばれ、データとI/O負荷を複数のドライブに分散させることもできます。ハイエンドデータベースには自動パーティション分割のサポートが組み込まれていますが、mysqlではおそらく手動でそれを実行し、それを考慮してデータアクセス層を変更する必要があります。

このサイトのトピックから外れています(したがって、詳細が必要かどうかを確認するには、おそらくServerFaultまたはSuperUserにニップする必要があります):非アクティブのために接続が失われているように見える場合は、SSHサーバーとSSHクライアントのオプションを確認して、キープアライブパケットが有効になっていて、十分な頻度で送信されていることを確認してください。接続がアクティブでもドロップが表示される場合は、OpenVPNなどを使用して接続をラップすることもできます。接続全体が数秒間ダウンしている場合、SSHクライアントとサーバーは気づかない。

139
David Spillett

mysqldumpでバックアップを実行するための洞察

IMHOバックアップを行う方法がわかっている場合、バックアップを行うことはアートの形になっています

オプションがあります

オプション1:mysqldumpでmysqlインスタンス全体を

これは最も簡単な方法です。

mysqldump -h... -u... -p... --hex-blob --routines --triggers --all-databases | gzip > MySQLData.sql.gz

1つのファイルに書き込まれたすべて:テーブル構造、インデックス、トリガー、ストアドプロシージャ、ユーザー、暗号化されたパスワード。他のmysqldumpオプションは、さまざまなスタイルのINSERTコマンド、バイナリログからのログファイルと位置の座標、データベース作成オプション、部分データ(--whereオプション)などもエクスポートできます。

オプション2:mysqldumpの個別のデータベースを個別のデータファイルに

データベースのリストを作成することから始めます(これを行う2つの手法)

テクニック1

mysql -h... -u... -p... -A --skip-column-names -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql')" > ListOfDatabases.txt

テクニック2

mysql -h... -u... -p... -A --skip-column-names -e"SELECT DISTINCT table_schema FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfDatabases.txt

手法1が最速の方法です。手法2が最も確実で安全です。手法2の方が優れているのは、ユーザーが/ var/lib/mysql(datadir)に汎用目的のフォルダーを作成し、データベースに関連しない場合があるためです。 information_schemaは、フォルダをデータベースとしてinformation_schema.schemataテーブルに登録します。手法2は、mysqlデータを含まないフォルダーをバイパスします。

データベースのリストをコンパイルしたら、必要に応じて、リストをループしてmysqldumpを実行し、並行して処理することができます。

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

一度に起動するにはデータベースが多すぎる場合は、一度に10個ずつ並列にダンプします。

COMMIT_COUNT=0
COMMIT_LIMIT=10
for DB in `cat ListOfDatabases.txt`
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
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

オプション3:mysqldumpの個別のテーブルを個別のデータファイルに

まず、テーブルのリストを作成します

mysql -h... -u... -p... -A --skip-column-names -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfTables.txt

次に、すべてのテーブルを10のグループにダンプします。

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

オプション4:自分の想像力を使う

前述のオプションのバリエーションとクリーンなスナップショットのためのテクニックを試してください

  1. 各テーブルのサイズを昇順または降順に並べ替えます。
  2. 別のプロセスを使用して、mysqldumpsを起動する前に「FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400)」を実行します。 mysqldumpの完了後にこのプロセスを終了します。これは、データベースにInnoDBとMyISAMの両方が含まれている場合に役立ちます
  3. Mysqldumpを日付の付いたフォルダに保存し、古いバックアップフォルダをローテーションします。
  4. インスタンスmysqldumps全体をスタンドアロンサーバーにロードします。

[〜#〜]警告[〜#〜]

オプション1だけがすべてをもたらします。欠点は、この方法で作成されたmysqldumpは、mysqldumpが生成されたのと同じmajotリリースバージョンのmysqlにのみ再ロードできることです。つまり、MySQL 5.0データベースのmysqldumpを5.1または5.5にロードすることはできません。理由 ? mysqlスキーマは、メジャーリリース間で完全に異なります。

オプション2と3には、ユーザー名とパスワードの保存は含まれません。

これは、読みやすく移植性の高いユーザー向けのSQL Grantsをダンプする一般的な方法です

mysql -h... -u... -p... --skip-column-names -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',Host,''';') FROM mysql.user WHERE user<>''" | mysql -h... -u... -p... --skip-column-names -A | sed 's/$/;/g' > MySQLGrants.sql

オプション3はストアドプロシージャを保存しないため、以下を実行できます。

mysqldump -h... -u... -p... --no-data --no-create-info --routines > MySQLStoredProcedures.sql &

注意すべきもう1つの点は、InnoDBに関するものです。 InnoDBバッファープールが大きい場合は、バックアップを実行する前にできる限りフラッシュするのが理にかなっています。そうでない場合、MySQLは、ダーティページが残っているテーブルをバッファプールからフラッシュする時間を費やします。これが私が提案するものです:

バックアップを実行する約1時間前に、このSQLコマンドを実行します

SET GLOBAL innodb_max_dirty_pages_pct = 0;

MySQL 5.5では、デフォルトのinnodb_max_dirty_pages_pctは75です。MySQL5.1以降では、デフォルトのinnodb_max_dirty_pages_pctは90です。innodb_max_dirty_pages_pctを0に設定することにより、ダーティページのディスクへのフラッシュを早めます。これにより、InnoDBテーブルに対してmysqldumpを実行する前に、InnoDBデータの不完全な2フェーズコミットをクリーンアップする影響が防止または少なくとも軽減されます。

mysqldumpの最後の単語

ほとんどの人はmysqldumpを避けて他のツールを支持しており、それらのツールは確かに優れています。

このようなツールには、

  1. MAATKIT(並列 ダンプ / 復元 スクリプト、Perconaから[非推奨ですがすばらしい])
  2. XtraBackup (PerconaからのTopNotchスナップショットバックアップ)
  3. CDP R1SoftMySQLモジュールオプション これは、特定の時点のスナップショットを取得します)
  4. MySQL Enterprise Backup (以前のInnoDBホットバックアップ[商用])

真のMySQL DBAの精神を持っている場合は、mysqldumpを採用して、それを完全に習得できます。すべてのバックアップが、MySQL DBAとしてのスキルを反映している可能性があります。

122
RolandoMySQLDBA

MySQLレプリケーションマスターからスレーブへの移行をご覧ください。マスターのデータベースを同じデータベースを持つ別のデータベースサーバーに複製できます。これには、マスターIDとスレーブIDが含まれます。スレーブは、マスターデータベースサーバーまたはそのデータベースの正確なコピーを作成します。マスターとスレーブの間には、1対1、多対多の関係がある場合があります。

スレーブは継続的にマスターでバイナリログを読み取り(バイナリログはマスターデータベースサーバーで書き込まれたクエリを保存します)、スレーブデータベースサーバーへの入力を取得します。 (つまり、マスターデータベースはまったく影響を受けません)

良いニュースは、ダウンタイムや遅いクエリ応答に気付かないため、MySQLサーバーにあまり影響を与えないことです。 10Gbのデータベースに使用しており、ダウンタイムなしで魅力的に機能します。

同じマシンでのMySQLレプリケーション

20
poelinca

プランA:PerconaのXtrabackupも参照してください。これにより、大幅なロックなしでInnoDBのオンラインバックアップが可能になります。

プランB:スレーブを停止でき、いくつかの方法(ファイルのコピー、mysqldump、xtrabackupなど)のいずれかで一貫したバックアップをとることができます

プランC:LVMスナップショット。不可解な設定の後、データベースのサイズに関係なく、バックアップのダウンタイムは1分未満です。 mysqldを停止し、スナップショットを作成し、mysqldを再起動してから、スナップショットをコピーします。最後のステップには時間がかかることがありますが、MySQLはダウンしていません。

プランD:スレーブのスナップショット-ダウンタイムなし。

19
Rick James

最初にいくつかの管理ポイント:ftpを実行するために接続していますか、それともsshを実行していて、それは死にかけていますか? sshの場合は、必ずscreenを使用して、comcastのクラッシュ後に再開できるようにしてください。 ftpの場合は、送信前にそれを圧縮していることを確認してください。

--optパラメータまたは--quickも試してください

--optこのオプションは、ダンプとリロードの操作をより効率的にするための一連の追加オプションをオンにします。具体的には、-add-drop-table、-add-locks、-all、-quick、-extended-insert、-lock-tables、および--disable-keysオプションを一緒に使用することと同等です。このオプションを使用すると、出力の移植性が低下し、他のデータベースシステムで理解されにくくなります。

--quickこのオプションは、サーバーから各行を読み取るときにダンプ出力を書き込むようにmysqldumpに指示します。これは、大きなテーブルに役立つ場合があります。デフォルトでは、mysqldumpは出力を書き込む前にテーブルからメモリにすべての行を読み取ります。大きなテーブルの場合、これには大量のメモリが必要になるため、ダンプが失敗する可能性があります。

15
David Hall

大きなデータベースのダンプ中のタイムアウトにも問題がありました。最終的に解決したのは、db内のすべてのテーブルに個別のコマンドを送信し、次のように1つのファイルにすべてを追加することです。

TABLES=`mysql -u $USER -p$PWD -Bse 'show tables' $DB`
for TABLE in $TABLES
do
    mysqldump -u $USER -p$PWD $DB $TABLE >> dump.sql
done
5
Patrick Heck

別のバックアップソリューションではなく、mysqldumpで作成されたダンプファイルからより速く復元する方法についての問題だと思います。

これを行う方法の1つは、スキーマにテーブルのグループを作成し、グループごとに個別のDBユーザーを作成し、最後にMySQL権限を使用して、1人を除くすべてのDBユーザーを使用してテーブルを挿入できないようにすることです。

これは、実証済みの高速でほぼ並列の手法ですが、100%確実ではありません。500Gなどの大規模なダンプから復元するのにどのくらいの時間がかかりますか。しかし、私の控えめな意見では、あなたは何か平行するものが必要です。例については、以下のリンクをチェックしてください。

[MySQLのSQLダンプ(mysqldump)からの高速並列復元] [1]

http://geeksww.com/tutorials/database_management_systems/mysql/tips_and_tricks/fast_parallel_restore_from_sql_dumps_mysqldump_for_mysql.php

「MySQLのSQLダンプ(mysqldump)からの高速な並列復元」

3
syed