mysqldump --single-transaction、それでも更新クエリはバックアップを待機しています


10

mysqldump --single-transactionを使用する場合、ドキュメントによると、読み取りロックでテーブルをフラッシュして一貫した状態を取得し、トランザクションを開始する必要があります。ライターは待機していません。

しかし、私は昨夜、次の状況に遭遇しました:

show fullプロセスリストからの抜粋:

何百もの...

   Command: Query
   Time: 291
   State: Waiting for table flush
   Info: insert into db_external_notification.....

次にこれ:

Command: Query
Time: 1204
State: Sending data
Info: SELECT /*!40001 SQL_NO_CACHE */ * FROM `db_external_notification`

残りのスレッドはスリープ状態です

これらの挿入が何を待っているのか誰かが何か知っていますか?クエリを待機させるFLUSHテーブル、DDL、またはマニュアルに記載されているものはありません。

mysqldumpコマンド全体

mysqldump --quick --add-drop-table --single-transaction --master-data=2 -uxx -pxx dbname

私は--quickはここでは冗長であると思います、おそらく以前の時間からの残り物です、このスクリプトは非常に古いですが、何も害しないはず


show full processlistとshow innodb status(anonymized)の完全な出力は次のとおりです。pastebin.com
Aleksandar Ivanisevic

完全なコマンドラインはmysqldump何ですか?特に、使用しています--flush-logs--master-data... オプション間に潜在的な相互作用があります。
マイケル-sqlbot 14

完全なmysqldumpコマンドを追加しました。探してくれてありがとう
Aleksandar Ivanisevic

回答:


6

mysqldump--single-transactionオプションは行いません。これにより、mysqldumpは、ダンプされるすべてのテーブルに対して繰り返し可能な読み取りトランザクションをセットアップします。FLUSH TABLES WITH READ LOCK;

あなたの質問から、db_external_notificationテーブルのmysqldumpのSELECT が同じテーブルへの何百ものINSERTコマンドを保持していると述べました。なんでこんなことが起こっているの ?

最も可能性が高いのは、gen_clust_index(クラスター化インデックスとして知られている)をロックすることです。このパラダイムにより、テーブルのデータとインデックスページが共存します。これらのインデックスページは、PRIMARY KEYまたは自動生成されたRowIDインデックスに基づいています(PRIMARY KEYがない場合)。

実行SHOW ENGINE INNODB STATUS\Gしてこれを見つけ、排他ロックを持つgen_clust_indexから任意のページを探すことができるはずです。クラスタ化インデックスのあるテーブルにINSERTを実行するには、PRIMARY KEYのBTREEを処理するための排他ロックと、auto_incrementのシリアル化が必要です。

以前にこの現象について話しました

UPDATE 2014-07-21 15:03 EDT

パストビンの614行目から617行目をご覧ください

mysql tables in use 1, locked 0
MySQL thread id 6155315, OS thread handle 0x85f11b70, query id 367774810 localhost root Sending data
SELECT /*!40001 SQL_NO_CACHE */ * FROM `db_external_notification`
Trx read view will not see trx with id >= 1252538405, sees < 1252538391

617行目は言うことに注意してください

Trx read view will not see trx with id >= 1252538405, sees < 1252538391

これは何を教えてくれますか?auto_incrementがオンのいくつかの主キーがありidます。

idテーブルの最大値は、mysqldumpが起動されたときdb_external_notificationよりも小さかった12525383911252538391から減算すると1252538405、これは14以上のINSERTコマンドが試行されたことを意味します。内部的には、このテーブルのauto_incrementを少なくとも14回移動する必要があります。ただし、このidギャップを管理するため、ログバッファーにコミットしたり、プッシュしたりすることはできません。

次に、PasteBinのプロセスリストを確認します。誤算しない限り、38のDB接続がINSERTを実行しているのを見ました(19はmysqldumpプロセス(プロセスIDの前6155315)、19は後)。auto_incrementギャップを管理しているため、これらの接続の14以上がフリーズしていると思います。


私は長い間探していましたが、排他ロックが見つかりませんでした。私はでフルショーのInnoDBのステータスを貼り付けているpastebin.com/D7WS3QAE何が私に何の排他的ロックのようにそこに見えない、
アレクイワニセビッチ

説明をありがとう。バックアップが書き​​込まれないことは明らかなので、なぜ読み取り専用トランザクションを使用しないのかと思いますが、エンタープライズバックアップ用にその機能を保持していると思います。
Aleksandar Ivanisevic 14

10

--single-transactionオプションはmysqldump ありません行うFLUSH TABLES WITH READ LOCK前にバックアップジョブを開始するだけで、一定の条件の下で。これらの条件の1つは、--master-dataオプションも指定した場合です。

ソースコードのmysql-5.6.19/client/mysqldump.c5797行目から:

if ((opt_lock_all_tables || opt_master_data ||
     (opt_single_transaction && flush_logs)) &&
    do_flush_tables_read_lock(mysql))
  goto err;

反復可能読み取りトランザクションを開始する前に正確なバイナリログ座標を確実にロックするには、この--master-dataオプションを使用してこのロックを取得し、バイナリログ座標が取得されると解放します。

実際、最初のフラッシュに時間がかかる場合に両方を実行すると、読み取りロックをより速く取得できるためmysqldump、のFLUSH TABLES後にaが続きFLUSH TABLES WITH READ LOCKます。

...しかしながら...

binlogの座標を取得するとすぐにmysqldumpUNLOCK TABLESステートメントを発行するので、開始したフラッシュの結果として何もブロックされないはずです。またWaiting for table flushmysqldump保持しているトランザクションの結果としてスレッドが発生することはありません。

Waiting for table flush状態のスレッドが表示された場合、それFLUSH TABLES [WITH READ LOCK]ステートメントが発行され、クエリの開始時にまだ実行中であったこと意味します。クエリは、実行する前にテーブルのフラッシュを待機する必要があります。あなたが投稿したプロセスリストの場合、mysqldumpはこの同じテーブルから読み取りを行っており、クエリはしばらく実行されていますが、ブロッククエリはその間ずっとブロックされていません。

これはすべて、何か他のことが起こったことを示唆しています。

バグ#44884FLUSH TABLES内部的に機能する方法について説明されている長期にわたる問題があります。 問題が解決しない場合でも、私は驚くことではありません。この問題が解決されると、非常に複雑な問題であるため、この問題が「修正」されても驚くことはありません。それを修正することは、何かを壊したり、新しく異なった、それでもなお望ましくない振る舞いを作成したりする重大なリスクを伴います。

これはあなたが見ているものの説明になると思われます。

具体的には:

  • テーブルに対して長時間実行されているクエリを実行していて、を発行FLUSH TABLESした場合、FLUSH TABLESは長時間実行されているクエリが完了するまでブロックされます。

  • さらに、FLUSH TABLESが発行された後に始まるクエリは、FLUSH TABLESが完了するまでブロックされます。

  • さらに、FLUSH TABLESクエリを強制終了しても、ブロックされたクエリは、元の長時間実行クエリ(クエリをブロックしていたクエリ)で引き続きブロックFLUSH TABLESFLUSH TABLESます。強制終了されたクエリが完了していなくても、そのテーブル(またはさらに、実行時間の長いクエリに関与している)はまだフラッシュされており、その実行中のフラッシュは、実行時間の長いクエリが完了するとすぐに発生しますが、その前ではありません。

ここで考えられる結論は、別のプロセス-おそらく別のmysqldump、または不適切なクエリ、または不適切に記述された監視プロセスがテーブルをフラッシュしようとしたことです。

その後、そのクエリは不明なメカニズムによって強制mysqldump終了またはタイムアウトされましたが、問題の後処理は、問題のテーブルからの読み取りが完了するまで続きました。

FLUSH TABLES長時間実行クエリの処理中に試行することで、この状態を再現できます。次に、ブロックする別のクエリを開始します。次に、FLUSH TABLESクエリを強制終了します。これにより、最新のクエリのブロックが解除されません。次に、最初のクエリを強制終了するか、終了させれば、最後のクエリが正常に実行されます。


後から考えると、これは無関係です。

Trx read view will not see trx with id >= 1252538405, sees < 1252538391

はをmysqldump --single-transaction発行するためSTART TRANSACTION WITH CONSISTENT SNAPSHOT、これは正常です。これにより、ダンプの進行中に変更されたデータをダンプできなくなります。それがなければ、最初に得られたbinlog座標は意味をなさない--single-transactionでしょう。このWaiting for table flushトランザクションは明らかにロックを保持していないため、これは決して問題とは関係ありません。


この答えは実際に正しいです。
Boban P.17年

2

機能リクエストを送信しました:https : //support.oracle.com/epmos/faces/BugDisplay?id=27103902

--single-transaction --master-dataと--single-transaction --slave-dataの組み合わせと同じ方法を使用する5.6.37に対するパッチも作成しました。これは、保証なしで現状のまま提供されます。自己責任。

--- mysql-5.6.37/client/mysqldump.c.bak 2017-11-14 12:24:41.846647514 -0600
+++ mysql-5.6.37/client/mysqldump.c 2017-11-14 14:17:51.187050091 -0600
@@ -4900,10 +4900,10 @@
   return 0;
 }

+/*
 static int do_stop_slave_sql(MYSQL *mysql_con)
 {
   MYSQL_RES *slave;
-  /* We need to check if the slave sql is running in the first place */
   if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
     return(1);
   else
@@ -4911,23 +4911,21 @@
     MYSQL_ROW row= mysql_fetch_row(slave);
     if (row && row[11])
     {
-      /* if SLAVE SQL is not running, we don't stop it */
       if (!strcmp(row[11],"No"))
       {
         mysql_free_result(slave);
-        /* Silently assume that they don't have the slave running */
         return(0);
       }
     }
   }
   mysql_free_result(slave);

-  /* now, stop slave if running */
   if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
     return(1);

   return(0);
 }
+*/

 static int add_stop_slave(void)
 {
@@ -5841,10 +5839,12 @@
   if (!path)
     write_header(md_result_file, *argv);

+  /*
   if (opt_slave_data && do_stop_slave_sql(mysql))
     goto err;
+  */

-  if ((opt_lock_all_tables || opt_master_data ||
+  if ((opt_lock_all_tables || opt_master_data || opt_slave_data ||
        (opt_single_transaction && flush_logs)) &&
       do_flush_tables_read_lock(mysql))
     goto err;
@@ -5853,7 +5853,7 @@
     Flush logs before starting transaction since
     this causes implicit commit starting mysql-5.5.
   */
-  if (opt_lock_all_tables || opt_master_data ||
+  if (opt_lock_all_tables || opt_master_data || opt_slave_data ||
       (opt_single_transaction && flush_logs) ||
       opt_delete_master_logs)
   {
 static int add_stop_slave(void)
 {
@@ -5841,10 +5839,12 @@
   if (!path)
     write_header(md_result_file, *argv);

+  /*
   if (opt_slave_data && do_stop_slave_sql(mysql))
     goto err;
+  */

-  if ((opt_lock_all_tables || opt_master_data ||
+  if ((opt_lock_all_tables || opt_master_data || opt_slave_data ||
        (opt_single_transaction && flush_logs)) &&
       do_flush_tables_read_lock(mysql))
     goto err;
@@ -5853,7 +5853,7 @@
     Flush logs before starting transaction since
     this causes implicit commit starting mysql-5.5.
   */
-  if (opt_lock_all_tables || opt_master_data ||
+  if (opt_lock_all_tables || opt_master_data || opt_slave_data ||
       (opt_single_transaction && flush_logs) ||
       opt_delete_master_logs)
   {

FK関係を持つ多くのInnoDBテーブルを使用して、非常にビジーなマスターへのスレーブを使用して、次のプロセスでテストしました。

  1. スレーブAを停止します。
  2. 15分ほど待ちます。
  3. オプション--single-transactionおよび--dump-slave = 2を使用して、スレーブBからDB 1をダンプします
  4. 手順3のダンプの座標までスレーブAを起動します。
  5. スレーブAからDB 1と2をドロップします。
  6. スレーブAに空のDB 1および2を作成します。
  7. 手順3のダンプをスレーブAにロードします。
  8. 同じオプションでスレーブBからDB 2をダンプします。DB 2はDB 1とのFK関係を持っています。
  9. DB 2にreplicate_ignore_dbを追加し、スレーブAにskip_slave_startを追加します。
  10. スレーブAを再起動します。
  11. スレーブAのステップ8のダンプから座標までスレーブを開始します。
  12. 手順8のダンプをスレーブAにロードします。
  13. スレーブAからreplicate_ignore_dbおよびskip_slave_startオプションを削除します。
  14. スレーブAを再起動します。
  15. 1週間ほど待ちます。
  16. pt-checksumを使用して、データの整合性を確認します。

Oracleのパッチ提出プロセスはかなり集中的であるため、なぜ私はこの方法を採用しましたか。PerconaやMariaDBを使って統合することもできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.