web-dev-qa-db-ja.com

アクティブな読み取りと書き込みがあるライブシステムでmysqldumpを実行する最も安全な方法は?

これが本当かどうかはわかりませんが、Linuxで次のコマンドを実行した場合に読んだことを覚えています

mysqldump -u username -p database_name > backup_db.sql

データベースの読み取りと書き込みが行われている間、ダンプにはエラーが含まれる場合があります。

コマンドmysqldumpには、これがライブシステムで安全に行われるようにするための特定のオプションがありますか?ユーザーの読み取り/書き込みを数秒間無効にしても問題ありません(データベース<50MB)

85
user784637

すべてのデータはInnoDBです

これは、データの正確なポイントインタイムスナップショットを提供するものです。

mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

--single-transactionは、着信変更を受け取っている間、ダンプがチェックポイントの前のすべてのデータをキャプチャできるようにするチェックポイントを生成します。これらの着信変更はダンプの一部にはなりません。これにより、すべてのテーブルで同じ時点が保証されます。

--routinesすべてのストアドプロシージャとストアド関数をダンプします

--triggersトリガーを含む各テーブルのすべてのトリガーをダンプします

すべてのデータはMyISAMまたはInnoDB/MyISAMの混合

グローバル読み取りロックを課し、mysqldumpを実行して、グローバルロックを解放する必要があります

mysql -uuser -ppass -Ae"FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400)" &
sleep 5
mysql -uuser -ppass -ANe"SHOW PROCESSLIST" | grep "SELECT SLEEP(86400)" > /tmp/proclist.txt
SLEEP_ID=`cat /tmp/proclist.txt | awk '{print $1}'`
echo "KILL ${SLEEP_ID};" > /tmp/kill_sleep.sql
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql
mysql -uuser -ppass -A < /tmp/kill_sleep.sql

試してみる !!!

PDATE 2012-06-22 08:12 EDT

合計データが50MB未満なので、別の方法があります。バックグラウンドでSLEEPコマンドを起動してグローバル読み取りロックを86400秒(24時間)保持して、プロセスIDを取得して外部で強制終了する代わりに、OSではなくmysqlで5秒のタイムアウトを設定してみましょう。

SLEEP_TIMEOUT=5
SQLSTMT="FLUSH TABLES WITH READ LOCK; SELECT SLEEP(${SLEEP_TIMEOUT})"
mysql -uuser -ppass -Ae"${SQLSTMT}" &
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

これは、非常に小さなデータベースの場合、よりクリーンでシンプルなアプローチです。

90
RolandoMySQLDBA
  • InnoDBテーブルの場合、別の回答で述べたように、--single-transactionオプションを使用する必要があります。
  • MyISAMには--lock-tablesがあります。

公式ドキュメントはこちら を参照してください

4
pesco

Mysqlの公式ドキュメントでは、「シナリオ2:読み取り専用スレーブによるバックアップ」で説明されているマスター「M1」データベースとスレーブ「S1」データベースが必要であることを示唆しています マスターまたは読み取り専用にすることによるスレーブ

スレーブデータベースを読み取り専用に設定して実行する必要があります。

ここに私がそれをした方法があります。 FLUSH TABLES WITH READ LOCKを使用しているため、すべてのケースで機能するはずです。

#!/bin/bash

DB=example
DUMP_FILE=export.sql

# Lock the database and sleep in background task
mysql -uroot -proot $DB -e "FLUSH TABLES WITH READ LOCK; DO SLEEP(3600);" &
sleep 3

# Export the database while it is locked
mysqldump -uroot -proot --opt $DB > $DUMP_FILE

# When finished, kill the previous background task to unlock
kill $! 2>/dev/null
wait $! 2>/dev/null

echo "Finished export, and unlocked !"

Shell sleepコマンドは、mysqldumpが開始する前に、mysqlのロックコマンドを実行しているバックグラウンドタスクが実行されていることを確認するためのものです。あなたはそれを1秒に減らすことができ、それでも問題ないはずです。この値を30秒に増やし、その30秒間に別のクライアントから任意のテーブルに値を挿入してみてください。ロックされていることがわかります。

mysqldumpオプション--single-transactionおよび--lock-tablesを使用する代わりに、この手動のバックグラウンドロックを使用することには2つの利点があります。

  1. MyISAM/InnoDBテーブルが混在している場合、これによりすべてがロックされます。
  2. 同じロック期間中にmysqldumpに加えて他のコマンドを実行できます。たとえば、マスターノードでレプリケーションを設定する場合に便利です。データベースをロック解除する前に、作成したダンプの正確な状態でSHOW MASTER STATUS;を使用してバイナリログの位置を取得する必要があるためです。レプリケーションスレーブを作成します。
1
Nicomak

MyISAMまたは混合テーブルに対して、テーブルのロックによるダウンタイムなしでこれを実行する場合は、スレーブデータベースをセットアップして、そこからスナップショットを取得できます。残念ながら、スレーブデータベースを設定すると、ライブデータベースのエクスポートに多少のダウンタイムが発生しますが、実行中の場合は、テーブルをロックし、他の人が説明した方法を使用してエクスポートできるはずです。これが発生すると、マスターよりも遅れますが、マスターによるテーブルの更新が停止されることはなく、バックアップが完了するとすぐに追いつきます。

1
Talik Eichinger

非常に大きなMYISAMテーブルがあり、ロックなしでテーブルをダンプし、サーバーの高負荷を回避する必要がある場合は、次のスクリプトを使用できます。

#!/bin/sh

my_user="user"
my_password="password"
my_db="vpn"
my_table="traffic"
my_step=100000

read -p "Dumping table ${my_db}.${my_table} to ${my_table}.sql?" yn
case $yn in
    [Yy]* ) break;;
    * ) echo "User cancel."; exit;;
esac

my_count=$(mysql $my_db -u $my_user -p$my_password -se "SELECT count(*) FROM $my_table")
my_count=$(($my_count + 0))

if [ ! $my_count ]
then
    echo "No records found"
    exit
fi

echo "Records in table ${my_db}.${my_table}: ${my_count}"

echo "" > $my_table.sql

max_progress=60

for (( limit=0; limit<=$my_count; limit+=$my_step )); do
    progress=$((max_progress * ( limit + my_step) / my_count))

    echo -ne "Dumping ["
    for ((i=0; i<$progress; i ++)); do
        echo -ne "#"
    done
    for ((; i<$max_progress; i ++)); do
        echo -ne "."
    done

    mysqldump -u $my_user -p$my_password --complete-insert --no-create-info --opt --where="1 limit $limit , $my_step" $my_db $my_table >> $my_table.sql
    echo "" >> $my_table.sql

    echo -ne "] $((100 * ( limit + my_step ) / my_count)) %"
    echo -ne "\r"

    sleep 1

done

echo -ne "\n"
0
vadim_hr