production.log

ピクスタ株式会社で開発部の部長をやっている星直史のブログです。

Apache Bench(abコマンド)をmacOSで実行した場合に出るエラー「socket: Too many open files (24)」の回避方法

概要

AWS ELBの暖気申請(Pre-Warming)をしたかったのですが、サポートのプランがBusiness以上でなければ申請できないため、自前でPre-Warmingをする必要がありました。 AWS ELBは負荷が上がった場合に、AutoScaleするLBです。
通常、事前に大量のトラフィックが予想できる場合は、WebサーバーとDBはスケールアップ/アウトできるのですが、その前段のLBが捌き切れないことが多々有ります。 マネージドサービスの場合、スケールするまで、数分~数十分要する為、機会損失が多くなってしまいます。

そこで、ELBの特性を考えて、自前に意図的に暖気(AutoScaleさせる)ことにしました。 負荷テストなどでよく使われるApache Benchを使おうとしたのですが、やっている途中でエラーが発生してしまったので、その備忘録としてApache Bench(abコマンド)をmacOSで実行した場合に出るエラー「socket: Too many open files (24)」の回避方法について書きます。

遭遇したエラー

Apache Benchの使用方法は下記の通りです。

ab -n [総リクエスト数] -c [同時リクエスト数] [URL]

[同時リクエスト]で指定した数値で[URL]に対してリクエストを行います。 リクエスト数が[総リクエスト数]に達したら終了です。

負荷をかけたいので、同時リクエスト数を増やすことになると思いますが、この数値を大きくした場合にsocket: Too many open files (24)というエラーが発生します。

原因

socket: Too many open files (24)は、プロセスが開けるファイルディスクリプタの上限に達してしまうと発生するエラーです。 そのため、この上限を変更する必要があります。

上限の確認は下記コマンドで確認ができます。

$ ulimit -n
 256

ulimitは使用できるリソースを制限するコマンドです。ファイルの最大サイズ、使用可能メモリ、同時実行プロセス数などを確認&制限できます。 -nオプションは、同時に開けるファイル数です。

回避方法

回避方法は2つあります。

一時的に設定を変更する

先述したulimitコマンドで設定を変更します。

$ ulimit -n
256
$ ulimit -n 1024
$ ulimit -n
1024

この変更はターミナルを閉じてしまうと既定値に戻ります。 そのため、ulimitを使用する場合は、変更した直後(ターミナルのプロセスを閉じないうち)にApache Benchを実行する必要があります。

恒久的に設定を変更する

恒久的に設定を変更したい場合はlaunchctlコマンドを使用します。 このコマンドはmacOSで使用できるコマンドで、macOSのプロセスを管理するためのコマンドです。

現状を確認するには下記コマンドを実行します。

$ sudo launchctl limit
    cpu         unlimited      unlimited      
    filesize    unlimited      unlimited      
    data        unlimited      unlimited      
    stack       8388608        67104768       
    core        0              unlimited      
    rss         unlimited      unlimited      
    memlock     unlimited      unlimited      
    maxproc     2837           4256           
    maxfiles    256         256 

この結果の「maxfiles」が今回のエラーの原因にあたります。

これを変更するために、設定ファイルを用意します。 最初は用意されていないはずなので、新規作成します。

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

次に、作成したファイルに設定を書き込みます。

<?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>  

最後に、設定を反映させるためのコマンドを実行します。

$ sudo launchctl load -w /Library/LaunchDaemons/limit.maxfiles.plist
$ sudo launchctl limit
    cpu         unlimited      unlimited      
    filesize    unlimited      unlimited      
    data        unlimited      unlimited      
    stack       8388608        67104768       
    core        0              unlimited      
    rss         unlimited      unlimited      
    memlock     unlimited      unlimited      
    maxproc     2837           4256           
    maxfiles    1024         1024

バッチリですね。

まとめ

やんごとなき理由で、AWS ELBの暖気申請ができない方は自前でPre-Warmingを行うこともできます。 その場合、負荷テスト用のコマンド(今回はApache Benchを紹介)を使用することになりますが、macOSでは同時に開くファイル数の上限に達してしまうエラーで阻まれてしまいます。 これを回避する方法は2通りあります。

  1. ulimitコマンドで一時的に上限設定する
  2. launchctlコマンドで恒久的に上限設定する