負荷ツールを利用して「socket: Too many open files」のエラーが出た場合の解決方法

技術

はじめに

こんにちは!さいけです。

今回は、「負荷ツールを利用して「socket: Too many open files」のエラーが出た場合の解決方法」について紹介します。

備忘録的な記事になります。

負荷ツールを利用して「socket: Too many open files」のエラーが出た場合の解決方法

結論から言うと、ファイルディスクリプタの上限を変更すると「socket: Too many open files」のエラーを解決することができます。

ファイルディスクリプタ?という方のためにわかりやすい解説記事があるので貼っておきます。mm

Error 403 (Forbidden)|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
403エラーページです。用語の意味を「ざっくりと」理解するためのIT用語辞典です。

このエラーは、負荷(同時リクエスト)をかけたことによって、プロセスが開けるファイルディスクリプタが上限に達してしまったために発生するエラーです。

なので、このエラーは負荷ツール(abコマンド、vegata等)で同時リクエスト数を増加させた場合によく発生するようです。

では、次に解決方法であるファイルディスクリプタの上限変更方法をについて解説していきます。

ファイルディスクリプタの上限変更方法

今回は2つの方法を紹介します。

  • 暫定的にファイルディスクリプタを変更する
  • 恒久的にファイルディスクリプタを変更する

暫定的にファイルディスクリプタを変更する

以下のコマンドで暫定的にファイルディスクリプタ数を変更することができます。

$ ulimit -n <設定値>

実際にファイルディスクリプタの設定値を変更してみます。

$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-v: address space (kbytes)          unlimited
-l: locked-in-memory size (kbytes)  unlimited
-u: processes                       2784
-n: file descriptors                256

$ ulimit -n 1024
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-v: address space (kbytes)          unlimited
-l: locked-in-memory size (kbytes)  unlimited
-u: processes                       2784
-n: file descriptors                1024

ファイルディスクリプタが256から1024に変更されました!

恒久的にファイルディスクリプタを変更する

恒久的にファイルディスクリプタを変更するには、設定ファイルを作成します。

touchコマンドで/Library/LaunchDaemons/ に limit.maxfiles.plistを作成します。

$ touch /Library/LaunchDaemons/limit.maxfiles.plist

limit.maxfiles.plistファイルに、以下のようなxmlを追加します。

1024となっている箇所がファイルディスクリプタの設定値です。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>limit.maxfiles</string>
    <key>ProgramArguments</key>
    <array>
      <string>launchctl</string>
      <string>limit</string>
      <string>maxfiles</string>
      <string>1024</string>
      <string>1024</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceIPC</key>
    <false/>
  </dict>
</plist>

ファイルを作成すれば、恒久的に設定されるようになります。

Macを再起動してみて反映されているか確認してみてください。

再起動後、以下のコマンドを実行して、ファイルディスクリプタが変更されていればOKです!

$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-v: address space (kbytes)          unlimited
-l: locked-in-memory size (kbytes)  unlimited
-u: processes                       2784
-n: file descriptors                1024

検証

ここでは、実際にファイルディスクリプタの上限を変更したら、「socket: Too many open files」のエラーが解決されるのか検証します。

検証方法はローカルのアプリケーションに同時リクエスト300のabコマンドを発行して検証します。

まず、ファイルディスクリプタは256に設定してエラーが再現するか検証します。

$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-v: address space (kbytes)          unlimited
-l: locked-in-memory size (kbytes)  unlimited
-u: processes                       2784
-n: file descriptors                256

以下のabコマンドで同時リクエスト300を発行してみます。

$ ab -c 300 -n 300 http://localhost:8080/person
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
socket: Too many open files (24)

socket: Too many open files (24)が出ました。

では、以下の通り、ファイルディスクリプタの設定値を512に変更します。

$ ulimit -n 512
$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-v: address space (kbytes)          unlimited
-l: locked-in-memory size (kbytes)  unlimited
-u: processes                       2784
-n: file descriptors                512

再度、同時リクエスト300のabコマンドを発行します。

$ ab -c 300 -n 300 http://localhost:8080/person
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Finished 300 requests


Server Software:
Server Hostname:        localhost
Server Port:            8080

Document Path:          /person1
Document Length:        47 bytes

Concurrency Level:      300
Time taken for tests:   0.032 seconds
Complete requests:      300
Failed requests:        0
Total transferred:      49800 bytes
HTML transferred:       14100 bytes
Requests per second:    9439.31 [#/sec] (mean)
Time per request:       31.782 [ms] (mean)
Time per request:       0.106 [ms] (mean, across all concurrent requests)
Transfer rate:          1530.20 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    9   1.4      9      11
Processing:     5   10   2.8     10      17
Waiting:        1   10   2.9     10      17
Total:         12   19   2.5     19      27

Percentage of the requests served within a certain time (ms)
  50%     19
  66%     20
  75%     21
  80%     21
  90%     22
  95%     23
  98%     24
  99%     25
 100%     27 (longest request)

変更したところ、エラーが解決されabコマンドが正常に実行できました!

👍🎉

おわりに

今回は、「負荷ツールを利用して「socket: Too many open files」のエラーが出た場合の解決方法」について紹介しました。

負荷ツールを利用して負荷テストを実施する際は、ファイルディスクリプタの上限に引っかかってしまう罠が結構あると思うので、本記事が参考になれば幸いです。

ファイルディスクリプタには気をつけて\(^o^)/

コメント

タイトルとURLをコピーしました