我正在尝试让 systemd 启动一个守护进程并将 8,192 个监听套接字传递给它。我有一个.service
和.socket
文件可以可靠地使用更多“正常”数量的侦听套接字,如下所示:
# a-daemon.socket
[Unit]
Description=A Daemon (sockets)
After=network.target
[Socket]
Accept=no
ListenStream=8192
# a-daemon.service
[Unit]
Description=A Daemon
After=network.target
Requires=a-daemon.socket
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
ExecStart=/usr/local/sbin/a-daemon
但是如果我换成a-daemon.socket
一个有 8,192ListenStream
行的版本,每个 TCP 端口从 8192 到 16383(含)一个,那么守护程序将不再启动。套接字单元可以正常启动,但服务单元失败;我得到的唯一错误信息是
systemd[17563]: a-daemon.service: Failed to execute command: Argument list too long
systemd[17563]: a-daemon.service: Failed at step EXEC spawning /usr/local/sbin/a-daemon: Argument list too long
据我了解,这实际上不是参数 list的问题,因为 systemd 不会将套接字 fd 编号放在守护进程的命令行或类似的东西上。我猜这是同时打开文件数量限制的问题,所以我设置DefaultLimitNOFILE=32768
了/etc/systemd/system.conf
一个等效设置/etc/security/limits.conf
并重新启动。没变。然后我把ExecStartPre=/usr/sbin/prlimit -n
.service文件放进去,尝试重启,确认增加的限制已经生效:
prlimit[18134]: RESOURCE DESCRIPTION SOFT HARD UNITS
prlimit[18134]: NOFILE max number of open files 32768 32768 files
但是服务仍然失败,同样的方式。现在我没有主意了。你能建议我可以尝试做些什么来完成这项工作吗?
(我知道监听 8,192 个连续的 TCP 端口是一件很奇怪的事情。请相信我,我有一个很好的理由,我不能分享。)
再看一下 systemd 联机帮助页后,我意识到systemd 在该区域中放置了一些东西,其
argv
大小与侦听套接字的数量成正比:(粗体 - 我的重点)这意味着,如果您
ListenStream
在套接字单元文件中有 8192 个条目,systemd 将尝试将LISTEN_FDNAMES=[name]:[name]:...
8192 重复(设置在哪里name
)FileDescriptorName
放入服务环境中。FileDescriptorName
默认为套接字单元文件的完整基本名称。这很容易溢出 Linux 对单个环境变量名称+值(通常为 128k)长度的相当低的固定限制MAX_ARG_STRLEN
,从而execve(2)
导致E2BIG
.对于一个不关心名字的守护进程,解决方法是把
在服务文件(
[Service]
部分)中。这消除了问题环境变量并使内核满意。如果您确实需要某些 fd 名称并且您达到了此限制,我不知道您会做什么。