ククログ

株式会社クリアコード > ククログ > macOSでファイルをたくさん開きたい!

macOSでファイルをたくさん開きたい!

macOSでファイルをたくさん開きたい阿部です。

PGroongaのCIで system call error: Too many open files というエラーが発生しました。 開いているファイルが多すぎてエラーになったようです。

このエラーを回避してCIが成功するように対応したので、その内容を紹介します。 今回はmacOSのCIで生じたエラーなので、macOSでの回避方法の紹介です。

同じエラーに遭遇した方は参考にしてください!

いきなり結論

sudo launchctl limit maxfiles unlimited unlimited

を実行すると良いです。

これで開けるファイルの上限が unlimited になります。

ulimit コマンドに馴染みがある方であれば、それのmacOS版と思ってください。)

以上で話したいことは終わったのですが、これだけだとさみしいので、 エラーが発生する原因やコマンドで何をやっているかなどをこのあと説明していきます。

エラーが発生する原因

ほとんどのOSではユーザが利用できるリソースが制限されています。 今回は開けるファイルの上限が制限されていました。

具体的にどのような設定になっているかは launchctl limit maxfiles で確認できます。 エラーになったCI環境では次の結果でした。

$ launchctl limit maxfiles
	maxfiles    256            unlimited

すでに unlimited ではないか!

なんですが、unlimitedなのは「ハードリミット」の方です。 大事なのは 256 の「ソフトリミット」の方です。

「ソフトリミット」の方が今適用されている上限値です。 ですので、今の上限は 256 なのでそれを超えてファイルを開こうとすると system call error: Too many open files エラーになります。

「ハードリミット」はシステムの上限のイメージです。 ユーザは「ハードリミット」を超える値を「ソフトリミット」に設定できません。 今回のCI環境では「ソフトリミット」を unlimited まで設定できるということです。

補足:

launchctl limit を実行すると他の値も確認できます。

$ launchctl limit
	cpu         unlimited      unlimited
	filesize    unlimited      unlimited
	data        unlimited      unlimited
	stack       8372224        67092480
	core        0              unlimited
	rss         unlimited      unlimited
	memlock     unlimited      unlimited
	maxproc     1333           2000
	maxfiles    256            unlimited

launchctl limit maxfiles unlimited unlimited は何をしているのか

sudo launchctl limit maxfiles unlimited unlimited は「ソフトリミット」と「ハードリミット」の値を unlimited に設定しています。

汎用的に表現すると sudo launchctl limit maxfiles "設定したいソフトリミットの値" "設定したいハードリミットの値" ということです。 (「ハードリミット」の値はrootでないと変更できません。)

sudo launchctl limit maxfiles unlimited unlimited を実行したあとに launchctl limit maxfiles で確認すると「ソフトリミット」が unlimited になったことが確認できます。

$ launchctl limit maxfiles
	maxfiles    unlimited      unlimited

この設定は一時的なものでサーバの再起動などで、設定がリセットされます。

補足: 永続的に設定する

このエラーに対応したプルリクエストでコメント をいただきましたが、ファイルを作成して設定することでマシンを再起動したあとも設定が適用されます。

/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>524288</string>
      <string>2048576</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceIPC</key>
    <false/>
    <key>HardResourceLimits</key>
    <dict>
      <key>NumberOfFiles</key>
      <integer>64000</integer>
    </dict>
    <key>SoftResourceLimits</key>
    <dict>
      <key>NumberOfFiles</key>
      <integer>64000</integer>
    </dict>
  </dict>
</plist>

すぐに適用したい場合は以下のコマンドを実行します。

sudo launchctl load -w /Library/LaunchDaemons/limit.maxfiles.plist

このファイルを作成するとマシンを再起動しても設定が適用されます。

補足: デーモンの場合は再起動する

今回のエラーを出力したのはPostgreSQLでした。 そのようなデーモンの場合は sudo launchctl limit maxfiles unlimited unlimited で設定を変更したあとに、 プロセスを再起動する必要があります。

補足: 気軽に実行しない

unlimited に設定しているので、環境によっては注意して設定してください。

今回はCIなので気軽に実行して設定しましたが、普段遣いのマシンだったり、サーバだったりの場合は unlimited になることで 悪影響が出る場合があります。

補足: そもそも launchctl とは?

systemdsystemctl に馴染みのある方であれば、それのmacOS版という理解で良いです。

参考: Macの「ターミナル」でのlaunchdを使ったスクリプトの管理

まとめ

macOSでは sudo launchctl limit maxfiles unlimited unlimited でファイルをたくさん開けるようになります!