最近、Ubuntu Server 16.04にMySQL 5.7の2つの同一のデフォルトインストールをインストールし、バイナリログレプリケーションを実行するように設定しました。これまではこれで問題なく動作していましたが、突然レプリケーションが停止し、スレーブクエリスレッドは何もせずに100%CPUで実行されます。
いくつか検索したところ、スレーブステータスがマスターよりもかなり遅れていることがわかりました。 Relay_Master_Log_Fileおよび位置Exec_Master_Log_Posによって示されるbinlogファイルでmysqlbinlogを使用すると、この位置で実行されるステートメントは次のとおりであることがわかりました。
SET @@SESSION.GTID_NEXT= 'ANONYMOUS';
どういうわけか、このステートメントを実行しようとするとスレーブがハングし、CPU負荷が100%に送られます(これが最初に状況を発見した方法です)。
スレーブがSET GLOBAL sql_slave_skip_counter=1
を使用してそのステートメントをスキップすることを除いて、この問題の実際の原因が何であるか、およびこれをどのように解決する必要があるかは不明です。
どんな助けでも本当にいただければ幸いです!
TL; DR:これはおそらく、ROWベースのレプリケーションと組み合わされた不適切なテーブル設計が原因です。
私はこの問題に遭遇しました。古いデータベースを新しいサーバーに移動してレプリケーションをセットアップするように求められました。
スレーブをハングさせるのは、実際には件名のステートメントではないことがわかりました(SET @@ SESSION.GTID_NEXT = 'ANONYMOUS')。このステートメントは、トランザクションの開始時に発行されます。
mysql> SHOW BINLOG EVENTS IN 'mysql-bin.000196' FROM 96754384 LIMIT 5000;
+------------------+-----------+----------------+-----------+-------------+----------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----------+----------------+-----------+-------------+----------------------------------------------+
| mysql-bin.000196 | 96754384 | Anonymous_Gtid | 1 | 96754449 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000196 | 96754449 | Query | 1 | 96754537 | BEGIN |
| mysql-bin.000196 | 96754537 | Table_map | 1 | 96754608 | table_id: 241 (db.bad_table) |
| mysql-bin.000196 | 96754608 | Delete_rows | 1 | 96762805 | table_id: 241 |
| mysql-bin.000196 | 96762805 | Delete_rows | 1 | 96771002 | table_id: 241 |
...
| mysql-bin.000196 | 106681175 | Delete_rows | 1 | 106689372 | table_id: 241 |
| mysql-bin.000196 | 106689372 | Delete_rows | 1 | 106697569 | table_id: 241 |
| mysql-bin.000196 | 106697569 | Delete_rows | 1 | 106697626 | table_id: 241 flags: STMT_END_F |
| mysql-bin.000196 | 106697626 | Xid | 1 | 106697657 | COMMIT /* xid=28382600 */ |
| mysql-bin.000196 | 106697657 | Rotate | 1 | 106697704 | mysql-bin.000197;pos=4 |
+------------------+-----------+----------------+-----------+-------------+----------------------------------------------+
1219 rows in set (0.02 sec)
このテーブルには、6600万行あります。主キーまたは一意キーがないことがわかりました。これを担当するクエリは、マスターでインデックススキャンを使用します。
mysql> SHOW VARIABLES LIKE '%binlog_format%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
1 row in set (0.00 sec)
スレーブがこれをROWベースのレプリケーションで複製するには、スレーブで約1200回の全テーブルスキャンを実行する必要があります。ここではおそらく1200はかなり少ない数です。それは数十万に及ぶ可能性があります。レプリケーションは実際に機能しますが、この設計では、「seconds_behind_master」が無制限に大きくなります。
このテーブルに主キーとパーティションを追加します。また、同僚にコードを書き換えて、一括削除が不要になるように依頼します。これには、おそらく列を追加する必要があります。
編集:他の投稿にコメントするのに十分なポイントがないので、ここではコメントをここに追加します。他の人が述べたように、「SET GLOBAL sql_slave_skip_counter = 1」を発行すると、トランザクション全体がスキップされ、データの不整合が生じると思います。私が間違っていたら訂正してください。
簡単な修正は、binlog形式をQUERYまたはMIXEDに変更することです。これらの形式はデータの不整合にもつながる可能性があるため、binlog形式を変更する代わりに、根本原因を見つけて修正することをお勧めします。
現在、同じ問題が発生しています。 RHEL6、Percona 5.7.15-9。これは繰り返し発生する問題であり、1回限りの問題ではないため、ステートメントをスキップすることは一時的な修正にすぎません。私の場合はすぐにまた壊れるでしょう。
私はもう少し掘りました:
ps -eLo %cpu,pid,spid,cmd | grep <mysqld pid>
これにより、すべてのmysqlスレッドのPID(実際にはスレッドID)が取得され、それぞれのCPU使用率が示されます。私のシステムでは、そのうちの1つだけが比較的高かった(スレーブSQLスレッドだと思います)。
それから:
strace -s 128 -p <thread-pid>
これにより、read、pread、lseek呼び出しの連続ループが発生しました。それぞれの最初の引数としてファイル記述子があります...常に同じです。そう:
ls -l /proc/<thread-pid>/fd/<id-number-from-strace>
読み込まれるファイルへのシンボリックリンクです。私の場合、それはデータベース内のランダムなMyISAM .MYDファイルでした。そのテーブルの内容はstraceからの文字列の出力と一致しますが、これはすぐにはわかりません(読んでください)。
「テーブルレベルのロックを待機しています」というこのテーブルでは何もできませんでした。レプリケーションを最新の状態に戻すためにステートメントをスキップし、魔法のようにテーブルが再び使用可能になりました。修理、最適化、分析テーブルを行いました。それらのどれも何も報告しなかったが、おそらくこれがとにかく役立つことを願っています。
そうでない場合は、InnoDBに変換します。