スマートスタイル TECH BLOG

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

pt-killの活用について

Percona Toolkit に含まれる pt-kill というツールがあります。

本ツールは、その名称からMySQLのセッションを効率的に切断するためのものという印象が強いですが、そのような緊急措置的な利用方法の他にも様々な機能を備えています。

今回のブログでは、pt-killの使い方について整理していきたいと思います。

なお、利用している環境情報は以下の通りです。

OS version MySQL version pt-kill version
CentOS Stream 8 8.0.32 3.5.1

pt-killのダウンロード、前提パッケージのインストールは以下の通りです。

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

pt-killの基本的な使い方

例えば10秒以上クエリを実行しているappユーザをすべてkillしたい、という場合以下のようになります。

appユーザの接続を10接続を作ると、killされる様子が確認できます。

pt-kill の処理フローについて

pt-kill の処理フローは、以下のとおりです。
それぞれのカテゴリごとに複数のオプションがあり、複数のオプションを組み合わせて意図した動作を実現します。

一定の間隔でSHOW PROCESSLISTを取得するところから開始し、SHOW PROCESSLISTの結果について加工、評価、評価結果へのアクションを行います。

前項で指定した --interval はこの一連のフローの実行間隔です。
--busy-time--match-user はマッチ条件にあたります(QUERY MATCHESを参照)。
--victim はアクション対象選定の部分にあたり、以下からいずれかを選択します。

説明
oldest 最も古い接続を対象とする
all すべてのマッチした接続を対象とする
all-but-oldest 最も古い接続以外を対象とする

recent/latest が無いのが気になりますが、大体のケースでは最も新しい接続が全体のパフォーマンスを損なうということは無いためでしょう。
oldestは、ロックの大本のセッションを切断するような利用用途を想定しており、all-but-oldest は、「キャッシュスタンピード」が発生した場合の対策を想定した値のようです。

アクション実行については、以下から選択できます。

オプション 説明
--kill 接続を切断する
--kill-query 実行中のクエリを中断する
--print 対象をログ(デフォルトではSTDOUT)に表示
--execute-command 任意のコマンドを実行する

アクションを拡張するオプションは以下です。

オプション 説明
--kill-busy-commands –busy-time オプションが対象とするCommand列の値を追加する
--fingerprint –printで表示されるクエリをフィンガープリントに変更する

特に理由がなければ --print は指定しておいたほうが有用でしょう。
--busy-time オプションは Command: Query である接続のみを対象としますが、PREPARE などのコマンドは Command: Execute になるなど対象から外れてしまうため、 --busy-time を指定した場合は --kill-busy-commands も指定したほうがよいでしょう。
その名称から効果を勘違しがちですが、--kill-busy-command はあくまで--busy-timeの対象範囲を広げるためのオプションであり、接続を切断したい場合は、さらに--kill オプションをつける必要があります。

最後にグループ化について触れておきます。

--group-by <SHOW PROCESSLISTの列名 or fingerprint> と指定すると、指定した値でグループ化してくれます。

デフォルトでは、1つのグループ(default)にすべてが含まれる形になり、特にグループ化は必須ではありません。

グループ化が役立つのは、CLASS MATCHES を使う場合です。

最もわかりやすいのは、 --query-count になるかと思いますが、--group-by User と組み合わせると 同じ User の値を持つ接続のカウントが --query-count 以上になったグループがマッチするという結果になります。
より実践的には、--match-command--match-user などとさらに組み合わせて使うとよいでしょう。

pt-kill でパフォーマンス情報を取る

例として、接続数が 100 以上になったら検知するたびに通知し、パフォーマンス解析情報を取る、といった事も可能です。

以下のスクリプトを --execute-command に指定します。

10秒ごとにパフォーマンス情報を取ることとします。
先の説明のとおり、--group-by を指定しない場合、すべての接続は単一のグループに入ります。
そして、グループに対して --query-count 100 つまり含まれる接続数が100以上のグループがマッチ条件で評価されます。
--match-all はすべてにマッチする条件ですので、単純に接続数が100以上になったらアクションが実行される、ということになります。
--ignore-user では、MySQLにおけるシステムユーザを指定して除外しています。

100 接続を作ってみます。

pt-killのログには、以下が出力されます。
デフォルトでは、--victim oldest なので、マッチするのは最古の1接続のみです。
--victim all にすると、マッチした接続ごとに --execute-command が実行されてしまうのでご注意ください。

ログが作成されていることを確認しました。

Slackへ通知も行われました。
slack notify

今回のコマンドには指定しませんでしたが、 --kill--kill-query をあわせて指定すると、問題が表面化する前にボトルネックとなっている接続を中断することができます。

pt-killで実行中の接続のEXPLAINを取る

pt-killでアクション --kill, --print, --execute-command の3つを組み合わせる場合、実行順序は以下となります。

  1. --print
  2. --execute-command
  3. --kill

pt-killでは、--daemonize モードで実行した際に、 --log オプションで出力をログファイルに書き込みます。
出力は --print オプションで行われますので、その後に実行される --execute-command のスクリプトで対象となった接続の Id を取得する事も可能です。

例えば、10秒以上かかっている遅いクエリが存在した場合に、それらのEXPLAINをログに出すという事もできます。

get-explain.sh は以下の内容です。

以下のクエリを実行してみます。

EXPLAINコマンドの結果と、その接続が実行していたSQLを以下のように取得できました。

惜しい点として、マッチした接続ごとに--execute-commandが実行されてしまうため、複数の接続をマッチさせてそれらすべてのEXPLAINが取りたいというニーズには応えられていません。
スクリプトの中で排他処理するなど、工夫が必要になります。

pt-kill VS

pt-killと似たような機能として、 MariaDB版のkillコマンドではユーザやホストを指定して一括killを行う機能が拡張されています。

MySQLでは見当たりませんが、一度それを実行するだけであれば簡単なワンライナーで可能なので特別必要としないということかもしれません。

また、今回実装してみたEXPLAINを取るという仕組みについては、PerconaやMariaDBの機能である、log_slow_verbosityを利用することで、スロークエリに出力されたクエリと一緒に実行計画を出力するという機能が存在します。

https://mariadb.com/kb/en/explain-in-the-slow-query-log/

https://docs.percona.com/percona-server/5.7/diagnostics/slow_extended.html#log_slow_verbosity

pt-killでは好きなスクリプトをフックに使えるという点で柔軟性がありますが、これらのDBの機能を利用するのもよいでしょう。

まとめ

今回は、 pt-kill についてご紹介させていただきました。

基本的にはパフォーマンス上の問題となりうる前に、過剰な接続を切断、もしくはクエリを中断することで未然に防ぐことを目的としたツールではありますが、様々なアレンジを加えられることをご理解いただけたかと思います。

チャンスが有ればPercona Toolkitを活用してみていただけると幸いです。

Return Top