午前2時のPagerDutyアラート午前2時に呼び出しを受けました。監視ダッシュボードを見るとトラフィックは100%減少し、データベースがダウンしています。MySQLを再起動しようとしても、すぐにクラッシュしてしまいます。エラーログ(通常は /var/log/mysql/error.log または journalctl -xeu mysql で確認可能)を素早く確認すると、次のような厄介なメッセージが表示されています。
InnoDB: Unable to lock ./ibdata1, error: 11
InnoDB: Check that you do not already have another mysqld process using the same InnoDB data or log files.
Linuxシステムでは、エラーコード11を使用して EAGAIN(リソースが一時的に利用不可)を通知します。この文脈では、InnoDBエンジンが ibdata1 ファイルに対して排他的な fcntl ロックをかけようとしています。しかし、別のプロセスやハングしたスレッドがすでにそのロックを保持しているため、失敗します。MySQLは、2つのプロセスが同じファイルに書き込むことによって数分以内に修復不可能なデータ破損が発生するのを防ぐため、即座にシャットダウンします。
よくある原因- 以前のMySQLインスタンスがクラッシュしたが、ゾンビプロセスが残っている。- 古いプロセスが10GBのバッファプールをディスクにフラッシュし終える前に、SystemdがMySQLを再起動しようとした。- 不適切な所有権(例:mysql ではなく root がファイルを所有している)により、サービスが自身のロックを管理できない。- Docker環境において、コンテナの再起動時にホストボリューム上のファイルハンドルの解放に失敗した。- 2つの異なるMySQLインスタンスが、誤って同じ datadir を使用するように設定されている。## デバッグのワークフロー### 1. ゾンビプロセスの追跡systemctl status を鵜呑みにしてはいけません。サービスマネージャーがMySQLは停止していると判断していても、Linuxカーネルがまだ稼働中のプロセスを追跡している場合があります。ps を使用して、残存しているデータベースエンジンを探します。
ps aux | grep -iE 'mysql|mariadb'
もし1234のようなプロセスID(PID)が表示された場合は、まず正常なシャットダウンを試みてください。30秒以内に反応がない場合は、より強力なシグナルを使用します。
# まずは丁寧な方法を試す
kill 1234
# 10秒待機。まだ残っている場合は強制終了する:
kill -9 1234
2. ファイル保持者の特定ps で明らかな原因が見つからない場合、認識できないプロセスによってロックが保持されている可能性があります。fuser ユーティリティを使用すると、どのプロセスがデータファイルにアクセスしているかを正確に特定できます。root権限で実行してください。
fuser -v /var/lib/mysql/ibdata1
出力にPIDが表示された場合、それが原因です。これは、バックアップスクリプトや自動スナップショットがデータベースファイルをロックしている構成でよく見られます。
3. 古いロックファイルの確認MySQLはアクセスを調整するために小さな .lock ファイルを作成します。サーバーの電源が切れた場合、これらのファイルがディスクに残ることがあります。データディレクトリにこれらの残骸がないか確認してください。
ls -la /var/lib/mysql/*.lock /var/lib/mysql/mysql.sock.lock
MySQLプロセスが実行されていないことを確認したら、これらのファイルを /tmp/ などの一時ディレクトリに移動し、サービスの再起動を試みてください。
実証済みの解決策### 解決策A:ディレクトリ権限のリセット権限の問題は、しばしばロックエラーのように見えることがあります。mysql ユーザーがディレクトリに書き込めない場合、ロックを作成できません。これは、手動でのデータ移行や rsync 操作の後に頻繁に発生します。
# 所有権をmysqlユーザーとグループにリセットする
chown -R mysql:mysql /var/lib/mysql
# 標準的なディレクトリ権限(750)を設定する
find /var/lib/mysql -type d -exec chmod 750 {} +
# 標準的なファイル権限(640)を設定する
find /var/lib/mysql -type f -exec chmod 640 {} +
解決策B:Dockerマウントの競合の解消DockerやKubernetesでは、このエラーは通常、ホストOSが以前のコンテナからのファイルハンドルを解放していないことを意味します。単にコンテナを再起動するだけでは不十分な場合が多いです。カーネルレベルのファイルロックを解除するために、Dockerデーモン自体を再起動する必要があるかもしれません。
docker-compose down
systemctl restart docker
docker-compose up -d
解決策C:緊急リカバリモード他にプロセスがなく権限も完璧な場合、 ibdata1 ファイルが「ダーティ」な状態で固まっている可能性があります。リカバリモードに入ることで、初期のロックチェックをバイパスできます。my.cnf または /etc/mysql/mysql.conf.d/mysqld.cnf の [mysqld] セクションの下に次の行を追加してください。
innodb_force_recovery = 1
サービスを開始します。起動した場合は、すぐに mysqldump を使用してフルバックアップを作成してください。データが安全に確保されたら、リカバリ用の行を削除し、通常の再起動を試みます。リカバリモードは多くのデータの整合性チェックを無効にするため、本番サイトをリカバリモードが有効な状態で運用することは絶対に避けてください。
修正の確認ロックを解除した後、サービスを開始し、ログをリアルタイムで監視します。
systemctl start mysql
tail -f /var/log/mysql/error.log
[System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. というメッセージを探してください。これが表示されれば、データベースはオンラインに戻り、正常な状態です。

