MySQLでInnoDBのDatabase pageが壊れる。
MySQL5.1,5.5で3~4年運用していたDatabaseをMySQL5.6にアップグレードして約3ヶ月が経過したが、その間InnoDBのDatabase pageが壊れる事象が発生している。 利用したのは次のバージョンのMySQL5.6系。 mysql-community-server.x86_64 5.6.17-4.el6 mysql-community-server.x86_64 5.6.19-2.el6 MySQLを利用しているLAMPアプリがエラーになり、妙なエラーが出ている。
PHP Warning: PDOStatement::execute(): MySQL server has gone away in xxx.php on line 78
/var/log/mysql.logを見てみると、次のようなログ出力され、ログも肥大化している。 2回目に壊れた時。
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 78481.
InnoDB: You may have to recover from a backup.
2014-05-27 04:19:31 7f25e7fff700 InnoDB: Page dump in ascii and hex (16384 bytes):
nnoDB: End of page dump
2014-05-27 04:19:31 7f25e7fff700 InnoDB: uncompressed page, stored checksum in field1 881243038, calculated checksums for field1: crc32 3412082521, innodb 47248
3626, none 3735928559, stored checksum in field2 910221241, calculated checksums for field2: crc32 3412082521, innodb 910221241, none 3735928559, page LSN 0 396
9463722, low 4 bytes of LSN at page end 3969463722, page number (if stored to page already) 78481, space id (if created with >= MySQL-4.1.1 and stored already)
405
InnoDB: Page may be an index page where index id is 904
InnoDB: (index "PRIMARY" of table "db01"."tbl01")
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 78481.
InnoDB: You may have to recover from a backup.
InnoDB: It is also possible that your operating
InnoDB: system has corrupted its own file cache
InnoDB: and rebooting your computer removes the
InnoDB: error.
InnoDB: If the corrupt page is an index page
InnoDB: you can also try to fix the corruption
InnoDB: by dumping, dropping, and reimporting
InnoDB: the corrupt table. You can use CHECK
InnoDB: TABLE to scan your table for corruption.
InnoDB: See also http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 78481.
InnoDB: You may have to recover from a backup.
3回目に壊れた時。
InnoDB: End of page dump
2014-06-12 04:03:28 7f03d7e15700 InnoDB: uncompressed page, stored checksum in field1 1783178167, calculated checksums for field1: crc32 6456952, innodb 4192140
979, none 3735928559, stored checksum in field2 1335262152, calculated checksums for field2: crc32 6456952, innodb 1335262152, none 3735928559, page LSN 3 36580
04246, low 4 bytes of LSN at page end 3658004246, page number (if stored to page already) 64982, space id (if created with >= MySQL-4.1.1 and stored already) 10
56
InnoDB: Page may be an index page where index id is 1980
InnoDB: (index "url" of table "db01"."tbl01")
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 64982.
InnoDB: You may have to recover from a backup.
InnoDB: It is also possible that your operating
InnoDB: system has corrupted its own file cache
InnoDB: and rebooting your computer removes the
InnoDB: error.
InnoDB: If the corrupt page is an index page
InnoDB: you can also try to fix the corruption
InnoDB: by dumping, dropping, and reimporting
InnoDB: the corrupt table. You can use CHECK
InnoDB: TABLE to scan your table for corruption.
InnoDB: See also http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 64982.
InnoDB: You may have to recover from a backup.
2014-06-12 04:03:28 7f03d7e15700 InnoDB: Page dump in ascii and hex (16384 bytes):
len 16384; hex 6a4923b70000fdd60000fb450001007700000003da08b71645bf000000000000000000000420005e3f208177007e002c0000000201730174000000000009fa660000000000000000
07bc00000000000000000000000000000000000000000100020047696e66696d756d0005000b00007375707
どちらも、同じDB・テーブルのINDEXが格納されているPageのようだ。 check tableしてみると、doesn’t existと、よくわからない結果が…
mysql> check table db01.tbl01;
+------------+-------+----------+----------------------------------+
| Table | Op | Msg_type | Msg_text |
+------------+-------+----------+----------------------------------+
| db01.tbl01 | check | Error | Table 'db01.tbl01' doesn't exist |
| db01.tbl01 | check | status | Operation failed |
+------------+-------+----------+----------------------------------+
このテーブルには次のようなカラムとINDEXがある。
DROP TABLE IF EXISTS `tbl01`;
CREATE TABLE `tbl01` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` text NOT NULL,
`dt` datetime NOT NULL,
`host` text NOT NULL,
`path` text NOT NULL,
`title` text NOT NULL,
`description` text NOT NULL,
`rem` text NOT NULL,
PRIMARY KEY (`id`),
KEY `url` (`url`(255)),
KEY `host` (`host`(255))
) ENGINE=InnoDB AUTO_INCREMENT=5872167 DEFAULT CHARSET=utf8;
このINDEXがまずいのだろうか? ※2度目に壊れた時には KEY `host` (`host`(255))→ KEY `host` (`host`(100))にしたが、再度壊れた。
PRIMARY KEY (`id`),
KEY `url` (`url`(255)),
KEY `host` (`host`(100))
あるいは、DISKが壊れかけていて、格納したデータが本当に壊れているのかもしれない。 このDB・TABLEはこのサーバーの中でも最も大きいDBなので、そのDISK領域にぶつかりやすいのか? しかし、必ずINDEXというのもヘンである。データ領域が壊れてもおかしくない。 あるいは、MySQLのConfigがよろしくないのかもしれない。 とりあえず復旧させて、様子を見ることにしました。 MySQLを復旧させた手順は次の通り。 1度目は全Databaseをダンプ、リストアしたが、今回は該当のTABLEのみで復旧できた。 参考
14.19.2 Starting InnoDB on a Corrupted Database
- MySQLのSlaveサーバーのレプリケーションを止める。
- /etc/my.cnfを書き換え、mysqlを再起動する。 ```ini [mysqld] innodb_force_recovery = 1
```terminal
/etc/init.d/mysqld restart
- 壊れたTABLEをダンプする。 ```terminal mysqldump –user root -p –opt –single-transaction –default-character-set=utf8 –hex-blob db01 tbl01 > tbl01_20140612.sql Enter password:
4. 何かテーブルが壊れるような要因がありそうなら、変える。今回は、urlのindexサイズを小さくしてみた。 ```terminal
DROP TABLE IF EXISTS `tbl01`;
CREATE TABLE `tbl01` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` text NOT NULL,
`dt` datetime NOT NULL,
`host` text NOT NULL,
`path` text NOT NULL,
`title` text NOT NULL,
`description` text NOT NULL,
`rem` text NOT NULL,
PRIMARY KEY (`id`),
KEY `url` (`url`(100)),
KEY `host` (`host`(100))
) ENGINE=InnoDB AUTO_INCREMENT=5872167 DEFAULT CHARSET=utf8;
- /etc/my.cnfをinnodb_force_recoveryを外し、mysqlを再起動する。 ```ini [mysqld] #log-bin=mysql-bin ※復旧時にバイナリログが不要ならlog-binをコメントにする。
#innodb_force_recovery = 1
```terminal
/etc/init.d/mysqld restart
※これをやらないと、Tableをインポート時にエラーが発生した。
```terminal
ERROR 1881 (HY000) at line 46: Operation not allowed when innodb_forced_recovery > 0.
6. Tableをインポートする。 ```terminal
mysql --user root -p db01 < tbl01_20140612.sql
Enter password:
- /etc/my.cnfをlog-binを戻し、mysqlを再起動する。 ```ini [mysqld] log-bin=mysql-bin
```terminal
/etc/init.d/mysqld restart
- MySQLのSlaveサーバーのレプリケーションを再度開始。 原因がわからないので、また再発した場合の復旧メモとして記録しておこう。 追記) その後、2回MySQLのDBが同様にクラッシュ。 結局、 ・全DBをダンプ ・MySQL関連のモジュールを yumでアンインストール ・再度MySQLをインストール ・DBリストア を行ったところ、クラッシュしなくなった。