MySQL サーバーリソースの使用を制限する方法の 1
つは、グローバルな
max_user_connections
システム変数をゼロ以外の値に設定することです。これにより、任意の特定のアカウントで実行できる同時接続の数が制限されますが、一度クライアントが接続したら、実行内容には制限が課されません。さらに、max_user_connections
を設定しても、各アカウントの管理は有効になりません。どちらのタイプの制御も、多くの
MySQL 管理者
(特に、インターネットサービスプロバイダの従業員)
にとって関心のあるものです。
MySQL 5.6 では、各アカウントに対して次のサーバーリソースの使用を制限できます。
アカウントが 1 時間ごとに発行できるクエリーの数
アカウントが 1 時間ごとに発行できる更新の数
アカウントが 1 時間ごとにサーバーに接続できる回数
アカウントによるサーバーへの同時接続の数
クエリー制限に対して、クライアントが発行できるステートメントがすべてカウントされます (その結果がクエリーキャッシュから提供される場合は除きます)。更新制限に対して、データベースまたはテーブルを変更するステートメントのみがカウントされます。
このコンテキストでは、「アカウント」は
mysql.user
テーブル内の行に対応しています。つまり、接続に適用される
user
テーブル行内の
User
および Host
値に対して、接続が評価されます。たとえば、アカウント
'usera'@'%.example.com'
は、example.com
ドメイン内の任意のホストから接続することを
usera
に許可するために、usera
および
%.example.com
の User
および Host
値を持つ
user
テーブル内の行に対応しています。この場合、このような接続ではすべて同じアカウントが使用されるため、サーバーは、usera
による example.com
ドメイン内の任意のホストからのすべての接続に、この行のリソース制限をまとめて適用します。
MySQL 5.0.3
よりも前では、ユーザーの接続元である実際のホストに対して、「アカウント」が評価されていました。--old-style-user-limits
オプションを付けてサーバーを起動すれば、この古いアカウント方式を選択できます。この場合、usera
が host1.example.com
と
host2.example.com
から同時に接続すると、サーバーは各接続に個別にアカウントリソースの制限を適用します。usera
が host1.example.com
から再度接続すると、サーバーはそのホストからの既存の接続とともに、その接続に対する制限を適用します。
アカウントに対してリソース制限を設定するには、GRANT
ステートメントを使用します
(セクション13.7.1.4「GRANT 構文」を参照してください)。制限される各リソースの名前を指定する
WITH
句を指定します。各制限のデフォルト値は、ゼロ
(制限なし)
です。たとえば、制限された方法でのみ
customer
データベースにアクセスできる新しいアカウントを作成するには、次のようなステートメントを発行します。
mysql> CREATE USER 'francis'@'localhost' IDENTIFIED BY 'frank';
mysql> GRANT ALL ON customer.* TO 'francis'@'localhost'
-> WITH MAX_QUERIES_PER_HOUR 20
-> MAX_UPDATES_PER_HOUR 10
-> MAX_CONNECTIONS_PER_HOUR 5
-> MAX_USER_CONNECTIONS 2;
制限タイプの名前をすべて WITH
句に指定する必要はありませんが、名前を指定したものは任意の順序で表示できます。1
時間ごとの各制限の値は、1
時間当たりの回数を表す整数にするようにしてください。MAX_USER_CONNECTIONS
では、制限はアカウントによる同時接続の最大数を表す整数です。この制限がゼロに設定されている場合は、グローバルな
max_user_connections
システム変数の値によって同時接続の数が決定されます。max_user_connections
もゼロである場合は、アカウントに制限がありません。
アカウントに対する既存の制約を変更するには、グローバルレベル
(ON *.*
) で
GRANT USAGE
ステートメントを使用します。次のステートメントは、francis
に対するクエリー制限を 100 に変更します。
mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
-> WITH MAX_QUERIES_PER_HOUR 100;
このステートメントは、指定された制限値のみを変更し、それ以外のアカウントは未変更のままにします。
制限を削除するには、その値をゼロに設定します。たとえば、francis
が接続できる 1
時間当たりの回数に対する制限を削除するには、次のステートメントを使用します。
mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
-> WITH MAX_CONNECTIONS_PER_HOUR 0;
すでに説明したように、アカウントに対する同時接続の制限は、MAX_USER_CONNECTIONS
制限および
max_user_connections
システム変数によって決定されます。グローバルな
max_user_connections
値が 10
であり、3 つのアカウントが
GRANT
を使用して指定されたリソース制限を持っていると仮定します。
GRANT ... TO 'user1'@'localhost' WITH MAX_USER_CONNECTIONS 0;
GRANT ... TO 'user2'@'localhost' WITH MAX_USER_CONNECTIONS 5;
GRANT ... TO 'user3'@'localhost' WITH MAX_USER_CONNECTIONS 20;
user1
の
MAX_USER_CONNECTIONS
はゼロであるため、接続の制限は 10
(グローバルな
max_user_connections
値)
です。user2
と user3
の
MAX_USER_CONNECTIONS
はゼロ以外であるため、接続の制限はそれぞれ 5
と 20 です。
サーバーはアカウントに対応する
user
テーブル行に、アカウントに対するリソース制限を格納します。max_questions
、max_updates
、または
max_connections
カラムには、1
時間当たりの制限が格納され、max_user_connections
カラムには、MAX_USER_CONNECTIONS
の制限が格納されます。セクション6.2.2「権限システム付与テーブル」を参照してください。
任意のアカウントによるリソースのいずれかの使用に対してゼロ以外の制限が設定されている場合は、リソース使用のカウントが発生します。
サーバーが実行されると、各アカウントがリソースを使用する回数がカウントされます。過去 1 時間以内にアカウントが接続数に対する制限に達した場合は、その時間が経過するまで、そのアカウントによる以降の接続が拒否されます。同様に、アカウントがクエリーまたは更新の回数に対する制限に達した場合も、その時間が経過するまで、以降のクエリーまたは更新が拒否されます。このような場合はすべて、適切なエラーメッセージが発行されます。
リソースのカウントはクライアントごとではなく、アカウントごとに実行されます。たとえば、アカウントのクエリー制限が 50 である場合は、サーバーへの 2 つの同時クライアント接続を作成しても、制限を 100 に増加できません。両方の接続で発行されたクエリーは、まとめてカウントされます。
現在の 1 時間ごとのリソース使用のカウントは、すべてのアカウントに対してグローバルにリセットすることも、特定のアカウントごとに個別にリセットすることもできます。
すべてのアカウントに対して現在のカウントをゼロにリセットするには、
FLUSH USER_RESOURCES
ステートメント発行します。また、(たとえば、FLUSH PRIVILEGES
ステートメントまたは mysqladmin reload コマンドを使用して) 付与テーブルを再ロードして、カウントをリセットすることもできます。各アカウントの制限のいずれかを再度付与すれば、そのカウントをゼロに設定できます。これを行うには、前述のように
GRANT USAGE
を使用して、アカウントが現在持っている値と等しい制限値を指定します。
カウンタをリセットしても、MAX_USER_CONNECTIONS
の制限は影響を受けません。
サーバーが起動されると、すべてのカウントがゼロで始まります。再起動後は、カウントが繰り越されません。
MAX_USER_CONNECTIONS
の制限では、アカウントが許可されている接続の最大数を現在開いている場合に、エッジケースが発生する可能性があります。接続が発生する時点までにサーバーで切断が完全に処理されていない場合に、切断後にすぐに接続すると、エラー
(ER_TOO_MANY_USER_CONNECTIONS
または ER_USER_LIMIT_REACHED
)
が発生する可能性があります。サーバーで切断処理が終了すると、別の接続がもう一度許可されます。