systemd 启动时意外地长时间激活服务

systemd 启动时意外地长时间激活服务

我用来systemd-analyze plot分析服务在系统启动时运行所花费的时间。有一个相当简单的oneshot服务,update_sysfs_cpu_permissions.service它花费的时间出乎意料的长(755ms),而且大部分时间都花在Activating状态,而不是Active状态。

服务文件的内容:

# /etc/systemd/system/update_sysfs_cpu_permissions.service
[Unit]
Description=Give the group `cpu_tuners` permissions to write to the files /sys/.../cpufreq/policy*/* if the `root` user can write to them

[Service]
Type=oneshot
User=root
# For every file of mode rw-r--r-- change mode to rw-rw-r-- and owners to root:cpu_tuners (instead of root:root)
# mindepth and maxdepth are to identify we only want to change files inside policy* (though, it's not a very strong constraint and could be replaced with something stricter)
ExecStart=/usr/bin/find /sys/devices/system/cpu/cpufreq/ -mindepth 2 -maxdepth 2 -type f -perm 644 -exec /bin/sh -c 'chown root:cpu_tuners "$1"; chmod 664 "$1"' _ {} \;

[Install]
WantedBy=multi-user.target

手动运行服务并不需要太多时间:

$ time sudo systemctl start update_sysfs_cpu_permissions.service

real    0m0.155s
user    0m0.019s
sys 0m0.010s
$

完整剧情:https://i.stack.imgur.com/EPh93.jpg

服务处于激活状态意味着什么?为什么启动时需要这么长时间才能运行?

答案1

为什么启动时需要这么长时间才能运行?

如果没有启动过程的更详细的跟踪(例如 bootchart),就不可能说,但是我猜是在启动期间它与其他服务竞争 CPU – 也可能是磁盘输入/输出,因为它需要将/bin/find/bin/sh/bin/chmod/bin/chown可执行文件从磁盘加载到内存中。

而且,大部分时间都花在Activating状态,而不是Active状态。

这是设计使然 – Type=oneshot 服务具有默认为“活动”状态。 Type=oneshot 服务的全部目的是在所有 ExecStart= 运行时处于“激活”状态,以便只有在 ExecStart= 命令完成后“启动”作业才会完成。

服务处于激活状态意味着什么?

“激活”意味着该单元已被调用,但尚未“准备好”用于依赖性和排序目的。例如,如果您采用数据库服务器守护程序,它可能会花费一些时间启动、建立套接字、重播日志等,在此期间进程正在运行,但尚未接受客户端连接,这意味着任何其他服务尝试使用它将会失败。

因此,当启动作业运行时,它等待让服务在继续启动其依赖项(如果有)之前离开“正在激活”状态。例如,httpd.service 将在队列中等待,而 php-fpm.service 仍处于“激活”状态。

  • 对于 Type=forking,“激活”持续到 systemd 看到进程“守护进程”(以传统的分叉或双分叉方式 - 更具体地说,它持续到初始父进程退出,让其孩子接管)。

  • 对于 Type=notify,“激活”将持续到进程通过指定套接字或管道向 systemd 发送“READY=1”消息为止。

  • 对于 Type=simple,默认情况下没有“激活”状态(当人们抱怨“Type=simple 是使用 systemd 的真正方式”时,他们往往会忘记这一点)。

  • 对于 Type=oneshot,如您的情况,“激活”持续到服务完成其任务为止,即直到 ExecStart= 中的所有命令都完成。

(ExecStartPost= 还可以扩展“激活”状态,即使对于 Type=simple,也可以用于某些任务必须在服务启动后、真正准备好使用之前完成。)

因此,在此示例中,保持“正在激活”状态意味着如果另一个启动服务将您的设备列在 中After=,它将被正确延迟,直到 /bin/find 完成并且权限确实已更新。

尝试删除 User=root,因为这可能会产生一些记录不足的副作用。

设置用户=没有PAMName= 仅具有更改 UID/GID 的作用。

相关内容