MySQL InnoDB デッドロックを調査する。integration test のフレーキーテスト、 SAVEPOINT does not exist エラー、deadlock detected エラーの原因特定に使用。 「デッドロック調査」「deadlock」「SAVEPOINT エラー」「テストがランダムに落ちる」 「フレーキーテスト」で使用する。
integration test の並列実行時に発生するデッドロックの原因を特定する。
127.0.0.1:3307 で起動中mysql -h 127.0.0.1 -P 3307 -u rootスキルが読み込まれた時点で general_log を有効化する。 再現テスト実行前からクエリを記録しておくことで、 thread ID の追跡漏れを防ぐ。
mysql -h 127.0.0.1 -P 3307 -u root -e "
SET GLOBAL general_log = OFF;
SET GLOBAL log_output = 'FILE';
SET GLOBAL general_log_file = '/var/lib/mysql/general.log';
SET GLOBAL general_log = ON;
" 2>/dev/null
調査完了後は必ず無効化すること(「調査完了」セクション参照)。
対象テストを -count=N で複数回実行して再現する。
go test -tags="integration" -count=100 \
-run 'TestA|TestB' ./path/to/package/...
NOTE: -count を使わないと Go のテストキャッシュにより1回しか実行されない。
mysql -h 127.0.0.1 -P 3307 -u root \
-e "SHOW ENGINE INNODB STATUS\G" 2>/dev/null \
| sed -n '/LATEST DETECTED DEADLOCK/,/TRANSACTIONS$/p'
deadlock log から以下を読み取る:
deadlock log だけではどのテスト関数が原因か特定できない。 general_log は初期化セクションで有効化済みのため、 thread ID で全クエリをトレースできる。
テスト再現後、deadlock log から thread ID を特定:
mysql -h 127.0.0.1 -P 3307 -u root \
-e "SHOW ENGINE INNODB STATUS\G" 2>/dev/null \
| sed -n '/LATEST DETECTED DEADLOCK/,/TRANSACTIONS$/p' \
| grep -E 'thread id|^INSERT|^DELETE|^UPDATE'
thread ID でクエリ履歴を照合:
docker compose exec db cat /var/lib/mysql/general.log \
| grep -E '^\d.*\s(THREAD_ID_1|THREAD_ID_2)\s' \
| grep -v -E 'SET |SELECT @@|statistics|Close stmt'
クエリ内容(テーブル名、INSERT/DELETE の値)からテスト関数を特定する。
deadlock log の HOLDS/WAITING から原因パターンを判定する。 詳細は lock-patterns.md を参照。
原因パターンに基づき改善案を検討する。 詳細は remediation.md を参照。
general_log を無効化する。有効のままだと I/O 負荷が継続するため必ず実行する。
mysql -h 127.0.0.1 -P 3307 -u root \
-e "SET GLOBAL general_log = OFF;" 2>/dev/null