環境
- MySQL 8.0
発端
journalctl -u mysqld でログを眺めていたら、以下の警告が繰り返し出ているのに気づいた。
[Warning] Could not increase number of max_open_files to more than 65536 (request: 100005) [Warning] Could not increase number of max_open_files to more than 65536 (request: 100005)
「65536以上に引き上げられなかった」という警告で、放置するとアクセス増加時に Too many open files エラーが発生してMySQLが停止するリスクがある。
65536の数値は自分が設定したもので、デフォルトの1024だと少なすぎるのでsystemdの設定を変更してMySQLのLimitNOFILEを65536に指定していた。
[Service] LimitNOFILE=65536
また my.cnf でも65535を指定していた。
max_allowed_packet=64MB open_files_limit=65535 key_cache_segments=32
65536でも足りないのか。。?あと100005という中途半端な値を要求している点はなんだ?
解決策
原因はMySQLとsystemdの設定値の乖離である。
MySQLが 100005 のファイルディスクリプタを必要としているのに対し、systemdの LimitNOFILE のデフォルト上限が 65536 に制限されているため、要求が通らずに警告となっている。
systemd 側の制限を引き上げれば解消できる。
systemctl edit mysqld
オーバーライド用のファイルが開くので、以下を追記して保存する。
[Service] LimitNOFILE=100005
保存後、設定を反映させる。
systemctl daemon-reload systemctl restart mysqld
再起動後に journalctl -u mysqld を確認して警告が出なくなっていれば完了だ。
ソースは?
my.cnf に open_files_limit=65535 と書いているのに、なぜMySQLは request: 100005 という値を要求したのか。
MySQLは open_files_limit の設定値をそのまま使うわけではない。起動時に以下の計算を行い、最大の値をOSに要求する仕様になっている。
10 + max_connections + (table_open_cache × 2)max_connections × 5- OSの制限値(正の値の場合)
- 起動時に
open_files_limitの指定がない場合は 5000
これはMySQL 8.4の公式リファレンスマニュアルの open_files_limit の項目に明記されている。
The effective open_files_limit value is based on the value specified at system startup (if any) and the values of max_connections and table_open_cache, using these formulas:
- 10 + max_connections + (table_open_cache * 2)
- max_connections * 5
- operating system limit (if positive)
- if operating system limit is infinity: open_files_limit value specified at startup, 5000 if none
The server attempts to obtain the number of file descriptors using the maximum of those four values.
今回の 100005 という値も、max_connections が 20000 前後に設定されていたとすれば 20000 × 5 = 100000 となり、内部的なオーバーヘッドを加えて 100005 が算出される。つまり my.cnf の open_files_limit 設定が計算結果を下回ったため、MySQLが自動的に大きい方の値をOSに要求したわけだ。