mysqlcheck がテーブルを破損していないと誤って報告する原因は何でしょうか?

mysqlcheck がテーブルを破損していないと誤って報告する原因は何でしょうか?

私たちは、顧客の 1 社のために MySQL サーバーを管理しています。このサーバーには、それぞれ約 50 個のテーブル (その多くは InnoDB テーブル) を持つ 100 個を超えるデータベースがあります。サーバーがクラッシュしたので、原因を突き止めようとしています。 を使用して再起動するとinnodb_force_recovery = 2、接続でき、error.log にエラーは表示されません。さらに重要なのは、mysqlcheck --all-databasesすべてのテーブルに対して が「OK」と報告することです。しかし、 を削除するとinnodb_force_recovery、サーバーが再びクラッシュし、スタック トレースが error.log に書き込まれ、 でしか停止できませんkill -9

このような状況で、問題のあるデータベースをどうやって見つければいいのでしょうか。また、mysqlcheck が破損したテーブルを見逃す原因は何でしょうか。無視してダンプからすべてのデータベースを復元するように言わないでください。1 つまたは 2 つのデータベースの場合や、めったに発生しない場合は許容できるかもしれませんが、同じサーバーで何度も問題が発生しており、ダンプからすべてを復元するには、毎回それを実行するには時間がかかり、手作業が必要になります。

サーバーのバージョンは 5.5.46 でinnodb_file_per_tableアクティブです。

要求された error.log の抜粋 (The tablespace free space info is corrupt特定のテーブルに存在せず、修正できないエラーがあることを意味しますか?):

180222 17:13:48 mysqld_safe Starting mysqld daemon with databases from /home/mysql
180222 17:13:48 [Warning] 'THREAD_CONCURRENCY' is deprecated and will be removed in a future release.
180222 17:13:48 [Note] /usr/libexec/mysqld (mysqld 5.5.46) starting as process 26242 ...
180222 17:13:48 [Note] Plugin 'FEDERATED' is disabled.
180222 17:13:48 InnoDB: The InnoDB memory heap is disabled
180222 17:13:48 InnoDB: Mutexes and rw_locks use InnoDB's own implementation
180222 17:13:48 InnoDB: Compressed tables use zlib 1.2.3
180222 17:13:48 InnoDB: Using Linux native AIO
180222 17:13:48 InnoDB: Initializing buffer pool, size = 128.0M
180222 17:13:49 InnoDB: Completed initialization of buffer pool
180222 17:13:49 InnoDB: highest supported file format is Barracuda.
180222 17:13:49  InnoDB: Waiting for the background threads to start
180222 17:13:50 InnoDB: 5.5.46 started; log sequence number 1632912830888
180222 17:13:50 [Note] Server hostname (bind-address): '0.0.0.0'; port: 3306
180222 17:13:50 [Note]   - '0.0.0.0' resolves to '0.0.0.0';
180222 17:13:50 [Note] Server socket created on IP: '0.0.0.0'.
180222 17:13:50 [Note] Event Scheduler: Loaded 0 events
180222 17:13:50 [Note] /usr/libexec/mysqld: ready for connections.
Version: '5.5.46'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MySQL Community Server (GPL) by Remi
InnoDB: Dump of the tablespace extent descriptor:  len 40; hex 000000000000000200000000061600000000126e00000004ffffffffffffffffffffffffffffbfaa; asc                    n                    ;
InnoDB: Serious error! InnoDB is trying to free page 512
InnoDB: though it is already marked as free in the tablespace!
InnoDB: The tablespace free space info is corrupt.
InnoDB: You may need to dump your InnoDB tables and recreate the whole
InnoDB: database!
InnoDB: Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
180222 17:13:50  InnoDB: Assertion failure in thread 2499464080 in file fsp0fsp.c line 3309
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
16:13:50 UTC - mysqld got signal 6 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help
diagnose the problem, but since we have already crashed,
something is definitely wrong and this may fail.

key_buffer_size=268435456
read_buffer_size=1048576
max_used_connections=0
max_threads=512
thread_count=0
connection_count=0
It is possible that mysqld could use up to
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 1314506 K  bytes of memory
Hope that's ok; if not, decrease some variables in the equation.

Thread pointer: 0x0
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 0 thread_stack 0x30000
/usr/libexec/mysqld(my_print_stacktrace+0x33)[0x842a1f3]
/usr/libexec/mysqld(handle_fatal_signal+0x42b)[0x82d9d3b]
[0x7bc420]
[0x7bc410]
/lib/libc.so.6(gsignal+0x50)[0x626b10]
/lib/libc.so.6(abort+0x101)[0x628421]
/usr/libexec/mysqld[0x85012e7]
/usr/libexec/mysqld[0x850147e]
/usr/libexec/mysqld[0x849c0b1]
/usr/libexec/mysqld[0x84a8a61]
/usr/libexec/mysqld[0x8561fef]
/usr/libexec/mysqld[0x85570a9]
/usr/libexec/mysqld[0x847b082]
/usr/libexec/mysqld[0x846bf04]
/usr/libexec/mysqld[0x846dad4]
/lib/libpthread.so.0[0x50d912]
/lib/libc.so.6(clone+0x5e)[0x6d347e]
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
information that should help you find out what is causing the crash.
180222 17:13:50 mysqld_safe Number of processes running now: 0
180222 17:13:50 mysqld_safe mysqld restarted

答え1

エラー メッセージ自体が、テーブル データを検証しても問題が解決しない理由を示しています。ページを解放しようとしましたが (おそらくテーブルまたはインデックスから)、そのページはすでに解放済みとしてマークされていました。つまり、テーブルまたはインデックスの 1 つがページを使用していましたが、そのページは別のテーブルまたはインデックスに提供できると見なされていました。そして、明らかに、InnoDB が実際に解放されているページを認識していない場合、問題が発生する可能性があります。

すべてのテーブル/インデックス データをダンプして再ロードすることは、InnoDB に空きページのコレクションを再構築する機会を与えることを意味します。理想的には、これを新しいデータベースで実行します。なぜでしょうか。それは、破損エラーが 1 つだけであると想定してはいけないからです。したがって、データを新規インストールに移動する場合、追加の検出されていない破損の問題があったとしても心配する必要はありません。

答え2

提案されたように、ダンプしてそれらのダンプから復元することが、最終的にすべてのデータベースを復元する方法として私が選択した方法です。幸運にも、innodb_force_recovery = 2エラーなしですべてをダンプできたため、バックアップからのダンプを使用する必要はありませんでした。もちろん、エラーの本当の原因を見つけたいのですが、MySQL はバグ レポートで「テーブルスペースの空き領域情報が壊れています」といういくつかの言及以外には役に立ちません。エラーの原因を特定して除去しなければ、最終的には再発すると思います。おそらく、顧客は私以上に怒るでしょう。

ハードウェアの不良が原因かもしれませんが、システム内のすべてのディスクの SMART データは正常で、/var/log/messagesクラッシュ時に疑わしいものは何も含まれていませんでした。予期しない電源喪失や再起動もありませんでした。

関連情報