systemd详解1-启动 systemd-run
liebian365 2024-10-27 13:21 35 浏览 0 评论
平常工作经常涉及systemd,之前掌握更多的是使用方法。源码走读了很久,准备系统的整理下,供其他人参考和交流。systemd提供的不仅仅是一个简单的启动管理系统,而是一个高度集成、功能丰富的操作系统基础架构解决方案,一套协同管理Linux系统各个方面的大规模软件套件,旨在简化系统配置、提高系统启动速度和整体性能。由于本人知识有限,梳理会有所侧重,其他未能覆盖到的地方可以参考其他文章。unti以service为主,源码梳理主路线:main->service ExecStart。
linux启动时序
在介绍systemd之前,有必要介绍下系统启动从上电到systemd的流程,有助于把握systemd在整个系统中的位置。
- 上电后启动ROMCode,做开机自检(POST)。
- 选择启动设备,从磁盘加载引导程序bootloader到内存。
- bootloader加载kernel镜像到内存,执行各个内核模块初始化和driver初始化,如mm_init、sched_init、init_IRQ等。
- kernel完成初始化进入用户空间,执行第一个用户空间init程序。
- 对于使用systemd的系统,内核不再寻找传统的/sbin/init,而是查找配置为init的程序,通常指向/usr/lib/systemd/systemd。
systemd管理方式
用户空间进程众多,systemd充当管理者的角色按照一定的时序高效并行启动各个进程。systemd用单元(unit)的概念来描述待管理的结构,每个单元都是系统的一个组件,具有特定的配置和行为,根据要实现的功能或作用划分为:service、mount、device、timer、socket、scope、target等[1]。
需要简单介绍下target单元类型,以便后面介绍sytemd分段启动做铺垫。它代表了系统的runlevel或者一组相关service的目标状态。target本身并不执行任何服务,而是作为一个容器,定义了一组需要同时激活的service集合。每个target unit文件(通常以.target为扩展名)包含所依赖的其他service和target单元。当系统切换到某个target时,systemd会确保所有该target依赖的service都被加载并启动成功,从而实现特定级别的系统功能。在Linux系统中常见的几个target units包括:
- sysinit.target:系统初始化阶段,完成系统底层服务及设备挂载等操作;
- basic.target:包含了基本系统服务,是许多其他target的基础。
- multi-user.target:代表多用户命令行模式,不包含图形界面。
- graphical.target:代表带有图形桌面环境的多用户模式。
default.target是一个特殊的unit,systemd在启动系统时始终使用default.target作为起点。default.target默认情况下会软连接到multi-user.target(服务器系统)或graphical.target(GUI)其中之一。可以通过下面命令查看和修改默认值:
root@localhost:~# ls -l /usr/lib/systemd/system/default.target
lrwxrwxrwx 1 root root 16 Jan 5 14:27 /usr/lib/systemd/system/default.target -> graphical.target
// 查看default.target
root@localhost:~# systemctl get-default
graphical.target
// 修改default.target
root@localhost:~# systemctl set-default multi-user.target
Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/multi-user.target.
systemd分层启动
上图是参考systemd bootup,进行了缩减以便清晰说明systemd分层启动的流程。
systemd以default.target为启动开始点,default.target软连接到graphical.target(以GUI系统为例),因为graphical.target配置了After=multi-user.target和Requires=multi-user.target,会先等待multi-user.target启动完成,依次类推到sysinit.target,最终会以sysinit.target以及依赖项为最早启动项,而graphical.target为最终达到的目标状态。
// graphical.target
[Unit]
Requires=multi-user.target
Wants=display-manager.service
After=multi-user.target rescue.service rescue.target display-manager.service
// multi-user.target
[Unit]
Requires=basic.target
After=basic.target rescue.service rescue.target
//basic-user.target
[Unit]
Requires=sysinit.target
Wants=sockets.target timers.target paths.target slices.target
After=sysinit.target sockets.target paths.target slices.target tmp.mount
//sysinit.target
[Unit]
Wants=local-fs.target swap.target
After=local-fs.target swap.target emergency.service emergency.target
Requires、Wants和After的区别
从上面给出的配置中可以看到使用了三个关键字,用来定义和管理unit之间的依赖关系,根据不同的需求选择不同的关键字,为了达到更好的效果有时候也需要组合使用:
- Requires: 侧重于业务之间的强依赖。如A.service Requires B.service,systemd会保证A启动前B处于启动状态(start)或者已经启动完成状态(running),所以如果A启动时发现B未启动,systemd会拉起B,这样A和B就同时启动了。如果B启动失败或者运行中出现异常退出,那么A同样也会退出,体现了2者的强绑定。场景举例:web服务器依赖于mysql数据库才能正常工作,依赖关系必须使用Requires。
- wants: 同Requires,区别在于依赖关系弱依赖,即被依赖者(B)不存在或者异常退出,依赖者(A)不受影响,依然正常运行。场景举例:系统大多service都需要收集log用于定位,弱依赖log service,即使log service未能启动,其他service也能正常运行。
- after: 侧重于启动顺序,解决的是时间上的依赖问题,而非功能上的依赖。如A.service After B.service,A必须等待B启动完成,B启动完成表示B处于active状态或者启动完成后正常退出。
启动完成的概念有必要解释下,即服务有start状态转为active状态。对于Type=notify类型的service来说开发者可以根据功能流程通过sd_notify(0, "READY=1")通知systemd已经启动完成。
用下面2个实验说明下Requires和After的区别:
- 实验1: A After B.service
- 实验2: A Requires B.service
// A.c
#include <stdio.h>
#include <unistd.h>
int main() {
while (1) {}
return 0;
}
// /etc/systemd/system/A.service
[Unit]
After=B.service //实验1
# Requires=B.service //实验2
[Service]
ExecStart=/home/xxx/Desktop/A
[Install]
WantedBy=multi-user.target
// B.c
#include <stdio.h>
#include <unistd.h>
#include <systemd/sd-daemon.h>
#include <sys/wait.h>
int main() {
// sleep 200ms后通知systemd ready
usleep(200000);
sd_notify(0, "READY=1");
while (1) {}
return 0;
}
// /etc/systemd/system/B.service
[Unit]
Description=B
[Service]
Type=notify
ExecStart=/home/xxx/Desktop/B
[Install]
WantedBy=multi-user.target
最常见的场景是当A.service需要在启动前确保B.service已经运行,在A.service中同时配置"Requires=B"和"After=B"。
注解
[1]:
systemd Unit | Description |
.automount | 用于实现启动时按需(即插即用)并行挂载文件系统单元。当访问特定的挂载点时,对应的文件系统会自动挂载。 |
.device | 定义在/dev/目录下暴露给系统管理员的硬件和虚拟设备。并非所有设备都有unit文件;通常,硬盘、网络设备等块设备会有相应的unit文件。 |
.mount | 定义Linux文件系统结构中的一个挂载点,用于管理文件系统的挂载操作。 |
.scope | .scope单元用于定义和管理一组系统进程集合。此类单元不由unit文件配置,而是通过程序方式创建。主要用于组织和管理服务工作者进程资源。 |
.service | .service unit文件定义由systemd管理的进程,包括cron定时任务服务、CUPS打印系统、iptables防火墙规则、逻辑卷管理服务(如LVM)、NetworkManager网络管理服务以及其他更多服务。 |
.slice | .slice单元定义了一个“切片”,它是系统资源的一个概念性划分,与一组进程相关联。可以将所有系统资源视为一个整体,而“切片”则代表从这个整体中划分出来的一部分资源。 |
.socket | .socket单元定义了进程间通信套接字,如网络套接字。当有连接请求到达时,systemd可以根据此单元来激活对应的服务。 |
.swap | .swap单元定义交换设备或交换文件,用于管理系统中的虚拟内存空间。 |
.target | .target单元定义了一组unit文件集合,它们表示启动同步点、运行级别和服务组。目标单元确定为了成功启动必须处于活动状态的服务和其他单元。 |
.timer | .timer单元定义了可以在指定时间触发程序执行的计时器 |
相关推荐
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
-
明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
-
首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
-
齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...
- Qt界面——搭配QCustomPlot(qt platform)
-
这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
-
老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
-
用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
-
前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...
- 掌握Visual Studio项目配置【基础篇】
-
1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
-
随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...
- Visual Studio Community 2022(VS2022)安装图文方法
-
直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...
- Qt添加MSVC构建套件的方法(qt添加c++11)
-
前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...
- Qt为什么站稳c++GUI的top1(qt c)
-
为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...
- qt开发IDE应该选择VS还是qt creator
-
如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...
- Qt 5.14.2超详细安装教程,不会来打我
-
Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...
- Cygwin配置与使用(四)——VI字体和颜色的配置
-
简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
- Qt界面——搭配QCustomPlot(qt platform)
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
- 掌握Visual Studio项目配置【基础篇】
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
- Visual Studio Community 2022(VS2022)安装图文方法
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)