スマートスタイル TECH BLOG

データベース&クラウド技術情報

pt-deadlock-loggerでデッドロックの情報を収集する

はじめに

MySQLでデッドロックに関する問題があり調査したいとき、InnoDB Monitor出力の LATEST DETECTED DEADLOCK セクションから直近に発生したデッドロックを確認することができます。ただし、これは直近で発生した1件しか確認ができません。
innodb_print_all_deadlocksを有効にすることで発生したデッドロックの情報を全てエラーログに出力できます。しかし、デッドロックが頻発している場合、その分ログへの出力も増えてしまいます。

Percona Toolkitに含まれるpt-deadlock-loggerを使用することで、定期的にSHOW ENGINE INNODB STATUSを実行し、LATEST DETECTED DEADLOCKが更新されたときのみ、その情報を記録することができます。

pt-deadlock-loggerの使用

インストールと設定ファイル

pt-deadlock-loggerのインストールの詳細はマニュアルを確認してください。

pt-deadlock-loggerのログインの簡略化のために、設定ファイルを追加しておきます
Percona Toolkitにおける設定ファイルの書き方については、マニュアルを確認してください。

MySQL用のユーザを作成します。必要な権限はPROCESSです。

使用方法

オプション無しで実行するとすぐにデッドロック情報の収集を開始します。
SHOW ENGINE INNODB STATUSの LATEST DETECTED DEADLOCK セクションから直近に発生したデッドロックの情報を取得し、そこから一部の情報を抜き出し出力します。

デフォルトでは30秒おきに永続的にSHOW ENGINE INNODB STATUSを実施し、前回とLATEST DETECTED DEADLOCKの内容が異なる場合は新たなデッドロックの情報を出力します。

役立つオプションを紹介します。

  • --run-time
    終了するまでの実行時間。 デフォルトでは、pt-deadlock-logger は永久に実行され、 --interval 秒ごとにデッドロックをチェックします。

  • --interval
    デッドロックをチェックする頻度。 --run-time が指定されていない場合、pt-deadlock-logger は無期限に実行され、間隔ごとにデッドロックをチェックします。デフォルトで30秒です。

  • --iterations
    デッドロックをチェックする回数。デフォルトでは、このオプションは未定義であり、無限回の反復を意味します。

なお、--run-time--iterationsを同時に指定した場合は、常に--run-timeの指定時間で終了します。
例えば、--run-time 1m --iterations 4 --interval 30とすると、30秒間隔で4回実行すると2分かかりますが、ツールは開始から1分で終了します。

この場合、4秒間隔で1時間の間デッドロックの情報収集を続けます。

  • --daemonize
    バックグラウンドで実行されます。

  • --log
    出力先のファイルを指定できます。 --daemonizeと一緒に使用します。

2回デッドロックを発生させたときの出力例です。

各収集方法の比較

デッドロックが何パターンか発生している可能性がある場合、SHOW ENGINE INNODB STATUSを1回実行するだけではデッドロックの情報を網羅的に集めることはできません。今回は、次の3つの方法を比較してみます

  • SHOW ENGINE INNODB STATUSを定期的に実行する
  • innodb_print_all_deadlocksを有効にする
  • pt-deadlock-loggerを使用する

出力内容

デッドロックを起こしたあと、それぞれの出力内容を確認します。

デッドロックを発生させる
trx1とtrx2はそれぞれ別の接続であることを示しています。

  • SHOW ENGINE INNODB STATUSの出力
  • エラーログの出力
  • pt-deadlock-loggerの出力

それぞれを比べると、SHOW ENGINE INNODB STATUSの出力とinnodb_print_all_deadlocksを有効にした場合のエラーログの出力はほとんど変わらないことがわかります。エラーログの方は*** (1) TRANSACTION:*** (2) WAITING FOR THIS LOCK TO BE GRANTED:といった部分が出力されていません。また、*** WE ROLL BACK TRANSACTION (2)という出力もないため、エラーログからはどちらのトランザクションがロールバックされたかはわかりません。
また、SHOW ENGINE INNODB STATUSの出力にはデッドロックの情報以外にもInnoDBに関連する情報が多数含まれております。デッドロックの調査に役立つ情報が含まれているかもしれません。

pt-deadlock-loggerの出力は他の2つに比べるとかなり少ないです。ただし、発生した時間やデッドロックを起こしたクエリ、どのテーブルのロックが解放されるのを待機していたかなど、調査に有益な情報は多く含まれています。

また、innodb_print_all_deadlocksを有効にした場合の出力とpt-deadlock-loggerの出力の場合、デッドロックが新たに発生したらその情報が出力されます。つまり出力内容に重複はありません。
一方、SHOW ENGINE INNODB STATUSを定期的に実行して情報収集する場合、デッドロックが発生していないとLATEST DETECTED DEADLOCKの内容は毎回同じです。

発生したデッドロック情報の網羅性

SHOW ENGINE INNODB STATUSから確認できるデッドロック情報は直近の1件です。例えば、1分間隔でSHOW ENGINE INNODB STATUSを実行する場合、1分間に2回デッドロックが発生すると片方のデッドロックの情報は取得漏れしてしまします。
pt-deadlock-loggerもSHOW ENGINE INNODB STATUSから情報を取得するため、同じことが言えます。
一方、innodb_print_all_deadlocksは発生するたびにエラーログに出力するので、短い期間に連続して発生しても情報の取得漏れを起こすことはありません。

SHOW ENGINE INNODB STATUSの実行間隔を短くすることで網羅性は高まりますが、その分重複して出力される情報も多くなります。
どの程度網羅的にデッドロックの情報を集めたいかと考えて収集間隔は選択するといいでしょう。

実行の簡易性

それぞれの方法を実行するために必要な準備について比較します。

SHOW ENGINE INNODB STATUSを定期的に実行する場合、そもそも定期的に実行する際に人が手動で実行するのは現実的ではありません。
スクリプトを作成したりして自動で実行するようにするのが一般的でしょう。そのような準備が必要となります。
innodb_print_all_deadlocksは動的に変更できるため、SETコマンドを実行するだけですぐに有効化できます。

pt-deadlock-loggerはツールのインストールなどが必要です。使用するために複雑な設定は不要ですが、商用環境ではツールのインストールは許可されていないといったこともあるかもしれません。

まとめ

それぞれの方法にメリットデメリットがありました。
SHOW ENGINE INNODB STATUSの出力結果には様々な情報が含まれており、一見優れているようにも思いますが、SHOW ENGINE INNODB STATUSを普段から読み慣れていないと、逆にどの部分を確認すればいいか困ってしまうかもしれません。
pt-deadlock-loggerは重要な部分を抜き出してくれているので、あまりSHOW ENGINE INNODB STATUSを見慣れていない人にはおすすめです。
また、SHOW ENGIN INNODB STATUSは1h間隔、pt-deadlock-loggerのモニター間隔は1m間隔と組み合わせて使ってもいいかもしれません。

Return Top