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


173

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

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

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

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


2
mysqldumpコマンドに渡すパラメーター(ある場合)は何ですか?
トビー

--compactを追加するオプションがあります。
トビー

本当に何もありません-- mysqldump [database] -u[user] -p'[password]' > db_backup.sql
パトリック

4
screenあなたの状況に対する単純な代替手段は、を使用することですnohup。これにより、接続が切断されても、サーバー上でコマンドを実行し続けることができます。例えばnohup mysqldump [options] > backup.sql 2> backup.err &。の出力ファイルを提供しない場合、デフォルトでnohup作成nohup.outされます。
-dabest1

1
長い接続がアイドル状態になった後にファイアウォールをシャットダウンする方法についてはatscreen(インストールされている場合は後者ですがat、すべてのUNIXで標準です)またはServerAliveIntervalSSH のオプションをご覧ください。
MattBianco

回答:


134

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

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

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

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

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

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


私のサーバーへのドロップされたssh接続の数を減らすことができたらいいのにと思います。ターミナルを60秒以上使用しないと予想される場合はtop、接続が切断されないように実行します。(そして、私はそれは我々が唯一の仕事で標準WRTルーター&ファイアウォールを使用していて、私の自宅のComcastの接続が低下したことがないようComcastの接続はかなり確信している)
パトリック・

SSH接続に固有の短いメモを追加しました。
デビッドスピレット

2
この答えの深さと洞察。これに対して+3を取得する必要があります。申し訳ありませんが、+ 1のみを提供できます。
-RolandoMySQLDBA

116

mysqldumpを使用してバックアップを行う方法を理解する

私見バックアップを行う方法を知っている場合、バックアップを行うことはより芸術的な形になっています

オプションがあります

オプション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を起動する前に、「読み取りロック付きのフラッシュテーブル、SELECT SLEEP(86400)」を実行します。mysqldumpsが完了した後、このプロセスを強制終了します。これは、データベースにInnoDBとMyISAMの両方が含まれる場合に役立ちます
  3. 日付の付いたフォルダーにmysqldumpsを保存し、古いバックアップフォルダーをローテーションします。
  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は残りのダーティページを持つテーブルをバッファプールからフラッシュするのに時間を費やします。ここに私が提案するものがあります:

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

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 R1Soft(ポイントインタイムスナップショットを取得するMySQL Module Option
  4. MySQL Enterprise Backup(以前のInnoDB Hot Backups [商用])

真のMySQL DBAの精神をお持ちの場合は、mysqldumpを採用し、それを完全にマスターすることができます。すべてのバックアップが、MySQL DBAとしてのスキルを反映している場合があります


2
+1とmysqldumpの適切な使用:真のMySQL DBAの精神をお持ちの場合は、mysqldumpを採用し、それを完全にマスターすることができます。すべてのバックアップが、MySQL DBAとしてのスキルを反映しているように。
アブドゥルマナフ

4
InnoDBでは、テーブルを個別にダンプすると、一貫性のないバックアップが作成されます。
アランコリンズ

5
@AlainCollinsこれが、読み取り専用のレプリケーションスレーブでmysqldumpsを実行する理由です。Seconds_Behind_Masterが0になったら、STOP SLAVEを実行します。これで、前述のスタイルのいずれかでmysqldumpsを実行する一貫した時点になりました。過去5年間、オンライン取引会社に対してこれを行ってきましたが、私や会社の所有者に対する苦情はそれほどありません。この時点で、このクライアントに対して10分ごとにmysqldumpを並行して実行しています。他のクライアントに対してもこれを行い、バックアップ期間を短縮します。
RolandoMySQLDBA

私は32GBのデータベースを持っているので、オプション3はまさに私が念頭に置いていたものです!ありがとう!
レイモンド14年

非常に大きく縮小するには、1TBのデータをバックアップおよび再インポートする必要がありますibdata1。ハードウェアRAIDでバックアップされたSSDの時代では、オプション3が唯一のソリューションです。
-rabudde

18

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

スレーブはマスターのバイナリログを継続的に読み取りバイナリログはマスターデータベースサーバーに書き込まれたクエリを格納します)、スレーブデータベースサーバーに入力を取得します。(これは、マスターデータベースがまったく影響を受けないことを意味します)

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

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


それは私にとってはうまくいくだろうが、少しやり過ぎかもしれないと思う。現在、そのレベルのバックアップは必要ありませんが、アプリケーションの要件が変更された場合、これを念頭に置いてください。
パトリック

4
バックアップのIO負荷をメインDBから削除し、潜在的なロック関連の問題を減らすために、レプリカをバックアップするための+1。重要な注意事項が1つあります。 IO帯域幅に関してマスターと競合する可能性があります-この問題を軽減するには、スレーブのデータファイルがマスターとは異なるドライブ/アレイであることを確認してください。
デビッドスピレット

1
David Spllletのコメントについても同じです。My Web Hosting Employerのスレーブでmysqldumpバックアップを使用して、多数のマスター/スレーブをセットアップおよび保守しています。私からも+1。
RolandoMySQLDBA

16

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

プランB:スレーブを停止することができ、いくつかの手段(コピーファイル、mysqldump、xtrabackupなど)のいずれかによって一貫性のあるバックアップを取ることができます。

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

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


2
4つの計画すべてにフーラー。私は答えごとに+0.25しか与えることができません!!! +1(4 x 0.25)
-RolandoMySQLDBA

15

最初にいくつかの管理ポイント:FTPを実行するために接続していますか?sshの場合は、画面を使用して、comcastのクラッシュ後に再開できるようにしてください。ftpの場合は、送信する前に必ずtar / tarを圧縮してください。

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

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

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


1
--optは、最終的に出力を取得するファイルのサイズを増やしませんか?
トビー

それはいくつか追加されます-私は--quickを追加するつもりでしたが、これは彼の問題に対する答えです....編集中 ありがとう!
デビッドホール

この問題を完全に回避する画面の+1
Gaius

mysqldumpの--optおよび--quickの説明に対する非常に素晴らしく簡潔な回答のために+1。
RolandoMySQLDBA

1
--optはデフォルトでオンです。
ヨルダン

5

以前は、大きなデータベースのダンプ中にもタイムアウトの問題がありました。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

4
これは「一貫性のない」バックアップと見なされます。復元時に、あるテーブルに別のテーブルにマップされていても存在しないデータがある可能性があるためです。
モーガントッカー14

3

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

その方法の1つとして、スキーマでテーブルのグループを作成し、グループごとに個別のDBユーザーを作成し、最後にMySQLパーミッションを使用して、1人を除くすべてのDBユーザーを使用してテーブルを挿入できないようにする方法があります。

これは、実証済みの高速なほぼ並行な手法ですが、500G程度の大規模なダンプからの復元にかか​​る時間は100%確実ではありません。しかし、私の謙虚な意見では、あなたは平行した何かを必要とします。例については、以下のリンクをご覧ください。

[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)からの高速な並列復元」


2
これは、別の質問に対する回答の正確なコピーです。この特定の質問に合わせて、もう少しカスタマイズすることをお勧めします。
ポールホワイト

問題は、特に高速な復元方法ではありません。
アンドリューロリアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.