2015年3月17日火曜日

mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `tablename` at row: nnnn

サーバーに余力ができたので、viliv n5 のDBをサーバー環境にも設置して同期することにした。

なので、タスクスケジューラーと mysqldump で バックアップされたあるDBのデータを新サーバーに移そうと思った。

移した後、そのDB依存のサービスを起動すると、テーブルのチェックサムが一致しないエラー。
見てみると、15テーブルのうち3つしか作成できていなかった。
バックアップの中身をみると 3 テーブルしか出力されていなかった。

手動で mysqldump してみると 以下のエラーが出た。

mysqldump: Error 2013: Lost connection to MySQL server during query when dumping  table `tablename` at row: nnnn

このエラーが出ると MySQL ごと落ちる。


エラーの原因を検索すると、バグだという話も。

とりあえず max_allowed_packet とか wait_timeout 等の調整で改善するらしいことが分かる。
 もともと max_allowed_packet=16M としていたので原因は他にあるのではと思いつつも
その table は、ファイルを分割して暗号化して保存しておくところなので、1つ1つが大きい。
なので、上記のエラーが出ても納得といえば納得。(InnoDB)

なので以下を my.ini で試す。


[mysqld]
wait_timeout=86400
max_allowed_packet=32M
innodb_buffer_pool_size=1G

結果、変化なし。

ということで、地味に調査する方針に変更。


そのテーブルに対して select * すると エラーが出ていた row でクラッシュ。
その row を避けて select * すると問題なし。
select で BLOB以外のフィールドを指定すると問題なし。
select で BLOBのフィールドを指定すると同様のエラーでクラッシュ。

結局、エラーが出ている row 以降の30レコードぐらいに対してアクセスできないことがわかった。
うちの使ってるバージョンだと InnoDB の recovery ができないらしいので、諦める。
エラーチェックも素通りする。

2013 年ごろのバックアップに、たまたまそのレコードが残っていたのでそれを抜き出して復元する方針で復旧作業を開始。

オリジナルのテーブル名を変更
mysql alter table ORIGINAL rename to WORK1

もともとのテーブル名に古いバックアップを復元
mysql -uroot -p database ORIGINAL <2013年ごろの完全なバックアップからそのテーブル

復旧用のテーブルを作成
create table WORK2 省略

オリジナルから正常なデータのみコピー

insert into WORK2 select * from WORK1 where idx<エラーの出た row
insert into WORK2 select * from WORK1 where idx>=正常な row

バックアップ から異常だった部分をコピー
insert into WORK2 select * from ORIGINAL where (idx>=エラーの出た row) and (idx<正常な row)

バックアップ を削除
drop table ORIGINAL;
復旧用のテーブルをオリジナルのテーブル名に変更

mysql alter table WORK2 rename to ORIGINAL;

オリジナルのテーブル WORK1 は、詳細な調査をしてから削除したほうがいいかもしれない。
#drop table WORK1;


ということで復旧。
mysqldump もエラーなし。

バグでも何でもなく、単に破損。

原因。
モバイルだったからだろう。
大きなデータの処理中にサスペンドにでも入って破損したのではないかと。


MicroSD に対してDBが置いてあるので、まあ壊れるだろう・・・。
一応、サスペンド前にディスクのフラッシュは実施していたが・・・。
サービスの稼働状況によっては意味ない気もする。
MySQL を停止してから、サスペンドに移行する設定に変更。
これで様子見。

ということで、破損の可能性もあるんだよという話。

ついでにサスペンドのバッチファイル。

以下、Windows 7 Pro用。

サスペンドの後に net start しているが、レジューム後に MySQLも再起動するかというと、これでうまくいく。
dosutyex は、スリープとか入力待ちなどの機能を提供するものなら別になんでもいいと思う。


@echo off
cls
@ECHO OFF
cd %~dp0

TASKLIST | FIND "mysqld-nt.exe" > NUL
IF NOT ERRORLEVEL 1  GOTO PGOK
goto PGNG

:PGOK
echo Terminating mysql
net stop "MySQL41"
c:\dosutyex -sleep 3000

echo The drive caches are now flushed.
D:\10_TOOLS\00_SOFTDEV\SysinternalsSuite\sync -r

cls
echo 10 sec
c:\dosutyex -sleep 1000
cls
echo 9 sec
c:\dosutyex -sleep 1000
cls
echo 8 sec
c:\dosutyex -sleep 1000
cls
echo 7 sec
c:\dosutyex -sleep 1000
cls
echo 6 sec
c:\dosutyex -sleep 1000
cls
echo 5 sec
c:\dosutyex -sleep 1000
cls
echo 4 sec
c:\dosutyex -sleep 1000
cls
echo 3 sec
c:\dosutyex -sleep 1000
cls
echo 2 sec
c:\dosutyex -sleep 1000
cls
echo Supended
c:\dosutyex -sleep 1000

C:\Windows\System32\rundll32.exe Powrprof.dll,SetSuspendState Sleep

c:\dosutyex -sleep 5000

echo Rebooting mysql
net start "MySQL41"

ちなみに、viliv n5 で MicroSD は、取り外し可能なメディアとしても扱えるが、ディスクキャッシュを有効にしないと遅くて使いものにならない・・・。 MySQLに限らず、勝手に読み書きする系はこの手の対策をもっと考えたほうがいいのかもしれない。

0 件のコメント:

コメントを投稿