web-dev-qa-db-ja.com

MySQLスレーブが単一のビンログ+ビンログの位置で17時間以上スタックしました

tl; dr:レプリケーションは特定のバイナリログと位置で停止しており、理由はわかりません


MySQL5.5でMySQLレプリケーションを設定しています。

このレプリケーション設定には、これまで遅れをとった歴史はなく、常に堅実です。

今朝、私はスレーブがマスターの後ろに17時間遅れていることに気づきました。

さらに調査を行うと、SQL_Threadの問題のようです。

スレーブによると、現在のマスターログファイルは(SLAVE STATUS経由で)mysql-bin.001306 @ position 20520499です。これは、マスターからのMASTER STATUS出力と一致しています。

ただし、SLAVE STATUSは、Relay_Master_Log_Fileが現在mysql-bin.001302であり、Exec_Master_Log_Pos36573336であることを示しています。 Relay_Master_Log_FileExec_Master_Log_Posも、今朝私がそれらを監視している間、まったく進歩しました。

マスターのバイナリログを見ると、これはmysql-bin.001302@3657336にあるステートメントです。

# at 36573053
#170221 14:33:48 server id 1  end_log_pos 36573130      Query   thread_id=96205677      exec_time=0     error_code=0
SET TIMESTAMP=1487716428/*!*/;
BEGIN
/*!*/;
# at 36573130
# at 36573213
#170221 14:33:48 server id 1  end_log_pos 36573213      Table_map: `database-name`.`table-name` mapped to number 5873
#170221 14:33:48 server id 1  end_log_pos 36573309      Write_rows: table id 5873 flags: STMT_END_F
### INSERT INTO `database-name`.`table-name`
### SET
###   @1='xxxxxxxx'
###   @2=6920826
###   @3='xxxxxxxx'
###   @4='GET'
###   @5='address'
###   @6=2017-02-21 14:40:24
###   @7=2017-02-21 14:40:24
# at 36573309
#170221 14:33:48 server id 1  end_log_pos 36573336      Xid = 1668637037
COMMIT/*!*/;
# at 36573336

この頃、昨日、データを新しいテーブルに移行するためにいくつかの大きなクエリを実行しました。プロセスはこのように見えました。

mysql> insert into tmp_table ( select <rows> from Origin table ); -- 44 million rows
mysql> insert into dest_table ( select * from tmp_table ); -- 44 million rows

問題の2つのテーブルにはプライマリキーまたは一意キーがありませんでした。これは問題である可能性があります。ただし、上記のbinlogエントリに示されているデータベース+テーブルは、ここでは宛先テーブルですが、示されている挿入レコードは、移行中に生成されたものではありません。

ここまで到達した場合は、インターネットポイントに値します。

この時点で、ログストールの理由を見つけるために他に何を検討するか、他にどこを探すべきかわかりません。どんな洞察もありがたいです。

ありがとう。


参考までに、この投稿の時点でのMASTER STATUSおよびSLAVE STATUSの出力は次のとおりです。

マスターステータス

mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.001306 | 20520499 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

スレーブステータス

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: master-Host
                  Master_User: replication-user
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.001306
          Read_Master_Log_Pos: 20520499
               Relay_Log_File: relay-bin.002601
                Relay_Log_Pos: 36573482
        Relay_Master_Log_File: mysql-bin.001302
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 36573336
              Relay_Log_Space: 3565987462
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 63435
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
1 row in set (0.00 sec)
4
Jim Rubenstein

私は昨日からの大規模なクエリトランザクションでここで正しい軌道に乗っていました。

データを移行した後、元のテーブルでDELETEステートメントを実行して、移行した行を削除しました。

これらのテーブルは追跡データでいっぱいであるため、プライマリキーまたは一意のキーはありません。

スレーブは、行​​ベースのレプリケーションがどのように機能するかにより、マスターで実行されたのと同じDELETEステートメントを実行する代わりに、行ごとにDELETEステートメントを実行します。

DELETE FROM table WHERE colA=foo AND colB=bar AND colC=baz....etc

そして、そのクエリに一致するインデックスがないため、シングルスレッドのレプリケーションSQLスレッドは4,000万以上の削除ステートメントを実行しました(または...試行していました)。各行を識別するために行われました(テーブルのサイズは当時約8000万行でした)。

最後に、私はスレーブスレッド(STOP SLAVE)単一のスレーブトランザクションをスキップします(SET GLOBAL sql_slave_skip_counter = 1;)とスレーブスレッド(START SLAVE)。

これにより、ここで問題のテーブルでマスターとスレーブが同期しなくなりました。ただし、マスターで次のコマンドを実行することにより、行ベースのレプリケーションの性質を利用して同期を取り戻すことができました。

mysql> CREATE TABLE table_tmp; -- with the same schema as 'table' (SHOW CREATE TABLE table;)
mysql> RENAME TABLE table TO table_bak, table_tmp TO table;
mysql> INSERT INTO table ( SELECT * FROM table_bak );
mysql> DROP TABLE table_bak;

DELETEはマスターで実行されたため、ここでのINSERTは、保持したいレコードのみを挿入しました(削除されたレコードはなくなりました)。また、行ベースのレプリケーションでは、同じINSERT INTO ... SELECTステートメントを実行する代わりに、各行が個別に挿入されるため、スレーブテーブルには必要なデータのみが入力されました。次に、後続のDROP TABLEステートメントは、各行を個別にアドレス指定することなく、スレーブ上のテーブルをドロップします。

ここでの注意点は、テーブルのマスターバージョンがまだ3000万〜4000万行だったためです... INSERTとその結果のレプリケーションは、しばらくの間スレーブをロックします(上記の問題を複製)が、それははるかに短いストールです。 mysqlが削除する行についてデータベースをスキャンする必要がないため(最終的には約20分になります)。

これが将来誰かの助けになることを願っています。申し訳ありませんが、それは曲がりくねっています、それが有益で役に立ったことを願っています。

5
Jim Rubenstein