CentOS7(systemctl環境)でMySQL RouterのMax oplen filesの上限を引き上げる
もともと年末年始休暇で暇な時間をつぶすために始めたブログですが、さすがに更新頻度が低いですね。
さて、先週MySQL8.0.19がGAとなりましたね:)
一番注目すべき新機能は何なんでしょうかね…
InnoDB Replica Setはちょっと触ってみたので今度記事にしてみます。
さて今回はMySQL8.0.19とは全く関係のない単発ネタです。
やりたかったこと
rpmでインストールしたmysqlrouterをmysqlrouterユーザで起動しなおかつMax open filesの上限を引き上げたい
環境はVM上のCentOS7.6です。
TL;DR
- mysqlrouterは接続ごとにソケットファイルを生成する
- デフォルトではmysqlrouterは一般ユーザ(mysqlrouter)で起動されるため
Max open files
の上限が低い - 接続数が多い環境だとすぐに
Too many open files
が発生してしまう - mysqlrouter.serviceの[Service]に
LimitNOFILE=設定したい上限値
と記述することで上限を引き上げることが可能
インストール
まずはmysqlrouterのインストールから
このサーバではすでにmysqlrouter(8.0.18)が存在していたので、正確にはUpgradeです。
[root@instance2:/usr/src]$ ll 合計 797728 drwxr-xr-x. 2 root root 6 4月 11 2018 debug drwxr-xr-x. 2 root root 6 4月 11 2018 kernels -rw-r--r--. 1 root root 765306880 12月 10 22:04 mysql-8.0.19-1.el7.x86_64.rpm-bundle.tar -rw-r--r--. 1 root root 22840048 1月 16 17:52 mysql-router-community-8.0.19-1.el7.x86_64.rpm -rw-r--r--. 1 root root 28714372 12月 17 10:25 mysql-shell-8.0.19-1.el7.x86_64.rpm drwxr-xr-x. 2 root root 4096 1月 14 11:17 tmp [root@instance2:/usr/src]$ [root@instance2:/usr/src]$ [root@instance2:/usr/src]$ rpm -Uvh mysql-router-community-8.0.19-1.el7.x86_64.rpm 準備しています... ################################# [100%] 更新中 / インストール中... 1:mysql-router-community-8.0.19-1.e################################# [ 50%] 整理中 / 削除中... 2:mysql-router-community-8.0
bootstrapしてconfなどを自動生成します。
[root@instance2:/usr/src]$ mysqlrouter --bootstrap=instance1:3306 --user=mysqlrouter Please enter MySQL password for root: # Bootstrapping system MySQL Router instance... - Creating account(s) (only those that are needed, if any) - Verifying account (using it to run SQL queries that would be run by Router) - Storing account in keyring - Adjusting permissions of generated files - Creating configuration /etc/mysqlrouter/mysqlrouter.conf Existing configuration backed up to '/etc/mysqlrouter/mysqlrouter.conf.bak' # MySQL Router configured for the InnoDB ReplicaSet 'example' After this MySQL Router has been started with the generated configuration $ /etc/init.d/mysqlrouter restart or $ systemctl start mysqlrouter or $ mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf the cluster 'example' can be reached by connecting to: ## MySQL Classic protocol - Read/Write Connections: localhost:6446 - Read/Only Connections: localhost:6447 ## MySQL X protocol - Read/Write Connections: localhost:64460 - Read/Only Connections: localhost:64470
mysqlrouterユーザーで起動しているためデフォルトだとMax open filesが1024と低い状態で起動されてしまいます。
[root@instance2:/usr/src]$ systemctl start mysqlrouter [root@instance2:/usr/src]$ systemctl status mysqlrouter ● mysqlrouter.service - MySQL Router Loaded: loaded (/usr/lib/systemd/system/mysqlrouter.service; disabled; vendor preset: disabled) Active: active (running) since 木 2020-01-16 17:54:23 JST; 3s ago Main PID: 14653 (main) Tasks: 9 CGroup: /system.slice/mysqlrouter.service └─14653 /usr/bin/mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf 1月 16 17:54:23 instance2 systemd[1]: Started MySQL Router. 1月 16 17:54:24 instance2 mysqlrouter[14653]: logging facility initialized, switching logging to loggers specified in configuration [root@instance2:/usr/src]$ cat /proc/$(pidof mysqlrouter)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 15027 15027 processes Max open files 1024 4096 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 15027 15027 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
Max open filesの上限を引き上げる理由
そもそもなぜMax open files
の上限を引き上げたかったというと、mysqlrouterはそれ経由の接続が発生すると
接続ごとに通信のためのソケットファイルを用意するので、MySQLへの接続数が多い環境ではMax open files
が低いとmysqlrouter経由での接続ができなくなってしまうからです。
例をお見せします。
簡単にするためにMax open filesのLimitを16に変更します。
[root@instance2:/var/log/mysqlrouter]$ cat /proc/$(pidof mysqlrouter)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 15027 15027 processes Max open files 16 16 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 15027 15027 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us [root@instance2:/var/log/mysqlrouter]$
mysqlrouter経由での接続が無い状態を確認します。
[root@instance2:~]$ ps -ef | grep mysqlroute[r] mysqlro+ 13935 1 9 09:46 ? 00:09:08 /usr/bin/mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf [root@instance2:~]$ lsof -i:6446 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME main 13935 mysqlrouter 6u IPv4 47585 0t0 TCP *:mysql-proxy (LISTEN) [root@instance2:~]$ ll /proc/$(pidof mysqlrouter)/fd 合計 0 lr-x------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 0 -> /dev/null lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 1 -> socket:[47561] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 2 -> socket:[47561] l-wx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 3 -> /var/log/mysqlrouter/mysqlrouter.log lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 4 -> socket:[92764] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 5 -> socket:[47580] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 6 -> socket:[47585] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 7 -> socket:[47610] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 8 -> socket:[47611]
デフォルトで9つのソケットファイルが作られていることがわかります。(その内1つは/dev/null用、もう1つはログ出力用のようですね)
続いてmysqlrouter経由でMySQLサーバに接続した状態を確認します。
[root@instance2:~]$ mysql -uroot -h127.0.0.1 -P6446 & [1] 15265 [root@instance2:~]$ Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 221388 Server version: 8.0.19 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. [1]+ 停止 mysql -uroot -h127.0.0.1 -P6446 [root@instance2:~]$ lsof -i:6446 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME main 13935 mysqlrouter 6u IPv4 47585 0t0 TCP *:mysql-proxy (LISTEN) main 13935 mysqlrouter 9u IPv4 94305 0t0 TCP localhost:mysql-proxy->localhost:54458 (ESTABLISHED) mysql 15265 root 3u IPv4 94304 0t0 TCP localhost:54458->localhost:mysql-proxy (ESTABLISHED) [root@instance2:~]$ ll /proc/$(pidof mysqlrouter)/fd 合計 0 lr-x------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 0 -> /dev/null lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 1 -> socket:[47561] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 10 -> socket:[94306] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 2 -> socket:[47561] l-wx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 3 -> /var/log/mysqlrouter/mysqlrouter.log lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 4 -> socket:[94779] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 5 -> socket:[47580] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 6 -> socket:[47585] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 7 -> socket:[47610] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 8 -> socket:[47611] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 9 -> socket:[94305]
9,10という名前のソケットファイルが増えていることがわかると思います。
ということは1つの接続で2つのソケットファイルが作られるということでしょうか。
同じ要領で接続数を増やしてみます。
counter=1 while true do echo "$counter 番目の接続" mysql -uroot -h127.0.0.1 -P6446 2>&1 >/dev/null & pid=$(echo "$!") wait $pid >/dev/null if [ $? -eq 1 ];then echo "接続に失敗しました。" break fi echo "接続に成功しました。" counter=$((counter + 1)) done
上記のようなスクリプトで何番目の接続で失敗するか確認してみます。
下記が実行結果です。(不要な箇所は割愛)
1 番目の接続 接続に成功しました。 2 番目の接続 接続に成功しました。 3 番目の接続 接続に成功しました。 4 番目の接続 接続に失敗しました。
4番目の接続で接続に失敗してしまったことが分かりました。
念のためmysqlrouterを経由しない接続は成功することを確認します。
[root@instance2:~]$ mysql -uroot -h instance1 -e "SELECT 'direct'" ; mysql -uroot -h 127.0.0.1 -P6446 -e "SELECT 'rooter'" +--------+ | direct | +--------+ | direct | +--------+ ERROR 2003 (HY000): Can't connect to remote MySQL server for client connected to '0.0.0.0:6446'
この時の状態を確認してみます。
[root@instance2:~]$ lsof -i:6446 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME main 13935 mysqlrouter 6u IPv4 47585 0t0 TCP *:mysql-proxy (LISTEN) main 13935 mysqlrouter 9u IPv4 109395 0t0 TCP localhost:mysql-proxy->localhost:39054 (ESTABLISHED) main 13935 mysqlrouter 11u IPv4 109405 0t0 TCP localhost:mysql-proxy->localhost:39058 (ESTABLISHED) main 13935 mysqlrouter 13u IPv4 109416 0t0 TCP localhost:mysql-proxy->localhost:39064 (ESTABLISHED) mysql 15793 root 3u IPv4 109394 0t0 TCP localhost:39054->localhost:mysql-proxy (ESTABLISHED) mysql 15796 root 3u IPv4 109404 0t0 TCP localhost:39058->localhost:mysql-proxy (ESTABLISHED) mysql 15799 root 3u IPv4 109415 0t0 TCP localhost:39064->localhost:mysql-proxy (ESTABLISHED) [root@instance2:~]$ ll /proc/$(pidof mysqlrouter)/fd 合計 0 lr-x------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 0 -> /dev/null lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 1 -> socket:[47561] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 10 -> socket:[109396] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 11 -> socket:[109405] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 12 -> socket:[109406] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 13 -> socket:[109416] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 14 -> socket:[109417] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 2 -> socket:[47561] l-wx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 3 -> /var/log/mysqlrouter/mysqlrouter.log lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 4 -> socket:[113849] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 5 -> socket:[47580] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 6 -> socket:[47585] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 7 -> socket:[47610] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 8 -> socket:[47611] lrwx------. 1 mysqlrouter mysqlrouter 64 1月 17 09:46 9 -> socket:[109395]
ソケットファイルの最大数は15ですね。
今Max open files
の上限が16なので、4本目の接続を作ろうとすると15+2=17で上限を超えてしまうということで接続に失敗してしまったと思われます。
mysqlrouterのログも確認してみましょう。
2020-01-17 12:25:46 routing ERROR [7fdfc2486700] [routing:example_rw] Failed accepting connection: Too many open files 2020-01-17 12:25:46 routing ERROR [7fdfc2486700] [routing:example_rw] Failed accepting connection: Too many open files 2020-01-17 12:25:46 routing ERROR [7fdfc2486700] [routing:example_rw] Failed accepting connection: Too many open files 2020-01-17 12:25:46 routing ERROR [7fdfc2486700] [routing:example_rw] Failed accepting connection: Too many open files 2020-01-17 12:25:46 routing WARNING [7fdfc017f700] [routing:example_rw] fd=15 Can't connect to remote MySQL server for client connected to '0.0.0.0:6446' 2020-01-17 12:25:46 routing WARNING [7fdfc017f700] [routing:example_rw] fd=15 Can't connect to remote MySQL server for client connected to '0.0.0.0:6446'
ログからも”Too many open files”が原因でエラーとなっていることが分かりました。(Can't connectはWARNINGなのか・・・)
最後にMax open files
の上限を引き上げてみて許容される接続数が増えることを確認してみます。
[root@instance2:/var/log/mysqlrouter]$ cat /proc/$(pidof mysqlrouter)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 15027 15027 processes Max open files 32 32 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 15027 15027 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
先ほどと同じスクリプトを利用します。
下記が実行結果です。
1 番目の接続 接続に成功しました。 2 番目の接続 接続に成功しました。 3 番目の接続 接続に成功しました。 4 番目の接続 接続に成功しました。 5 番目の接続 接続に成功しました。 6 番目の接続 接続に成功しました。 7 番目の接続 接続に成功しました。 8 番目の接続 接続に成功しました。 9 番目の接続 接続に成功しました。 10 番目の接続 接続に成功しました。 11 番目の接続 接続に成功しました。 12 番目の接続 接続に失敗しました。
11番目の接続までは成功しているのでこの時のソケットファイルの数は9 + (2 * 11) = 31
この状態でもう1本接続を増やそうとすると32の上限に引っかかるため接続できない
ということでMax open files
の上限を引き上げてあげればmysqlrouter経由の接続が増えても問題ないことが分かりました。(もちろん別途でMySQLサーバ側およびMySQL Router側のmax_connections
も調整する必要はあります)
対策
さて本題ですが、mysqlrouter.serviceにLimitNOFILE=65536と追記することでこの問題を回避できます。
[root@instance2:/usr/src]$ cp /usr/lib/systemd/system/mysqlrouter.service{,.org} [root@instance2:/usr/src]$ vim /usr/lib/systemd/system/mysqlrouter.service [root@instance2:/usr/src]$ diff /usr/lib/systemd/system/mysqlrouter.service.org /usr/lib/systemd/system/mysqlrouter.service 31a32 > LimitNOFILE=655356
あとは設定変更を反映させるためにsystemctl daemon-reload
を実行して再度mysqlrouter
を起動させれば完了です。
[root@instance2:/usr/src]$ systemctl daemon-reload [root@instance2:/usr/src]$ systemctl restart mysqlrouter [root@instance2:/usr/src]$ cat /proc/$(pidof mysqlrouter)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 15027 15027 processes Max open files 655356 655356 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 15027 15027 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
無事Max open files
を引き上げることが出来ました!
Max open filesの上限はどの程度が適切か
さて上記の対応でMax open files
の上限を引き上げることができましたが、655356はちょっと高すぎですね。
ここは環境によって適切な値を設定すべきですが、どのように考えるのが適切なのでしょうか。
あくまで僕個人の考えなのですが、mysqlrouter1台に接続する台数×2+(マージン)
程度がいいのではないかと思います。
僕が担当しているサービスではmysqlrouter2台をL4の下にぶら下げてWEBサーバはL4に接続するという形をとっています。(InnoDB Cluster環境) Oracle公式ではmysqlrouterはWEBサーバにインストールするのがよいなどと書いているのですが、ちょっと理由があってそのような形はとっていません。
このような構成だとMySQLサーバ全体の接続数÷2がmysqlrouter経由で接続されることになります。そのためMySQLサーバ全体の接続数が1000だとすると、mysqlrouterのMax open files
の上限は1000+マージンで2000程度が妥当なのかなと思います。