systemd LimitNOFILE=

這發現很久但還是寫下來好了。查 man systemd.exec 找 LimitNOFILE= 可發現說明寫「不建議使用」,因為 systemd 本來就會忽略 limits.conf 而採用自己的設定值。在我系統上預設是 DefaultLimitNOFILE=1024:524288, 寫在 /etc/systemd/system.conf 裡面,soft limit 一樣是 1024 但 hard limit 已經提高到一般情況一定夠用了。那因為一般使用者程式就可以自行呼叫 system call setrlimit(2) 來改變 soft limit, 所以設定 LimitNOFILE 就變得沒有必要。

但事實上很多程式都不會自行去改,所以例如 Kafka, Elasticsearch 都還是要自行在 service unit 裡面設定好 (systemctl edit 可覆寫 package 預設 service). 原先那個 soft limit 1024 限制是因為如果用 select(2) 去寫,上限就 1024 (FD_SETSIZE), 改超過會出錯,所以才保留下來。有意思的是 golang 在 1.19 之後預設行為是這樣(直接 Google 翻譯):

在 Unix 作業系統上,匯入 os 套件的 Go 程式現在會自動將開啟檔案限制 (RLIMIT_NOFILE) 提高到允許的最大值;也就是說,它們會將軟限制更改為與硬限制一致。這修正了某些系統為了相容於使用 select 系統呼叫的非常古老的 C 程式而人為設定的較低限制。 Go 程序並不受此限制的影響,相反,即使是像 gofmt 這樣簡單的程序,在並行處理多個文件時,也經常會耗盡這些系統上的文件描述符。此變更的一個影響是,Go 程式在子進程中執行非常古老的 C 程式時,可能會以過高的限制執行這些程式。可以透過在呼叫 Go 程式之前設定硬限制來修正此問題。

以前用 golang 寫一些要處理 high concurrency 寫入的程式還特別在 service 裡面改 LimitNOFILE, 原來在 2022 年 1.19 之後就已經不需要了啊。