2015年10月2日金曜日

MySQL 4.0からあるMAX_QUERIES_PER_HOURという機能について

MySQL CasualのSlack でふと まえあつさん が発した一言から、気になったので調べてみました。意外と知られてないんですね。

MAX_QUERIES_PER_HOUR count、MAX_UPDATES_PER_HOUR count、および MAX_CONNECTIONS_PER_HOUR count 制限は、いずれかの特定の 1 時間の間にこのアカウントに対して許可されるサーバーへのクエリー、更新、および接続の数を制限します。(結果がクエリーキャッシュから得られたクエリーは、MAX_QUERIES_PER_HOUR 制限に対してカウントされません。) count が 0 (デフォルト) である場合、これは、このアカウントに対する制限が存在しないことを示します。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.7.1.4 GRANT 構文


5.6まではGRANTステートメントで指定する。ユーザー固有の属性(mysql.userにカラムがある)なので、グローバル権限(GRANT .. ON *.*)でしかつけられない。

mysql56> SHOW GRANTS;
+-------------------------------------------------------------------+
| Grants for yoku0825@%                                             |
+-------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'yoku0825'@'%' WITH MAX_QUERIES_PER_HOUR 10 |
| GRANT ALL PRIVILEGES ON `d1`.* TO 'yoku0825'@'%'                  |
+-------------------------------------------------------------------+
2 rows in set (0.00 sec)


で、こうなる。mysqlコマンドラインクライアントは接続する時に内部的に`SELECT @@version;`を投げているので、1コネクションに対して2クエリー、5回接続してクエリーを投げたら終了(てことは、O/Rマッパー使ってる環境でこれやるともっと少なくなるだろうなあ。。)

$ while true ; do mysql56 -uyoku0825 -e "SELECT 1" d1 || break; done
+---+
| 1 |
+---+
| 1 |
+---+
+---+
| 1 |
+---+
| 1 |
+---+
+---+
| 1 |
+---+
| 1 |
+---+
+---+
| 1 |
+---+
| 1 |
+---+
+---+
| 1 |
+---+
| 1 |
+---+
ERROR 1226 (42000) at line 1: User 'yoku0825' has exceeded the 'max_questions' resource (current value: 10)

いくつかメモ。

* この制約はアカウント単位(user@host)でかかるので、yoku0825@%とyoku0825@localhostは別人でカウントされるのにエラーメッセージには`User 'yoku0825'`としか出てくれない。
* `FLUSH PRIVILEGES`ステートメントでクリアできる。
* GRANTステートメント上はMAX_QUERIES_PER_HOURなににエラーメッセージには'max_questions'ってかかれてて、GRANTにmax_quiestions_per_hourって書いてアレーってなった。
* ↑に書いた通り、接続時に内部的に暗黙のクエリーを投げてることが多い(接続元の実装依存)ので、綺麗に計れないかも知れない


判定のロジックはcheck_mqhにあって、
mysql-server/sql_connect.cc at 253084f78a60816ce19430cff00f861c520830c5 · mysql/mysql-server

check_mqhを呼んでいるのはmysql_parse(MySQLコマンドパケットのパース)
mysql-server/sql_parse.cc at 253084f78a60816ce19430cff00f861c520830c5 · mysql/mysql-server

check_mqhの中でtime_out_user_resource_limitsを呼んでいて、コイツはreset_utimeと現在時刻を比較して、3600秒経っていたら、カウンターをクリアして、reset_utimeに新しく現在時刻を指定する。
mysql-server/sql_class.cc at 253084f78a60816ce19430cff00f861c520830c5 · mysql/mysql-servertime_out_user_resource_limits

という訳で、一律00分にクリアーみたいなものではない。あんまり使い方思いつかないけど、調べてるのは楽しかった。ごちそうさまでした。

0 件のコメント :

コメントを投稿