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

  1. MySQLのSlaveサーバーのレプリケーションを止める。
  2. /etc/my.cnfを書き換え、mysqlを再起動する。 ```ini [mysqld] innodb_force_recovery = 1

    
    ```terminal
/etc/init.d/mysqld restart
  1. 壊れた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;
  1. /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:
  1. /etc/my.cnfをlog-binを戻し、mysqlを再起動する。 ```ini [mysqld] log-bin=mysql-bin

    
    ```terminal
/etc/init.d/mysqld restart
  1. MySQLのSlaveサーバーのレプリケーションを再度開始。 原因がわからないので、また再発した場合の復旧メモとして記録しておこう。 追記) その後、2回MySQLのDBが同様にクラッシュ。 結局、 ・全DBをダンプ ・MySQL関連のモジュールを yumでアンインストール ・再度MySQLをインストール ・DBリストア を行ったところ、クラッシュしなくなった。