systemd-analyze critical-chain 怎样定位启动慢的依赖
Linux 启动变慢时,我通常不会先把 systemd-analyze blame 输出里耗时最长的服务逐个禁掉。更稳妥的顺序是:先用 systemd-analyze critical-chain 找到目标启动链上的关键等待,再用 blame、systemctl status 和 journalctl 判断真正需要处理的单元。
关键点在于“慢”有两种:一个单元可能确实初始化很久,也可能只是排在一个更慢的依赖后面。critical-chain 适合回答“谁在这条启动路径上挡住了目标”,blame 更适合回答“哪些单元自身花费的启动时间较多”。
官方地址:https://www.freedesktop.org/software/systemd/
先定位目标和关键链,再解释单元耗时,最后回到状态与日志。只看一个排序列表,容易把并行启动中的正常等待误判成根因。
先确认要排查的启动目标
先看 systemd 给出的启动总览,确认问题发生在系统启动、某个 target,还是某个服务被拉起时。下面的命令只读取状态,不修改 unit 配置。
# 查看本次启动各阶段的总体耗时
systemd-analyze
# 查看默认启动目标,确认系统最终要到达的 target
systemctl get-default
# 列出当前启动目标的依赖,帮助确认服务是否在这条路径上
systemctl list-dependencies multi-user.target --all
如果问题描述是“开机后某个业务迟迟不可用”,目标不一定是 multi-user.target。可以把具体服务作为后续分析对象,例如 app.service。如果问题只发生在图形环境,则应先确认对应的 target,而不是把所有启动单元混在一起看。
读取 critical-chain 找最长等待路径
critical-chain 会把启动过程中影响目标的关键单元链路打印出来。默认观察启动目标,也可以指定一个 unit。输出中的时间标记用于帮助理解单元何时开始、花费多久以及它依赖谁;示例输出的数值只是格式示意。
# 查看默认启动目标的关键链
systemd-analyze critical-chain
# 只围绕指定服务查看关键依赖链
systemd-analyze critical-chain app.service
# 查看一个 target 的关键链,避免把无关服务纳入判断
systemd-analyze critical-chain multi-user.target

阅读时先从底部或目标单元开始向依赖方向回溯,找出最长的连续等待段。假设一条链是 multi-user.target 依赖 app.service,而 app.service 又等待网络初始化,那么应该先检查网络相关 unit 是否真的阻塞了目标;不能只因为另一个服务在 blame 里耗时更高,就直接把它当成根因。
用 blame 分辨单元自身耗时
关键链解决的是“影响目标的依赖路径”,但它不等于所有单元的完整耗时排行。接着看 blame,把在启动阶段花费时间较多的单元列出来,与关键链中的候选交叉比较。
# 按启动耗时查看单元,便于找出需要深入检查的候选
systemd-analyze blame
# 输出更适合脚本或表格处理的单元耗时列表
systemd-analyze blame --no-pager
# 查看启动耗时统计和关键链,保留目标上下文
systemd-analyze time
systemd-analyze critical-chain app.service
这里要注意两个边界。第一,systemd 会并行启动很多单元,某个单元耗时较长,不代表它一直阻塞了最终目标。第二,关键链上的短单元也可能很重要,因为它位于连续等待路径中。排障时可以做一个小表格:
| 观察结果 | 优先判断 | 下一步 |
|---|---|---|
| critical-chain 上出现并且 blame 也很慢 | 可能是依赖链中的自身初始化瓶颈 | 查看 status 与本次启动日志 |
| critical-chain 上出现但 blame 很短 | 可能是它等待了更早的依赖 | 继续向依赖方向回溯 |
| blame 很慢但不在目标关键链 | 可能没有影响当前目标 | 确认它是否是另一个工作流的问题 |
| 输出显示失败、重试或超时迹象 | 启动异常而非单纯性能问题 | 转到 unit 状态和 journalctl |
用 status 看单元到底卡在哪里
确定候选后,不要马上编辑 unit 文件。先查看状态、最近一次启动时间和 systemd 记录的结果。下面的 --no-pager 让输出更适合保存到排障记录中。
# 查看服务的当前状态、主进程和最近几行日志
systemctl status app.service --no-pager
# 查看 unit 的完整属性,重点关注启动状态和依赖相关字段
systemctl show app.service \
-p ActiveState \
-p SubState \
-p Result \
-p ExecMainStartTimestamp \
-p After \
-p Requires
status 适合快速判断“服务是否成功、是否正在重启、主进程是谁”;show 适合提取结构化字段。若 Result 表明启动失败或超时,应先修复失败条件,再讨论启动耗时,否则重复重启本身就会污染观察结果。
用 journalctl 对齐本次启动日志
关键链给出路径,状态命令给出当前结果,日志则用来解释为什么等待。排查启动问题时最好限定到一次 boot,避免旧日志把判断带偏。
# 查看本次启动中指定服务的日志,并按时间顺序输出
journalctl -b -u app.service --no-pager --output=short-monotonic
# 只看本次启动的警告及更高等级,减少无关输出
journalctl -b -u app.service -p warning..emerg --no-pager
# 同时观察依赖服务,确认到底是等待、失败还是重试
journalctl -b -u network-online.target -u app.service \
--no-pager --output=short-monotonic
-b 把范围限定在当前启动批次,-u 按 unit 过滤,--output=short-monotonic 便于比较相对时间。日志中如果出现连接重试、挂载等待、权限错误或超时,应把它们和 critical-chain 中对应的等待位置对齐,而不是只摘一条最醒目的错误。

修改 unit 前保留可回滚的基线
如果确认是某个依赖关系或初始化动作造成等待,先保存修改前的证据:启动总览、目标关键链、候选单元的 status 和对应 boot 日志。这样调整后才能比较是否真的缩短了目标路径。
# 建立本次排障目录,保存的是诊断结果而不是敏感凭据
mkdir -p /tmp/systemd-boot-check
# 记录目标的关键链与耗时排行,便于修改前后对照
systemd-analyze critical-chain multi-user.target \
> /tmp/systemd-boot-check/critical-chain.before.txt
systemd-analyze blame --no-pager \
> /tmp/systemd-boot-check/blame.before.txt
# 记录当前 unit 配置摘要,便于回滚或审阅差异
systemctl cat app.service \
> /tmp/systemd-boot-check/app.service.before.txt
真正修改时尽量使用 drop-in,而不是直接覆盖发行版提供的 unit 文件。修改后先执行配置重新加载,再单独验证目标服务;如果依赖关系变更扩大了启动范围,应立即恢复原配置并重新采集一次关键链。
# 让 systemd 重新读取 unit 文件,不会自动启动所有服务
systemctl daemon-reload
# 只验证目标服务的状态,避免把排障动作扩大到整台主机
systemctl restart app.service
systemctl status app.service --no-pager
常见误判和一个简短的排查顺序
- 把
blame第一名当成根因:先回到目标的critical-chain,确认它是否真的位于阻塞路径。 - 把链上的每个等待都归咎于最后一个服务:沿依赖方向检查
After=、Requires=与实际日志。 - 混用不同启动批次的日志:优先使用
journalctl -b,必要时明确指定历史 boot。 - 没有保留修改前结果就调整多个 unit:一次只改一个影响点,保留 before/after 文件。
我自己实际排这类问题时,会把顺序压缩成四步:systemd-analyze 看总览,critical-chain TARGET 看路径,blame 看候选耗时,最后用 status 和 journalctl -b 解释原因。这样做的好处是先处理真正影响目标的依赖,而不是被一张看起来很长的耗时列表牵着走。
相关问题
critical-chain 和 blame 有什么区别?
critical-chain 关注某个启动目标依赖链上的关键路径;blame 关注单元自身记录的启动耗时排序。两者应该交叉使用,不能互相替代。
为什么 blame 最慢的服务不一定拖慢开机?
systemd 支持并行启动。一个服务即使自身初始化时间较长,只要不在当前目标的关键依赖链上,就可能没有影响目标到达时间。
critical-chain 应该指定服务还是 target?
如果问题是系统进入某个阶段慢,指定相关 target;如果只有一个服务不可用或启动慢,指定该 service,更容易缩小依赖范围。
修改 unit 后看不到变化怎么办?
先确认 drop-in 的位置和内容,再执行 systemctl daemon-reload。随后重新启动目标单元并用新的 boot 日志或状态记录对照,避免把旧输出当成新结果。
总结
systemd-analyze critical-chain 最适合做第一轮路径定位:它帮助你知道哪些依赖连续地影响目标。systemd-analyze blame 用来补充单元自身耗时,systemctl status 和 journalctl -b 则负责把候选连接到状态和日志证据。按这个顺序排查,通常能更快区分“依赖在等什么”和“服务自己做了什么”,也能在修改前后留下可回滚的依据。
systemd 服务怎样用 Type=notify 表达就绪状态
- 上一篇
- systemd 服务怎样用 Type=notify 表达就绪状态
- 下一篇
- Linux fanotify 权限事件的允许与拒绝处理方案
-
- 文章 · linux | 42分钟前 |
- Linux shell 管道失败状态怎样向上返回
- 290浏览 收藏
-
- 文章 · linux | 46分钟前 |
- Linux cron 和 systemd timer 怎样选择
- 192浏览 收藏
-
- 文章 · linux | 50分钟前 | 内存管理 · 日志排查 · Linux pid journalctl 内核日志 dmesg cgroup 内存排障 OOM Killer
- Linux OOM killer 怎样从日志确认触发对象
- 131浏览 收藏
-
- 文章 · linux | 51分钟前 | Linux IPC 性能诊断 perf stat CPU指标 cycles instructions cache-misses
- Linux perf stat 怎样先看 CPU 指标
- 110浏览 收藏
-
- 文章 · linux | 53分钟前 | Linux 僵尸进程 SIGCHLD PID namespace init进程 孤儿进程 waitpid
- Linux PID namespace 中 init 进程怎样回收子进程
- 206浏览 收藏
-
- 文章 · linux | 55分钟前 |
- Linux TCP backlog 怎样区分监听队列和连接队列
- 407浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux journalctl 怎样按优先级筛出启动错误日志
- 326浏览 收藏
-
- 文章 · linux | 1小时前 | Linux · Linux fanotify FAN_OPEN_PERM FAN_ACCESS_PERM
- Linux fanotify 权限事件的允许与拒绝处理方案
- 489浏览 收藏
-
- 文章 · linux | 1小时前 | 服务管理 · Linux systemd 服务启动 Type=notify READY=1 NOTIFY_SOCKET 就绪状态
- systemd 服务怎样用 Type=notify 表达就绪状态
- 436浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 471次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 530次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 549次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 499次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 317次使用
-
- 详解CentOS7下PHP+Nginx+Mysql编译安装方法
- 2023-01-21 432浏览
-
- Linux 服务启动失败怎么查:状态和日志的排查顺序
- 2026-07-15 195浏览
-
- Linux 开机慢怎么查:用启动分析工具看耗时、依赖链和网络等待
- 2026-07-16 442浏览
-
- Linux 业务服务部署怎么选:服务单元与 Docker Compose 的启动、恢复与回滚取舍
- 2026-07-19 473浏览
-
- Linux 服务重启后找不到 PATH 怎么办:EnvironmentFile、登录 Shell 和启动日志排查
- 2026-07-20 187浏览
