2015年11月12日木曜日

tomcatを再起動せずにlong_query_timeの変更を反映させられないかの思考実験

なんか作ろうと思っていて、その考えてる過程を整理のためにメモ。
取り敢えず目の前にある事案を想定してtomcat, long_query_timeだけど、コネクション永続化しててセッション変数が実効パラメーターなグローバル変数の変更は全部一緒。

どうでもいいですがマークダウンがただのテキストとして書かれてるのは仕様です(このあと社内のドキュメントにコピううんなんでもない)


## 前提

1. `SET GLOBAL long_query_time= n`は@@grobal.long_query_timeの値を書き換える

2. 各スレッドの実効パラメーターは @@session.long_query_time であり、 @@global.long_query_time は @@session.long_query_timeのデフォルト値である

3. よって、既に作成されてしまったスレッド= コネクションに対しては影響を持たない

4. スレッドを再作成するため、tomcatを再起動する必要がある

5. tomcat再起動する(or してもらう)のがめんどい


## 考えたこと

pt-kill を使って、`pt-kill S=/usr/mysql/5.7.9/data/mysql.sock,u=root --idle-time=1 --victims=oldest --wait-after-kill=30s --kill --print --match-command=Sleep` とかやれば古いやつから順番にゆっくり切って再接続をアプリケーションに任せられるかなと思ったけど

  * pt-killを開始した時間以降に接続してきたスレッドは除外対象にしないといけない

    * pt-killを開始した時間以前のスレッドが全滅したら自然に止まってほしい

  * pt-killではクエリーレベルまでしか見てくれないので、トランザクションが走ってるかどうかまでは検知してくれない

    * 迂闊にkillして大量ロールバックされても面倒


## というわけで

* `SELECT MAX(id) FROM information_schema.processlist`で、「開始時点より古いプロセスIDの最大値」を取る

  * プロセスIDは単調増加なので、これよりも大きいプロセスIDを持つスレッドはkillしなくていい

* `SELECT * FROM processlist LEFT JOIN innodb_trx ON processlist.id = innodb_trx.trx_mysql_thread_id WHERE id <= $maxid AND command = 'Sleep' AND time > 3 AND trx_id IS NULL ORDER BY processlist.id LIMIT 1` でスリープしててトランザクション中じゃないいちばん古いプロセスを引いてkill

  * time > 3にしてるのは、0だとMyISAMな複数ステートメント処理(似非トランザクション)のスキマに挟まるかもとか思った

    * いやどんな条件を付けようと、トランザクション非対応な複数ステートメント処理は救えないんだけど一応。。

  * SELECTからkillまでの100ミリ秒くらいの間に開始されたトランザクションはあきらめる(ロールバックが暴走することはないはず)

    * アプリケーションがエラーハンドルしてくれるのが大前提

* ちょっとスリープする

* `SELECT MIN(id) FROM information_schema.processlist WHERE id <= $maxid`がNULLになるまでこれを繰り返す

* なんてことをprogress出しながらやる


どうだろう。
監視のための永続コネクションも検知されたので、user, hostでフィルターはかけるとしてこれじゃダメかしら(そこまでしてtomcatを再起動しちゃダメな理由も見当たらないが)

0 件のコメント :

コメントを投稿