百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

systemd详解1-启动 systemd-run

liebian365 2024-10-27 13:21 35 浏览 0 评论

平常工作经常涉及systemd,之前掌握更多的是使用方法。源码走读了很久,准备系统的整理下,供其他人参考和交流。systemd提供的不仅仅是一个简单的启动管理系统,而是一个高度集成、功能丰富的操作系统基础架构解决方案,一套协同管理Linux系统各个方面的大规模软件套件,旨在简化系统配置、提高系统启动速度和整体性能。由于本人知识有限,梳理会有所侧重,其他未能覆盖到的地方可以参考其他文章。unti以service为主,源码梳理主路线:main->service ExecStart。

linux启动时序

在介绍systemd之前,有必要介绍下系统启动从上电到systemd的流程,有助于把握systemd在整个系统中的位置。

  1. 上电后启动ROMCode,做开机自检(POST)。
  2. 选择启动设备,从磁盘加载引导程序bootloader到内存。
  3. bootloader加载kernel镜像到内存,执行各个内核模块初始化和driver初始化,如mm_init、sched_init、init_IRQ等。
  4. kernel完成初始化进入用户空间,执行第一个用户空间init程序。
  5. 对于使用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包括:

  1. sysinit.target:系统初始化阶段,完成系统底层服务及设备挂载等操作;
  2. basic.target:包含了基本系统服务,是许多其他target的基础。
  3. multi-user.target:代表多用户命令行模式,不包含图形界面。
  4. 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之间的依赖关系,根据不同的需求选择不同的关键字,为了达到更好的效果有时候也需要组合使用:

  1. Requires: 侧重于业务之间的强依赖。如A.service Requires B.service,systemd会保证A启动前B处于启动状态(start)或者已经启动完成状态(running),所以如果A启动时发现B未启动,systemd会拉起B,这样A和B就同时启动了。如果B启动失败或者运行中出现异常退出,那么A同样也会退出,体现了2者的强绑定。场景举例:web服务器依赖于mysql数据库才能正常工作,依赖关系必须使用Requires
  2. wants: 同Requires,区别在于依赖关系弱依赖,即被依赖者(B)不存在或者异常退出,依赖者(A)不受影响,依然正常运行。场景举例:系统大多service都需要收集log用于定位,弱依赖log service,即使log service未能启动,其他service也能正常运行。
  3. 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”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对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)...

取消回复欢迎 发表评论: