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_Pos
が36573336
であることを示しています。 Relay_Master_Log_File
もExec_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)
私は昨日からの大規模なクエリトランザクションでここで正しい軌道に乗っていました。
データを移行した後、元のテーブルで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分になります)。
これが将来誰かの助けになることを願っています。申し訳ありませんが、それは曲がりくねっています、それが有益で役に立ったことを願っています。