systemd的启动流程
2026-01-06
1591 字约 6 分钟
...一、systemd的启动流程
当Linux系统启动时,systemd作为第一个用户空间进程(PID 1)被内核启动,其初始化过程如下:
-
内核移交控制权:
- 内核完成硬件初始化后,执行
/sbin/init(指向systemd的符号链接) - systemd以PID 1身份启动,继承内核创建的初始环境
- 内核完成硬件初始化后,执行
-
基础环境准备:
- 挂载基础虚拟文件系统:/proc, /sys, /dev
- 设置基本cgroups层次结构
- 应用系统时钟和区域设置
-
单元加载与依赖解析:
- 扫描所有单元文件路径(/usr/lib/systemd/system/, /etc/systemd/system/等)
- 构建完整的依赖关系图
- 确定启动顺序和并行启动可能性
-
启动阶段(target)执行:
graph LR A[Basic.target] --> B[sysinit.target] B --> C[sockets.target] B --> D[paths.target] B --> E[timers.target] C --> F[systemd-journald.socket] C --> G[dbus.socket] B --> H[multi-user.target] H --> I[graphical.target] -
最终目标激活:
- 根据配置启动multi-user.target(命令行模式)或graphical.target(图形界面)
- 启动getty进程提供登录提示
- 完成系统启动,进入运行状态
二、systemd服务单元的创建
1. 单元文件结构与位置
systemd服务单元定义在配置文件中,有严格的目录层次:
- 系统默认单元:
/usr/lib/systemd/system/(软件包安装) - 系统管理员自定义:
/etc/systemd/system/(优先级最高) - 运行时生成:
/run/systemd/system/(临时,重启后消失)
2. 创建一个基本服务单元
以创建一个简单的Web应用服务为例:
# 1. 创建服务文件
sudo nano /etc/systemd/system/mywebapp.service
[Unit]
Description=My Web Application Server
Documentation=https://example.com/docs
After=network.target nginx.service
Requires=nginx.service
[Service]
Type=simple
User=webapp
Group=webapp
WorkingDirectory=/opt/mywebapp
ExecStart=/usr/bin/python3 /opt/mywebapp/app.py --port=8000
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=5s
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
Environment="PYTHONPATH=/opt/mywebapp/lib"
[Install]
WantedBy=multi-user.target
# 3. 重载systemd配置
sudo systemctl daemon-reload
# 4. 启用并启动服务
sudo systemctl enable --now mywebapp.service
3. 服务类型详解
不同服务类型影响systemd如何判断服务状态:
-
simple(默认):执行ExecStart后立即视为激活
[Service] Type=simple ExecStart=/usr/sbin/nginx -g "daemon off;" -
forking:服务会fork,父进程退出后才视为激活
[Service] Type=forking ExecStart=/usr/sbin/apache2ctl start PIDFile=/var/run/apache2.pid -
oneshot:一次性执行,完成后服务处于非活动状态
[Service] Type=oneshot ExecStart=/usr/bin/migration_tool --apply RemainAfterExit=yes -
notify:服务通过sd_notify()通知systemd准备就绪
[Service] Type=notify ExecStart=/usr/bin/my_daemon --daemonize=no
三、systemd服务的启动机制
1. 依赖关系与启动顺序
systemd通过多种指令控制服务间的依赖关系:
[Unit]
Description=Database Service
# 强依赖,若mysql失败,则本服务不会启动
Requires=mysql.service
# 弱依赖,仅在mysql存在时才需要它
Wants=mysql.service
# 在网络服务启动后启动本服务
After=network.target
# 在本服务启动前必须启动的服务
Before=webapp.service
# 冲突关系,不能同时运行
Conflicts=old-database.service
2. 启动过程的生命周期
一个systemd服务的启动过程包含以下阶段:
-
准备阶段:
- 解析单元文件
- 验证依赖关系
- 分配cgroups和资源
-
执行阶段:
- 设置用户/组权限
- 配置环境变量
- 设置工作目录
- 应用资源限制(如MemoryLimit, CPUQuota)
- 执行ExecStartPre命令(如果有)
-
主进程启动:
- 执行ExecStart命令
- 根据服务类型等待服务准备就绪
-
监控与维护:
- 持续监控主进程状态
- 根据Restart策略处理失败
- 记录日志到journald
3. 按需启动机制(Socket Activation)
systemd支持通过监听套接字按需启动服务,延迟资源使用直到实际需要:
# /etc/systemd/system/myapp.socket
[Unit]
Description=MyApp Socket
[Socket]
ListenStream=127.0.0.1:8000
Accept=yes # 每个连接创建一个实例
[Install]
WantedBy=sockets.target
# /etc/systemd/system/myapp@.service
[Unit]
Description=MyApp Service
After=network.target
[Service]
ExecStart=/usr/bin/myapp-handler
StandardInput=socket
StandardError=journal
启用此配置后:
- systemd监听8000端口
- 当第一个连接到达时,systemd启动myapp@.service实例
- 将连接的socket传递给服务进程
- 服务处理请求,完成后可配置自动退出
四、系统启动优化
systemd提供多种机制优化启动过程:
1. 并行启动
- 服务可以并行启动,而不是传统的串行启动
- 依赖树被分析,无依赖关系的服务同时启动
- 通过
systemd-analyze critical-chain识别启动瓶颈
2. 启动时间分析
# 分析总体启动时间
systemd-analyze
# 按启动时间排序服务
systemd-analyze blame
# 查看关键链(最长依赖链)
systemd-analyze critical-chain
# 生成启动过程可视化图表
systemd-analyze plot > boot-process.svg
3. 启动延迟配置
[Unit]
Description=Delayed Service
# 延迟启动,避免资源竞争
After=network.target
# 确保网络完全就绪
# Wants=network-online.target
# After=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/my_service
# 在执行前延迟3秒
ExecStartPre=/bin/sleep 3
五、调试systemd服务启动问题
当服务无法正常启动时,使用以下方法诊断:
# 1. 检查服务状态
systemctl status myservice.service
# 2. 查看详细日志
journalctl -u myservice.service --since "5 minutes ago"
# 3. 详细调试模式
sudo systemctl stop myservice.service
sudo systemd-run --unit=debug-myservice --service-type=exec \
-p Environment=SYSTEMD_LOG_LEVEL=debug \
-p StandardOutput=journal \
-p StandardError=journal \
-- /usr/bin/my_service --debug
# 4. 检查单元文件语法
systemd-analyze verify /etc/systemd/system/myservice.service
# 5. 跟踪实时启动过程
journalctl -f -u myservice.service
六、实战:创建一个完整的systemd服务
以下是一个生产级Nginx缓存清理服务示例:
[Unit]
Description=Nginx Cache Purge Service
Documentation=https://example.com/nginx-cache-docs
After=network.target nginx.service
Requires=nginx.service
[Service]
Type=oneshot
User=www-data
Group=www-data
# 清理24小时前的缓存
ExecStart=/usr/bin/find /var/cache/nginx -type f -mtime +1 -delete
# 重新加载Nginx配置
ExecStartPost=/usr/sbin/nginx -s reload
# 资源限制
MemoryLimit=100M
Nice=10
IOSchedulingClass=idle
[Install]
WantedBy=multi-user.target
配合定时器:
[Unit]
Description=Daily Nginx Cache Purge Timer
[Timer]
OnCalendar=*-*-* 03:00:00 # 每天凌晨3点
Persistent=true
Unit=nginx-cache-purge.service
[Install]
WantedBy=timers.target
启用服务:
sudo systemctl daemon-reload
sudo systemctl enable --now nginx-cache-purge.timer
总结
systemd通过单元文件定义服务,通过依赖解析实现并行启动,通过套接字激活实现按需启动,形成了一个高效、灵活的系统初始化和服务管理体系。理解systemd的启动机制和服务创建方法,是掌握现代Linux系统管理的关键。通过合理设计单元文件,可以实现复杂的服务依赖、资源限制和自动恢复策略,大幅提升系统的可靠性和性能。
如果您觉得这篇文章有帮助,请点个赞吧~
相关文章
更多文章 →Linux2025-07-17
Ubuntu 22.04下Docker安装
Ubuntu22.04下Docker的安装 为什么要安装Docker,在这里就不用多说了,在我的另一篇文章里有告诉大家原因。大家可以去看看 下面是具体的步骤: 准备条件 准备安装 安装Docker 安装Docker 命令补全工具 允许非Root用户执行docker 命令 当我们安装好了Docker之后,有两种方式来执行docker 命令 在docker命令前加上sudo, 比如:sudo docker ps sudo i 切换至root...
学习
Linux2025-06-12
Ubuntu 安装Redis
更新系统包 在安装 Redis 之前,先更新系统的包列表: 安装 Redis 运行以下命令安装 Redis 服务器: 启动 Redis 服务 安装完成后,Redis 服务会自动启动。如果没有启动,可以手动启动: 设置 Redis 开机自启动 确保 Redis 在系统启动时自动启动: 测试 Redis 使用 Redis 客户端连接到 Redis 服务器并测试: 在 Redis CLI 中运行以下命令测试: 如果返回 ,说明 Redis 正...
学习
Linux2024-07-12
ssh登陆报错“IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!“问题原因及解决方法
最近给 重装完固件连接时发现ssh报错,如下 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 警告:远程主机标识已更改! 这个报错主要是因为远程主机的ssh公钥发生了变化,两边不一致导致的 删除本地对应ip的在known hosts相关信息 删除之后重新连接,成功!
学习
Linux2024-07-12
Ubuntu 一站式 Zsh 和 Oh My Zsh 安装配置指南
本文介绍了如何在Ubuntu系统上安装和配置zsh和oh my zsh,包括基本安装步骤、配置插件等操作。提高终端的使用效率和定制性。 步骤一:安装 Zsh 安装Zsh前,需要更新Ubuntu的包列表: 接下来,安装Zsh 验证安装: 步骤二: 安装 oh my zsh 使用一行命令安装 也可以手动脚本安装 步骤三: 装插件 安装插件 安装自动补全插件和语法高亮插件以提高命令行的效率和易用性。 启用插件 编辑 文件以启用下载的插件。 在...
学习
Linux2024-07-12
在Ubuntu 22.04 LTS 上安装 MySQL两种方式
Ubuntu安装MySQL 介绍: 是一款基于 的免费开源发行版,广受欢迎。它以稳定性、安全性和用户友好性而闻名,适用于桌面和服务器环境。Ubuntu提供了大量的软件包和应用程序,拥有庞大的社区支持和活跃的开发者社区。它的长期支持(LTS)版本获得5年的安全更新,为企业和个人提供了可靠的选择。 Ubuntu的桌面版本具有直观的用户界面,而服务器版本则适用于构建强大的Web服务器和云计算平台。 当你需要 时,有两种主要的方式:在线安装和离...
学习
Linux2024-06-19
Ubuntu查看文件夹大小
在 中,你可以使用 命令来查看文件夹的大小。 命令的全称是"disk usage",用于估计和显示目录或文件的磁盘使用空间。 如果你想查看某个特定文件夹的大小,你可以使用以下命令: 在这个命令中, 选项表示"summary",它将只给出总计的大小,而不是每个子目录的大小。 选项表示"human readable",它将以易于阅读的格式(例如KB,MB,GB)显示大小。 例如,如果你想查看名为"Documents"的文件夹的大小,你可以运...
学习
评论
请登录后发表评论
去登录