MySQL の max_connections, table_open_cache, open_files_limit の関係

昔書いた記事を久々に見てみたら何書いてあるかさっぱりわからなかったので、最新情報で書き直してみます。

tmtms.hatenablog.com

以下は MySQL 5.6, 5.7 について書かれています。

MySQL の max_connectoins, table_open_cache, open_files_limit パラメータは相互に依存して動的に値が設定されます。

パラメータ名 デフォルト値 最小値 最大値
max_connections 151 1 100000
table_open_cache 2000 1 524288
open_files_limit 5000 0 4G

わからないと言われたので追記。

my.cnfやコマンドラインオプション等で設定された値(またはデフォルト値)を初期値として、open_files_limit → max_connections → table_open_cache の順に値が決定します。

open_files_limit

open_files_limit は次の計算結果の最大の値になります。

  1. 10 + max_connections + table_open_cache * 2
  2. max_connections * 5
  3. open_files_limit に指定された値(未指定時は 5000)
  4. 現在の getrlimit(2) の RLIMIT_NOFILE の値 (ulimit -n の値)

ただし、setrlimit(2) で RLIMIT_NOFILE にこの値を設定できない場合(おそらく root で起動されなかった場合)、open_files_limit は現在の RLIMIT_NOFILE の値になり、次の警告メッセージを出力します。

open_files_limit が未指定の場合:

Changed limits: max_open_files: XXX (requested YYY)

open_files_limit に値が設定されていた場合:

Could not increase number of max_open_files to more than XXX (request: YYY)

max_connections

max_connections が open_files_limit - 810 よりも大きい場合は、open_files_limit -810 の値になります。

table_open_cache

(open_files_limit - 10 - max_connections) / 2 (この値が 400 よりも小さい場合は 400) よりも table_open_cache が大きい場合、次の警告メッセージを出力して、table_open_cache がその値に変更されます。

Changed limits: table_open_cache: XXX (requested YYY)

open_files_limit = 100 を指定した場合、open_files_limit は 10 + max_connections + table_open_cache * 2 が採用されて 4161 になります。

ulimit -n が 1024 である一般ユーザーでは、setrlimit(2) で RLIMIT_NOFILE を増加させることはできないので、open_files_limit は 1024 になり、table_open_cache が 431 になります。次の警告メッセージが出力されます。

[Warning] Changed limits: max_open_files: 1024 (requested 5000)
[Warning] Changed limits: table_open_cache: 431 (requested 2000)

この状況では max_connections も指定した値にならないことがあります。

max_connections=1000 を指定した場合、max_connections=214, table_open_cache=400 になります。

max_connections = open_files_limit(1024)-810 = 214
table_open_cache = (open_files_limit(1024)-10-max_connections(214))/2 = 400

Ubuntuの罠

Ubuntu で mysql-server をインストールすると my.cnf で max_connections を設定しても指定した値になりません。

/etc/mysql/my.cnfmax-connections = 1024 と記述して起動した mysql では次のようになります。

mysql> select * from performance_schema.global_variables where variable_name in ('max_connections','table_open_cache','open_files_limit');
+------------------+----------------+
| VARIABLE_NAME    | VARIABLE_VALUE |
+------------------+----------------+
| max_connections  | 214            |
| open_files_limit | 1024           |
| table_open_cache | 400            |
+------------------+----------------+

これは mysqld が root ではなく mysql ユーザーで起動されるようになっているためです。

/lib/systemd/system/mysql.service

[Service]
User=mysql
Group=mysql
PermissionsStartOnly=true
ExecStartPre=/usr/share/mysql/mysql-systemd-start pre
ExecStart=/usr/sbin/mysqld
ExecStartPost=/usr/share/mysql/mysql-systemd-start post

なんでこんな設定になっているのかわかりませんが、root で起動するようにすれば普通に設定されるようになります。 RuntimeDirectoryMode=1777 を設定しているのは、/var/run/mysqld/ が root の 755 で作られると、mysqld が pid や socket ファイルを作成できないためです。

# systemctl edit mysql
[Service]
User=root
Group=root
RuntimeDirectoryMode=1777
# systemctl restart mysql
mysql> select * from performance_schema.global_variables where variable_name in ('max_connections','table_open_cache','open_files_limit');
+------------------+----------------+
| VARIABLE_NAME    | VARIABLE_VALUE |
+------------------+----------------+
| max_connections  | 1024           |
| open_files_limit | 5120           |
| table_open_cache | 2000           |
+------------------+----------------+

追記

はてブで指摘されましたが、どうやら systemd は LimitNOFILE で最大ファイルディスクリプタ数を設定できるようです。

User=root にしなくても、LimitNOFILE で適切な値を設定すればいいみたいです。

# systemctl edit mysql
[Service]
LimitNOFILE=65535
mysql> select * from performance_schema.global_variables where variable_name in ('max_connections','table_open_cache','open_files_limit');
+------------------+----------------+
| VARIABLE_NAME    | VARIABLE_VALUE |
+------------------+----------------+
| max_connections  | 1024           |
| open_files_limit | 65535          |
| table_open_cache | 2000           |
+------------------+----------------+