systemd (简体中文)
zh-TW:Systemd Template:Article summary start Template:Article summary text Template:Article summary heading Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary end
摘自项目主页:
systemd 是 Linux 下的一款系统和服务管理器,兼容 SysV 和 LSB 的启动脚本。systemd 的特性有:支持并行化任务;同时采用 socket 式与 D-Bus 总线式激活服务;按需启动守护进程(daemon);利用 Linux 的 cgroups 监视进程;支持快照和系统恢复;维护挂载点和自动挂载点;各服务间基于依赖关系进行精密控制。systemd 完全可以替代 Arch 曾经使用的 sysvinit 启动系统。
另见维基百科上的介绍。
Contents
迁移前需考虑
- 阅读该站,了解 systemd。
- systemd 自己有一套日志(journal)系统,用于代替 syslog。两者也可以共存,参见后面的日志部分。
- 虽然 systemd 可以替换 cron、acpid、xinetd 等的部分功能。至少目前还可以继续使用这些服务,无需立即切换。
- 交互式 initscripts 启动脚本在 systemd 中无法工作。例如 netcfg-menu 无法FS#31377)在启动时显示。
安装
本部分帮助还在使用sysvinitAUR 和 initscripts 的用户迁移到 systemd.
- 从官方软件仓库安装 systemd 并添加内核参数
init=/usr/lib/systemd/systemd
- 使用
systemctl enable <服务名>
启用需要的服务(大致相当于以前DAEMONS
数组的作用,新的服务名称参见 Daemons_List_(简体中文))。 - 重启系统,执行命令
cat /proc/1/comm
,如果返回systemd
,表示 systemd 已经正常启动。 - 确认主机名已经正确设置:
hostnamectl set-hostname myhostname
。 - 删除 initscripts 和 sysvinit,并安装systemd-sysvcompat.
- (可选)删除
init=/usr/lib/systemd/systemd
内核参数,现在已经不需要它了。systemd-sysvcompat 软件包提供了一个软链接,使 systemd 成为默认 init。
附加信息
- 如果内核参数中有
quiet
,建议在一开始先去掉,以便调试。
- 使用 systemd 的时候无需将用户加入特殊用户组(如
sys
、disk
、lp
、network
、video
、audio
、optical
、storage
、scanner
、power
等等)。加入这些组反而会有问题,例如audio组会导致程序阻塞软件混声。每个 PAM 登录都拥有一个 logind 会话,它通过POSIX ACLs,赋予本地会话以声音设备访问权限、通过udisks挂载和卸载移动设备的权限等。
- 阅读 Network Configuration (简体中文),了解如何配置网络。
原生 systemd 配置文件
虚拟控制台
/etc/vconsole.conf
文件用来配置虚拟控制台,包括键盘布局和控制台字体:
/etc/vconsole.conf
KEYMAP=us FONT=lat9w-16 FONT_MAP=8859-1_to_uni
还可以通过命令设置键盘布局:
# localectl set-keymap de
localectl
也可以设置X11的键盘布局:
# localectl set-x11-keymap de
详情参见 man 1 localectl
和 man 5 vconsole.conf
。
硬件时钟
systemd 默认硬件时钟为协调世界时(UTC)。
硬件时钟设定为地方时
将硬件时钟配置为地方时(不建议):
# timedatectl set-local-rtc true
重新调整为 UTC:
# timedatectl set-local-rtc false
如果设置成本地时间,处理夏令时有些麻烦。如果夏令时调整发生在关机时,下次启动时时间会出现问题(更多信息)。最新的内核直接从实时时钟芯片(RTC)读取时间,不使用 hwclock
,内核把从 RTC 读取的时间当作 UTC 处理。所以如果硬件时间是地方时,系统启动一开始识别的时间是错误的,之后很快会进行矫正。这可能导致一些问题(尤其是时间倒退时)。
如果同时安装了 Windows 操作系统(默认使用地方时),那么一般 RTC 会被设置为地方时。Windows 其实也能处理 UTC,需要修改注册表。建议让 Windows 使用 UTC,而非让 Linux 使用地方时。Windows 使用 UTC 后,请记得禁用 Windows 的时间同步功能,以防 Windows 错误设置硬件时间。如上文所说,Linux 可以使用NTP服务来在线同步硬件时钟。
- 详情参阅 Time (简体中文)。
内核模块
目前,所有必要模块的加载均由 udev 自动完成。所以,如果不需要使用任何额外的模块,就没有必要在任何配置文件中添加启动时加载的模块。但是,有些情况下可能需要在系统启动时加载某个额外的模块,或者将某个模块列入黑名单以便使系统正常运行。
开机加载
systemd 读取 /etc/modules-load.d/
中的配置加载额外的内核模块。配置文件名称通常为 /etc/modules-load.d/<program>.conf
。格式很简单,一行一个要读取的模块名,而空行以及第一个非空格字符为#
或;
的行会被忽略,如:
/etc/modules-load.d/virtio-net.conf
# Load virtio-net.ko at boot virtio-net
另见man 5 modules-load.d
。
配置内核模块参数
在 /etc/modprobe.d/modprobe.conf
中设置额外的模块参数。
例如:
- 我们已经在
/etc/modules-load.d/loop.conf
中添加文本loop
,告诉系统开机自动加载该模块。
- 在
/etc/modprobe.d/modprobe.conf
设置额外的参数,如:options loop max_loop=64
。
最后,可以通过 cat /sys/module/loop/parameters/max_loop
命令检查配置是否生效。
禁用内核模块
禁用内核模块的方法和 Arch 默认的 initscripts 相同,因为该过程实际由 kmod 处理。参见:Kernel modules (简体中文)#黑名单。
文件系统挂载
默认行为是:在启动一个需要挂载特定分区的服务之前,系统自动检查并挂载分区。/etc/fstab
中设定的网络文件系统(如 NFS、Samba)无需配置即可正常工作,systemd 将确保网络文件系统在网络链接就绪后挂载。
详情参阅:man 5 systemd.mount
。
自动挂载
- 如果
/home
分区较大,可以让不依赖/home
分区的服务先启动。把下面的参数添加到/etc/fstab
文件中/home
项目的参数部分即可:
noauto,x-systemd.automount
这样 /home
分区只有需要访问时才会被挂载。内核会缓存所有的文件操作,直到 /home
分区准备完成。
- 挂载远程文件系统也是同理。如果你仅想在需要的时候才挂载,也可以添加
noauto,x-systemd.automount
参数。另外,可以设置x-systemd.device-timeout=#
参数,设置超时时间,以防止网络资源不能访问的时候浪费时间。
- 如果你的加密文件系统需要密钥,则需要添加
noauto
参数到/etc/crypttab
文件中的对应位置。systemd 开机的时候就不会打开这个加密设备,会一直等待到设备被访问时再使用密钥文件挂载。比如在使用加密RAID设备的时候可以节省一定的时间,因为 systemd 不必等到设备可用后才能访问。例如:
/etc/crypttab
data /dev/md0 /root/key noauto
LVM
如果装有不通过 initramfs 激活的LVM卷,则需启动 lvm-monitoring
服务(由 lvm2 软件包提供):
# systemctl enable lvm-monitoring
ACPI 电源管理
systemd 能够处理某些电源相关的 ACPI 事件,通过 /etc/systemd/logind.conf
的下列选项配置:
-
HandlePowerKey
:按下电源键后的动作 -
HandleSleepKey
:按下挂起键后的动作 -
HandleHibernateKey
: 按下休眠键后的动作 -
HandleLidSwitch
:合上笔记本盖后待机
动作可以是 ignore
、poweroff
、reboot
、halt
、suspend
、hibernate
、hybrid-sleep
、lock
或 kexec
。
系统默认设置为:
HandlePowerKey=poweroff HandleSuspendKey=suspend HandleHibernateKey=hibernate HandleLidSwitch=suspend
不用图形界面、或者使用 i3、awesome 这样简单的桌面管理器时,systemd 可以替代 acpid 处理 ACPI 事件。
在当前版本的 systemd 中,这些 Handle
选项将会被应用到整个系统当中,除非它们被别的程序——例如某个桌面环境中的电源管理器——给“阻止”(inhibited)。如果其它的程序没有阻止这些 Handle
,你可能会先被 systemd 挂起你的系统,然后当系统被唤醒之后,电源管理器又会再次将系统挂起。
要令 systemctl hibernate
工作,需要按照休眠和 mkinitcpio 唤醒扩展的设置步骤进行操作。(不必安装 pm-utils
)
休眠时执行的脚本
使用 systemctl suspend
、systemctl hibernate
或 systemctl hybrid-sleep
命令执行待机/休眠时,systemd 不会调用 pm-utils。pm-utils 的钩子扩展(hook)——包括 自定义钩子——会失效。不过,systemd 提供了两种类似的待机/休眠时执行脚本的机制。
使用服务文件
可以将服务文件附在 suspend.target、hibernate.target 或 sleep.target 中,这样就能在待机/休眠前后执行某些操作。用户级操作和root/系统级操作应该使用不同的服务文件。要启用用户级服务文件,使用 # systemctl enable suspend@<用户名> && systemctl enable resume@<用户名>
。例如:
/etc/systemd/system/suspend@.service
[Unit] Description=User suspend actions Before=sleep.target [Service] User=%I Type=forking Environment=DISPLAY=:0 ExecStartPre= -/usr/bin/pkill -u %u unison ; /usr/local/bin/music.sh stop ; /usr/bin/mysql -e 'slave stop' ExecStart=/usr/bin/sflock [Install] WantedBy=sleep.target
/etc/systemd/system/resume@.service
[Unit] Description=User resume actions After=suspend.target [Service] User=%I Type=simple ExecStartPre=/usr/local/bin/ssh-connect.sh ExecStart=/usr/bin/mysql -e 'slave start' [Install] WantedBy=suspend.target
至于root/系统级服务(使用 # systemctl enable root-suspend
激活):
/etc/systemd/system/root-resume.service
[Unit] Description=Local system resume actions After=suspend.target [Service] Type=simple ExecStart=/usr/bin/systemctl restart mnt-media.automount [Install] WantedBy=suspend.target
/etc/systemd/system/root-suspend.service
[Unit] Description=Local system suspend actions Before=sleep.target [Service] Type=simple ExecStart=-/usr/bin/pkill sshfs [Install] WantedBy=sleep.target
上述服务文件的一些解释(详见 man systemd.service
):
- 如果设置
Type=OneShot
,那么可以使用多个ExecStart=
参数。否则只能写一个,替代方案是在ExecStartPre
中添加命令,或使用分号分隔不同命令(见第一个例子,分号前后的空格都是必须的)。 - 若命令前加上一个“-”(半角减号),则命令返回非零值时会被忽略、当作正常执行处理。
- 有关调试,最好的方法是用
journalctl
查看日志。
合并待机和唤醒服务文件
利用下面这种自定义的一体化待机和唤醒服务,使用单一的钩子扩展即可对不同操作(待机/休眠/混合休眠)的不同阶段(进入/唤醒)进行控制。
例子和解释:
/etc/systemd/system/wicd-sleep.service
[Unit] Description=Wicd sleep hook Before=sleep.target StopWhenUnneeded=yes [Service] Type=oneshot RemainAfterExit=yes ExecStart=-/usr/share/wicd/daemon/suspend.py ExecStop=-/usr/share/wicd/daemon/autoconnect.py [Install] WantedBy=sleep.target
-
RemainAfterExit=yes
:服务启动后,除非显式地停止,否则就认为是活动的。 -
StopWhenUnneeded=yes
:服务活动时,如果无其他服务依赖该服务,就停止它。在本例中,该服务会在 sleep.target 停止后停止活动。 - 由于 sleep.target 会被 suspend.target、hibernate.target、hybrid-sleep.target 调用,且 sleep.target 本身设置了 StopWhenUnneeded,该服务文件对以上各种操作都是有效的。
使用 /usr/lib/systemd/system-sleep
systemd 在待机/休眠时执行 /usr/lib/systemd/system-sleep/
里的所有脚本,传递下面两个参数:
- 参数1:若是准备进入待机/休眠状态,则为
pre
;唤醒时为post
。 - 参数2:事件名称,
suspend
,hibernate
或hybrid-sleep
。
systemd 会同时执行所有脚本,而不是像 pm-utils 那样顺序执行。
脚本输出会记录在相关服务(systemd-suspend.service
、systemd-hibernate.service
或 systemd-hybrid-sleep.service
)中。通过日志查看:
# journalctl -b -u systemd-suspend
脚本示范:
/usr/lib/systemd/system-sleep/example.sh
#!/bin/sh case $1/$2 in pre/*) echo "进入 $2 状态..." ;; post/*) echo "从 $2 状态唤醒..." ;; esac
记得添加可执行权限:
- chmod a+x /usr/lib/systemd/system-sleep/example.sh
详情参见 man 7 systemd.special
和 man 8 systemd-sleep
。
临时文件
/usr/lib/tmpfiles.d/
和 /etc/tmpfiles.d/
中的文件描述了 systemd-tmpfiles 如何创建、清理、删除临时文件和目录,这些文件和目录通常存放在 /run
和 /tmp
中。配置文件名称为 /etc/tmpfiles.d/<program>.conf
。此处的配置能覆盖 /usr/lib/tmpfiles.d/
目录中的同名配置。
临时文件通常和服务文件同时提供,以生成守护进程需要的文件和目录。例如 Samba 服务需要目录 /run/samba
存在并设置正确的权限位,就象这样:
/usr/lib/tmpfiles.d/samba.conf
D /run/samba 0755 root root
此外,临时文件还可以用来在开机时向特定文件写入某些内容。比如,要禁止系统从USB设备唤醒,利用旧的 /etc/rc.local
可以用 echo USBE > /proc/acpi/wakeup
,而现在可以这么做:
/etc/tmpfiles.d/disable-usb-wake.conf
w /proc/acpi/wakeup - - - - USBE
详情参见 man 5 tmpfiles.d
。
单元(unit)
一个单元配置文件可以描述如下内容之一:系统服务、socket、系统设备、挂载点、交换分区/文件、启动目标(target)、文件系统路径、由 systemd 管理的计时器。文件格式受 .desktop 文件启发,而最初起源是 Windows 下的 .ini 文件。
详情参阅 man 5 systemd.unit
.
systemd 基本工具
检视和控制systemd的主要命令是systemctl
。该命令可用于查看系统状态和管理系统及服务。详见man 1 systemctl
。
分析系统状态
输出激活的单元:
$ systemctl
以下命令等效:
$ systemctl list-units
输出运行失败的单元:
$ systemctl --failed
所有可用的单元文件存放在 /usr/lib/systemd/system/
和 /etc/systemd/system/
目录(后者优先级更高)。查看所有已安装服务:
$ systemctl list-unit-files
使用单元
一个单元可以是系统服务(.service
)、挂载点(.mount
)、sockets(.sockets
)。
使用 systemctl
控制单元时,通常需要使用单元文件的全名,包括扩展名(例如 sshd.service
)。但是有些单元可以在systemctl
中使用简写方式。
- 如果无扩展名,systemctl 默认把扩展名当作
.service
。例如netcfg
和netcfg.service
是等价的。 - 挂载点会自动转化为相应的
.mount
单元。例如/home
等价于home.mount
。 - 设备会自动转化为相应的
.device
单元,所以/dev/sda2
等价于dev-sda2.device
。
立即激活单元:
# systemctl start <单元>
立即停止单元:
# systemctl stop <单元>
重启单元:
# systemctl restart <单元>
命令单元重新读取配置:
# systemctl reload <单元>
输出单元运行状态:
$ systemctl status <单元>
检查单元是否配置为自动启动:
$ systemctl is-enabled <单元>
开机自动激活单元:
# systemctl enable <单元>
取消开机自动激活单元:
# systemctl disable <单元>
显示单元的手册页(必须由单元文件提供):
# systemctl help <单元>
重新载入 systemd,扫描新的或有变动的单元:
# systemctl daemon-reload
电源管理
安装 polkit
后才可使用电源管理。
如果你正登录在一个本地的systemd-logind
用户会话,且当前没有其它活动的会话,那么以下命令无需root权限即可执行。否则(例如,当前有另一个用户登录在某个tty),systemd 将会自动请求输入root密码。
重启:
$ systemctl reboot
退出系统并停止电源:
$ systemctl poweroff
待机:
$ systemctl suspend
休眠:
$ systemctl hibernate
混合休眠模式(同时休眠到硬盘并待机):
$ systemctl hybrid-sleep
启动登录管理器
通过启动登录管理器(或称显示管理器),即可进行图形界面登录。 要启用图形界面登录,运行适当的登录管理器(或称显示管理器)即可。目前,Arch 提供了 GDM、KDM、SLiM、XDM、LXDM、LightDM 和 SDDMAUR 的 systemd 服务文件。以 KDM 为例,配置开机启动:
# systemctl enable kdm.service
执行上述命令后,登录管理器应当能正常工作了。如果不是的话,很可能是因为你修改了default.target
。默认情况应当如下:
# ls -l /etc/systemd/system/default.target
/etc/systemd/system/default.target -> /usr/lib/systemd/system/graphical.target
删除被修改的 default.target
即可,systemd 会自动使用默认配置(即 graphical.target
):
# rm /etc/systemd/system/default.target
使用 systemd-logind
可使用 loginctl
来查看用户会话的状态。所有 PolicyKit 操作,如挂起系统、挂载外部驱动器,都无需配置即可使用。
$ loginctl show-session $XDG_SESSION_ID
自己编写 .service 文件
处理依赖关系
使用systemd时,可通过正确编写单元配置文件来解决其依赖关系。典型的情况是,单元A
要求单元B
在A
启动之前运行。在此情况下,向单元A
配置文件中的 [Unit]
段添加 Requires=B
和 After=B
即可。若此依赖关系是可选的,可添加 Wants=B
和 After=B
。请注意 Wants=
和 Requires=
并不意味着 After=
,即如果 After=
选项没有制定,这两个单元将被并行启动。
依赖关系通常被用在服务(service)而不是目标(target)上。例如, network.target
一般会被某个配置网络接口的服务引入,所以,将自定义的单元排在该服务之后即可,因为 network.target
已经启动。
启动方式
编写自定义的service文件时,可以选择几种不同的服务启动方式。启动方式可通过配置文件 [Service]
段中的 Type=
参数进行设置。具体的参数说明请参阅 man systemd.service
。
-
Type=simple
(默认值):systemd认为该服务将立即启动。服务进程不会fork。如果该服务要启动其他服务,不要使用此类型启动,除非该服务是socket激活型。 -
Type=forking
:systemd认为当该服务进程fork,且父进程退出后服务启动成功。对于常规的守护进程(daemon),除非你确定此启动方式无法满足需求,使用此类型启动即可。使用此启动类型应同时指定PIDFile=
,以便systemd能够跟踪服务的主进程。 -
Type=oneshot
:这一选项适用于只执行一项任务随后退出的服务。你可能需要同时设置RemainAfterExit=yes
使得 systemd 在服务进程退出之后仍然认为服务处于激活状态。 -
Type=notify
:与Type=simple
相同,但约定服务会在就绪后向 systemd 发送一个信号。这一通知的实现由libsystemd-daemon.so
提供。 -
Type=dbus
:若以此方式启动,当指定的BusName
出现在DBus系统总线上时,systemd认为服务就绪。
修改现存单元文件
要更改由软件包提供的单元文件,先创建名为 /etc/systemd/system/<单元名>.d/
的目录(如 /etc/systemd/system/httpd.service.d/
),然后放入 *.conf
文件,其中可以添加或重置参数。这里设置的参数优先级高于原来的单元文件。例如,如果想添加一个额外的依赖,创建这么一个文件即可:
/etc/systemd/system/<unit>.d/customdependency.conf
[Unit] Requires=<新依赖> After=<新依赖>
然后运行以下命令使更改生效:
# systemctl daemon-reload # systemctl restart <单元>
此外,把旧的单元文件从 /usr/lib/systemd/system/
复制到 /etc/systemd/system/
,然后进行修改,也可以达到同样效果。在 /etc/systemd/system/
目录中的单元文件的优先级总是高于 /usr/lib/systemd/system/
目录中的同名单元文件。注意,当 /usr/lib/
中的单元文件因软件包升级变更时,/etc/
中自定义的单元文件不会同步更新。此外,你还得执行 systemctl reenable <unit>
,手动重新启用该单元。因此,建议使用前面一种利用 *.conf
的方法。
单元配置文件的 vim 语法高亮支持
可从 官方仓库 安装 vim-systemd 软件包,使 unit 配置文件在 Vim 下支持语法高亮。
目标(target)
启动级别(runlevel)是一个旧的概念。现在,systemd 引入了一个和启动级别功能相似又不同的概念——目标(target)。不像数字表示的启动级别,每个目标都有名字和独特的功能,并且能同时启用多个。一些目标继承其他目标的服务,并启动新服务。systemd 提供了一些模仿 sysvinit 启动级别的目标,仍可以使用旧的 telinit 启动级别
命令切换。
获取当前目标
不要使用 runlevel
命令了:
$ systemctl list-units --type=target
创建新目标
在 Fedora 中,启动级别 0、1、3、5、6 都被赋予特定用途,并且都对应一个 systemd 的目标。然而,没有什么很好的移植用户定义的启动级别(2、4)的方法。要实现类似功能,可以以原有的启动级别为基础,创建一个新的目标 /etc/systemd/system/<新目标>
(可以参考 /usr/lib/systemd/system/graphical.target
),创建 /etc/systemd/system/<新目标>.wants
目录,向其中加入额外服务的链接(指向 /usr/lib/systemd/system/
中的单元文件)。
目标表
SysV 启动级别 | Systemd 目标 | 注释 |
---|---|---|
0 | runlevel0.target, poweroff.target | 中断系统(halt) |
1, s, single | runlevel1.target, rescue.target | 单用户模式 |
2, 4 | runlevel2.target, runlevel4.target, multi-user.target | 用户自定义启动级别,通常识别为级别3。 |
3 | runlevel3.target, multi-user.target | 多用户,无图形界面。用户可以通过终端或网络登录。 |
5 | runlevel5.target, graphical.target | 多用户,图形界面。继承级别3的服务,并启动图形界面服务。 |
6 | runlevel6.target, reboot.target | 重启 |
emergency | emergency.target | 急救模式(Emergency shell) |
切换启动级别/目标
systemd 中,启动级别通过“目标单元”访问。通过如下命令切换:
# systemctl isolate graphical.target
该命令对下次启动无影响。等价于telinit 3
或 telinit 5
。
修改默认启动级别/目标
开机启动进的目标是 default.target
,默认链接到 graphical.target
(大致相当于原来的启动级别5)。可以通过内核参数更改默认启动级别:
-
systemd.unit=multi-user.target
(大致相当于级别3) -
systemd.unit=rescue.target
(大致相当于级别1)
另一个方法是修改 default.target
。可以通过 systemctl
修改它:
# systemctl enable multi-user.target
命令执行情况由 systemctl
显示:链接 /etc/systemd/system/default.target
被创建,指向新的默认启动级别。该方法当且仅当目标配置文件中有以下内容时有效:
[Install] Alias=default.target
目前,multi-user.target
、graphical.target
都包含这段内容。
日志
systemd 提供了自己日志系统(logging system),称为 journal. 使用 systemd 日志,无需额外安装日志服务(syslog)。读取日志的命令:
# journalctl
默认情况下(当 Storage=
在文件 /etc/systemd/journald.conf
中被设置为 auto
),日志记录将被写入 /var/log/journal/
。该目录是 systemd 软件包的一部分。若被删除,systemd 不会自动创建它,直到下次升级软件包时重建该目录。如果该目录缺失,systemd 会将日志记录写入 /run/systemd/journal
。这意味着,系统重启后日志将丢失。
过滤输出
journalctl
可以根据特定字段过滤输出,例如:
显示本次启动后的所有日志:
# journalctl -b
不过,一般大家更关心的不是本次启动后的日志,而是上次启动时的(例如,刚刚系统崩溃了)。目前还没有这项功能,正在 systemd-devel@lists.freedesktop.org 讨论中。
目前的折中方案是:
# journalctl --since=today | tac | sed -n '/-- Reboot --/{n;:r;/-- Reboot --/q;p;n;b r}' | tac
以上命令输出本日内的所有启动信息。但要注意,如果日志很多,该命令执行时间会比较漫长。
动态跟踪最新信息:
# journalctl -f
显示特定程序的所有消息:
# journalctl /usr/lib/systemd/systemd
显示特定进程的所有消息:
# journalctl _PID=1
显示指定单元的所有消息:
# journalctl -u netcfg
详情参阅man journalctl
、man systemd.journal-fields
,以及 Lennert 的这篇博文。
日志大小限制
如果按上面的操作保留日志的话,默认日志最大限制为所在文件系统容量的 10%,即:如果 /var/log/journal
储存在 50GiB 的根分区中,那么日志最多存储 5GiB 数据。可以修改 /etc/systemd/journald.conf
中的 SystemMaxUse
来指定该最大限制。如限制日志最大 50MiB:
SystemMaxUse=50M
详情参见 man journald.conf
.
配合 syslog 使用
systemd 提供了 socket /run/systemd/journal/syslog
,以兼容传统日志服务。所有系统信息都会被传入。要使传统日志服务工作,需要让服务链接该 socket,而非 /dev/log
(官方说明)。Arch 软件仓库中的 syslog-ng 已经包含了需要的配置。
设置开机启动 syslog-ng:
# systemctl enable syslog-ng
这里有一份很不错的 journalctl
指南。
优化
参阅:Improve Boot Performance (简体中文)。
启动过程分析
systemd 提供了一个分析启动过程的工具 —— systemd-analyze
。可以用它看看哪些单元拖慢了开机过程,并据此进行优化。
查看开机过程在内核/用户空间消耗的时间:
$ systemd-analyze
按照耗费时间顺序,输出启动每个单元耗费的时间:
$ systemd-analyze blame
生成类似于 bootchart 的开机过程图表:
$ systemd-analyze plot > plot.svg
使用 systemd-bootchart
自2012年10月17日,bootchart 工具已经合并进 systemd 中,使用方法和原来的 bootchart 大同小异,添加下列内容到内核参数即可:
initcall_debug printk.time=y init=/usr/lib/systemd/systemd-bootchart
使用 bootchart2
由于没有办法在内核参数设置两个 init,所以不能使用源里的 bootchart。不过,AUR 软件包 bootchart2-gitAUR 提供了一个的 systemd 服务,这样就可以和 systemd 一起使用。安装后启用即可:
# systemctl enable bootchart.service
详情参阅 bootchart 文档。
预读
systemd 自己实现了一个 readahead,可以用来提高开机效率。不过,效果会因内核版本和硬件情况而不同(极少数情况下还会变慢)。开启 readahead:
# systemctl enable systemd-readahead-collect.service systemd-readahead-replay.service
要知道,readahead 的超级牛力只有在重启几次后才会显现。
疑难解答
关机/重启十分缓慢
如果关机特别慢(甚至跟死机了一样),很可能是某个拒不退出的服务在作怪。systemd 会等待一段时间,然后再尝试杀死它。请阅读这篇文章,确认你是否是该问题受害者。
短时进程无日志记录
若 journalctl -u foounit.service
没有显示某个短时进程的任何输出,那么改用 PID 试试。例如,若 systemd-modules-load.service
执行失败,那么先用 systemctl status systemd-modules-load
查询其 PID(比如是123),然后检索该 PID 相关的日志 journalctl -b _PID=123
。运行时进程的日志元数据(诸如 _SYSTEMD_UNIT 和 _COMM)被乱序收集在 /proc
目录。要修复该问题,必须修改内核,使其通过套接字连接来提供上述数据,该过程类似于 SCM_CREDENTIALS。
诊断启动问题
使用如下内核参数引导:
systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M
更多有关调试的信息,参见该文。
禁止在程序崩溃时转储内存
把 /etc/sysctl.d/coredump.conf
链接到 /dev/null
,然后应用 sysctl 即可(来源):
# ln -s /dev/null /etc/sysctl.d/coredump.conf # /usr/lib/systemd/systemd-sysctl # ulimit -c unlimited