状況とエラー文

状況としては、ECSでMySQLコンテナをデプロイする際に、すぐにコンテナが落ちてしまうことでタスクが失敗していました。
そこでCloudWatchを見てみると、この2つのログが大量に出力されている状況でした。

[Note] InnoDB: Check that you do not already have another mysqld process using the same InnoDB data or log files.
[ERROR]InnoDB: Unable to lock ./ibdata1 error: 11

前提

だいたいこのエラーを検索にかけると、以下の内容が解決策として有効とされています。

  • MySQLの再起動
  • MySQLの他プロセスをキルする(エラー文的にも解決法紹介でこれが圧倒的に多い)
  • my.cnf ファイルから「innodb_force_recovery=1」パラメータを削除
  • /var/lib/mysql/ib_logfile0 と var/lib/mysql/ib_logfile1を削除

「全然解決せんやないかい!!!」

となり、あなたのエラーはどこから?状態だったのでその時の備忘録です。
ただし、この方法はデータが壊れてしまう恐れもあるので、実施は状況を見て行う必要があります。
なので、最初は他の解決法を試した上で解決しなかった場合の最終的な手段として捉えています。

先に結論

解決策だけでいうと、こちらの記事を見つけて下記のコマンドで解決しました。
コンテナが落ちてしまう前にコンテナに入って実行する必要があり、スピード勝負でした。

 /var/lib/mysql/# mv ibdata1 ibdata1.bak
 /var/lib/mysql/# cp -a ibdata1.bak ibdata1
 /var/lib/mysql/# mv ib_logfile0 iblog_file0.bak
 /var/lib/mysql/# cp -a iblog_file0.bak ib_logfile0
 /var/lib/mysql/# mv ib_logfile1 iblog_file1.bak
 /var/lib/mysql/# cp -a iblog_file1.bak ib_logfile1

ただ、「ibdata1Innodbiblog_fileってなんやねん」という疑問が残りました。
そのため、下記ではこれらについて学び、このコマンドで何故に解決できたのかをまとめたいと思います。

InnoDBとは

InnoDBは現在のMySQL標準のデータベースエンジン(ストレージエンジン)とのことです。
データベースエンジンといえば、「select」「insert」「update」「delete」などのデータの読み書きを行なってくれるもので、エンジンと言われるだけあってデータベースの中枢を担う処理を行なってくれるものです。

例えば、下記のようなSQL文を例に見てみると、

SELECT * FROM users WHERE age = 20;
  1. usersテーブルからageが20であるレコードを全て返すんだなと解釈してくれます
  2. その後にこのSQL文の条件に合ったレコードを検索してくれます
  3. そして、検索したレコードをSQL文の実行結果として返却してくれます

いつも行なってることですね。

自分がSQL文を書いてデータを操作しているというイメージではなく、書いたSQL文をデータベースエンジンに渡すとそれに沿ったものをデータベースエンジンが仲介して返してくれるという形です。
お店で料理を注文したら、ホールの人が持ってきてくれるのと同じイメージです。

そして以下3つが簡単にInnoDB特有の主な機能かなと思います。

行ロック

表ではなく、行単位のロックのため複数人で同じ表の別の行を操作できるのが利点。
逆にいえば、複数人で同じ行を操作できないので「悪いなのび太、この行は1人用なんだ」ができて整合性を保てます。

トランザクション

トランザクションとは一連の処理を内包する1つの処理としてみたものです。
例えば、業務を開始する前に「起床」「PCを起動」「出勤打刻」という大きく3つのフローがあるとして、この1つ1つがSQLの処理と考えます。
起床すればPCを起動させることができ、PCが起動すれば打刻もできます。
ただ、もし起床していないのにPCが起動したりPCが起動していないのに出勤打刻がされていると普通に怪奇現象で困ってしまいます。
そのためこのような、どこかの処理が転けた時に、整合性が保てるようにトランザクション管理されている処理はロールバックされます。
これで、寝坊すればきちんと出勤打刻は押されません。しっかり起きましょう。

クラッシュリカバリ

例えば異常終了した場合などに、その時点で確定している箇所までロールバックしてくれます。
自分の環境ではWorkbenchが落ちまくりなのでロールバックしまくりです。

ibdataとは

InnoDBのデータ(テーブルに存在するデータ)やテーブルのテーブル名やカラム名などのテーブル情報などが存在します。

ib_logfileとは

トランザクションのログなどが保存されています。
先ほどのクラッシュした際のリカバリにも使用されます。

mvとcpコマンドで解決した理由

では、ある程度用語の意味がわかったところで、なぜ今回のエラーはこれらのコマンドで解決できたのか。

 /var/lib/mysql/# mv ibdata1 ibdata1.bak
 /var/lib/mysql/# cp -a ibdata1.bak ibdata1
 /var/lib/mysql/# mv ib_logfile0 iblog_file0.bak
 /var/lib/mysql/# cp -a iblog_file0.bak ib_logfile0
 /var/lib/mysql/# mv ib_logfile1 iblog_file1.bak
 /var/lib/mysql/# cp -a iblog_file1.bak ib_logfile1

これらのファイルはMySQLが起動するとロックされます。
それは前述でも述べたようにデータの情報であったりトランザクションの情報のため他のMySQLのプロセスからアクセスされると整合性が保てなくなるからです。
しかし今回はその他のMySQLのプロセスはキルしている状態です。
ただ、何かしらが原因でファイルが別のMySQLプロセスにロックされていると判定されていたので、名前を変更することで、ibdata1が作成可能になります。
この時点でibdata1が存在しないため、ロックされている事実がなくなります。
そして、名前を変更したファイルの中身を新たにibdata1としてコピーすることで、現在のMySQLプロセスがロックすることができるようになりました。(ib_logfileも同様の理由)
めでたしめでたし。

参考文献