Systemd 的简介和特点
同 SysVinit 和 LSB init scripts 兼容
更快的启动速度
- 尽可能启动更少的进程
- 尽可能将更多进程并行启动
图 1. UpStart 对 SysVinit 的改进
图 2. systemd 的并发启动
systemd 提供按需启动能力
Systemd 采用 Linux 的 Cgroup 特性跟踪和管理进程的生命周期
图 3. 找到正确 pid
启动挂载点和自动挂载的管理
实现事务性依赖关系管理
能够对系统进行快照和恢复
日志服务
- syslog 不安全,消息的内容无法验证。每一个本地进程都可以声称自己是 Apache PID 4711,而 syslog 也就相信并保存到磁盘上。
- 数据没有严格的格式,非常随意。自动化的日志分析器需要分析人类语言字符串来识别消息。一方面此类分析困难低效;此外日志格式的变化会导致分析代码需要更新甚至重写。
- 简单性:代码少,依赖少,抽象开销最小。
- 零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
- 移植性:日志 文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
- 性能:添加和浏览 日志 非常快。
- 最小资源占用:日志 数据文件需要较小。
- 统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。Syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
- 扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
- 安全性:日志 文件是可以验证的,让无法检测的修改不再可能。
Systemd 的基本概念
单元的概念
- service :代表一个后台服务进程,比如 mysqld。这是最常用的一类。
- socket :此类配置单元封装系统和互联网中的一个 套接字 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。每一个套接字配置单元都有一个相应的服务配置单元 。相应的服务在第一个"连接"进入套接字时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。
- device :此类配置单元封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备配置单元出现。
- mount :此类配置单元封装文件系统结构层次中的一个挂载点。Systemd 将对这个挂载点进行监控和管理。比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。Systemd 会将/etc/fstab 中的条目都转换为挂载点,并在开机时处理。
- automount :此类配置单元封装系统结构层次中的一个自挂载点。每一个自挂载配置单元对应一个挂载配置单元 ,当该自动挂载点被访问时,systemd 执行挂载点中定义的挂载行为。
- swap: 和挂载配置单元类似,交换配置单元用来管理交换分区。用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。
- target :此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。这样便可以对配置单元做一个统一的控制。这样就可以实现大家都已经非常熟悉的运行级别概念。比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。 (例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别 5)
- timer:定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了 atd、crond 等传统的定时服务。
- snapshot :与 target 配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
依赖关系
Systemd 事务
图 4, Unit 的循环依赖
Target 和运行级别
表 1. Sysvinit 运行级别和 systemd 目标的对应表
| Sysvinit 运行级别 | Systemd 目标 | 备注 |
|---|---|---|
| 0 | runlevel0.target, poweroff.target | 关闭系统。 |
| 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 | 紧急 Shell |
Systemd 的并发启动原理
并发启动原理之一:解决 socket 依赖
并发启动原理之二:解决 D-Bus 依赖
并发启动原理之三:解决文件系统依赖
Systemd 的使用
系统软件开发人员
- 后台服务进程代码不需要执行两次派生来实现后台精灵进程,只需要实现服务本身的主循环即可。
- 不要调用 setsid(),交给 systemd 处理
- 不再需要维护 pid 文件。
- Systemd 提供了日志功能,服务进程只需要输出到 stderr 即可,无需使用 syslog。
- 处理信号 SIGTERM,这个信号的唯一正确作用就是停止当前服务,不要做其他的事情。
- SIGHUP 信号的作用是重启服务。
- 需要套接字的服务,不要自己创建套接字,让 systemd 传入套接字。
- 使用 sd_notify()函数通知 systemd 服务自己的状态改变。一般地,当服务初始化结束,进入服务就绪状态时,可以调用它。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | #cat /etc/system/system/sshd.service [Unit] Description=OpenSSH server daemon [Service] EnvironmentFile=/etc/sysconfig/sshd ExecStartPre=/usr/sbin/sshd-keygen ExecStart=/usrsbin/sshd –D $OPTIONS ExecReload=/bin/kill –HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s [Install] WantedBy=multi-user.target |
| 1 2 3 4 5 6 7 8 9 10 | #cat multi-user.target [Unit] Description=Multi-User System Documentation=man.systemd.special(7) Requires=basic.target Conflicts=rescue.service rescure.target After=basic.target rescue.service rescue.target AllowIsolate=yes [Install] Alias=default.target |
| 1 2 3 4 5 6 7 8 9 10 | #cat sys-kernel-debug.mount [Unit] Description=Debug File Syste DefaultDependencies=no ConditionPathExists=/sys/kernel/debug Before=sysinit.target [Mount] What=debugfs Where=/sys/kernel/debug Type=debugfs |
系统管理员
表 2. Systemd 命令和 sysvinit 命令的对照表
| Sysvinit 命令 | Systemd 命令 | 备注 |
|---|---|---|
| service foo start | systemctl start foo.service | 用来启动一个服务 (并不会重启现有的) |
| service foo stop | systemctl stop foo.service | 用来停止一个服务 (并不会重启现有的)。 |
| service foo restart | systemctl restart foo.service | 用来停止并启动一个服务。 |
| service foo reload | systemctl reload foo.service | 当支持时,重新装载配置文件而不中断等待操作。 |
| service foo condrestart | systemctl condrestart foo.service | 如果服务正在运行那么重启它。 |
| service foo status | systemctl status foo.service | 汇报服务是否正在运行。 |
| ls /etc/rc.d/init.d/ | systemctl list-unit-files --type=service | 用来列出可以启动或停止的服务列表。 |
| chkconfig foo on | systemctl enable foo.service | 在下次启动时或满足其他触发条件时设置服务为启用 |
| chkconfig foo off | systemctl disable foo.service | 在下次启动时或满足其他触发条件时设置服务为禁用 |
| chkconfig foo | systemctl is-enabled foo.service | 用来检查一个服务在当前环境下被配置为启用还是禁用。 |
| chkconfig –list | systemctl list-unit-files --type=service | 输出在各个运行级别下服务的启用和禁用情况 |
| chkconfig foo –list | ls /etc/systemd/system/*.wants/foo.service | 用来列出该服务在哪些运行级别下启用和禁用。 |
| chkconfig foo –add | systemctl daemon-reload | 当您创建新服务文件或者变更设置时使用。 |
| telinit 3 | systemctl isolate multi-user.target (OR systemctl isolate runlevel3.target OR telinit 3) | 改变至多用户运行级别。 |
表 3,systemd 电源管理命令
| 命令 | 操作 |
|---|---|
| systemctl reboot | 重启机器 |
| systemctl poweroff | 关机 |
| systemctl suspend | 待机 |
| systemctl hibernate | 休眠 |
| systemctl hybrid-sleep | 混合休眠模式(同时休眠到硬盘并待机) |
- 维护,跟踪会话和用户登录情况。如上所述,为了决定关机命令是否可行,系统需要了解当前用户登录情况,如果用户从 SSH 登录,不允许其执行关机命令;如果普通用户从本地登录,且该用户是系统中的唯一会话,则允许其执行关机命令;这些判断都需要 logind 维护所有的用户会话和登录情况。
- Logind 也负责统计用户会话是否长时间没有操作,可以执行休眠/关机等相应操作。
- 为用户会话的所有进程创建 CGroup。这不仅方便统计所有用户会话的相关进程,也可以实现会话级别的系统资源控制。
- 负责电源管理的组合键处理,比如用户按下电源键,将系统切换至睡眠状态。
- 多席位(multi-seat) 管理。如今的电脑,即便一台笔记本电脑,也完全可以提供多人同时使用的计算能力。多席位就是一台电脑主机管理多个外设,比如两个屏幕和两个鼠标/键盘。席位一使用屏幕 1 和键盘 1;席位二使用屏幕 2 和键盘 2,但他们都共享一台主机。用户会话可以自由在多个席位之间切换。或者当插入新的键盘,屏幕等物理外设时,自动启动 gdm 用户登录界面等。所有这些都是多席位管理的内容。ConsoleKit 始终没有实现这个功能,systemd 的 logind 能够支持多席位。
systemd 小结
- 令人惊奇的激进的并发启动能力,极大地提高了系统启动速度;
- 用 CGroup 统计跟踪子进程,干净可靠。
结束语
相关主题
原文链接:https://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html